Two facts only your site can know, and Loghound will not invent either: what you call the person, and whether they were signed in.
You may pass an identity for a visitor who is not authenticated. You may want “this was a signed-in session” recorded without handing over who it was. Neither implies the other and neither is derived from the other.
Loghound never guesses either value. No cookie is read, no form is scraped, no meta tag is looked for, no variable is hunted through. If your site does not say, the field does not exist on the session.
The normal case. The template that renders the page renders the tag, in the same response: no second request, no extra script, no ordering problem.
<script src="https://loghound.example.com/b.js?v=1"
data-ident="ada@example.com" data-signed-in="1" defer></script>You would not write the address literally, of course — it comes out of whatever object your framework already has.
WordPress
<?php
// wp-content/mu-plugins/loghound.php - a must-use plugin, so it survives a theme change.
add_action('wp_head', static function (): void {
$attrs = ' data-signed-in="0"';
if (is_user_logged_in()) {
$attrs = ' data-ident="' . esc_attr(wp_get_current_user()->user_email) . '"'
. ' data-signed-in="1"';
}
echo '<script src="https://loghound.example.com/b.js?v=1"' . $attrs . ' defer></script>' . "\n";
}, 99);A signed-out visitor gets data-signed-in="0" and no data-ident at all — which is right: they are anonymous, and that is a different statement from “we were not told”. esc_attr() is what stops an address containing a quote from breaking the tag.
WP Rocket, W3 Total Cache, LiteSpeed and Cloudflare APO all cache the rendered tag with the page, so the first visitor’s identity would be served to everybody else. Exclude logged-in users from the cache — every one of those plugins does so by default — or use route 3 below from an uncached request.
Drupal
<?php
# your_theme.theme (or a small custom module)
function your_theme_page_attachments(array &$attachments): void {
$account = \Drupal::currentUser();
$tag = [
'#type' => 'html_tag',
'#tag' => 'script',
'#attributes' => [
'src' => 'https://loghound.example.com/b.js?v=1',
'defer' => TRUE,
'data-signed-in' => $account->isAuthenticated() ? '1' : '0',
],
];
if ($account->isAuthenticated()) {
$tag['#attributes']['data-ident'] = $account->getEmail();
}
$attachments['#attached']['html_head'][] = [$tag, 'loghound'];
$attachments['#cache']['contexts'][] = 'user';
}html_head rather than a library, because a library is declared once in YAML and cannot carry a value that changes per request. The user cache context is not optional: without it Drupal’s render cache serves the first authenticated visitor’s address to every other one. Use getAccountName() instead of getEmail() if a username is the identifier you want, and run drush cr afterwards.
They must be set before b.js executes, which with defer means anywhere in the document.
<script>window.LoghoundIdent = "ada@example.com"; window.LoghoundSignedIn = true;</script> <script src="https://loghound.example.com/b.js?v=1" defer></script>
In Google Tag Manager that is a Custom HTML tag with data layer variables, because a tag manager runs in the browser and cannot know who is signed in — the value has to reach it from your own page:
<script>
window.LoghoundIdent = "{{Loghound Ident}}";
window.LoghoundSignedIn = "{{Loghound Signed In}}";
</script>
<script src="https://loghound.example.com/b.js?v=1" defer></script>A single-page application that signs somebody in without a navigation, which no attribute can express:
window.loghound.identify('ada@example.com', true);It makes no request of its own: the values ride the heartbeat that is already scheduled, so attaching an identity costs your site nothing extra. Both arguments are optional and independent, so identify(null, true) records the signed-in state and no identity.
The signed-in field on a session is written only when your site actually said one or the other. A site that never sends the attribute leaves the field absent, and the panel reports that population as “not reported” — never as anonymous.
Figure 1 — three states. The split between signed-in and anonymous traffic is the reason the field exists; counting “not reported” as anonymous would make that split a fabrication over traffic nobody classified.
Where several payloads in one session disagree, the resolution follows what happened: the last non-empty identity wins, because somebody who signs in halfway through a visit is that person by the end of it; and signed-in beats anonymous, because a session that was authenticated at any point was an authenticated session.
| Setting | Default | What it stores |
|---|---|---|
beacon.store_identity | false | The string your site sent, at most 128 bytes, on the session document |
beacon.store_signed_in | true | A boolean on the session document, or nothing when unreported |
Everything else this beacon collects is a measurement of a browser. This is a name. With it on, an address is written to the session document, appears in the panel, lives in the Solr index, and is in every backup of that index until retention deletes the session. With it off, the string is discarded before anything is written — it never reaches the staging database, let alone Solr. Switching it off stops collection; it does not merely hide what was collected.
The signed-in switch is on by default because the boolean identifies nobody, and because the split it enables — engaged time, paths, bounce and bot verdict for signed-in versus anonymous traffic — is one of the most useful things the panel can show. The two switches are independent: storing the split while storing no identities at all is a perfectly ordinary configuration, and probably the right one for most sites.
In the panel, both appear on the session detail dialog in a strip flagged with the accent, because they are the only facts there that Loghound did not derive for itself. The identity string is rendered as text at every sink like every other value that came off the wire — it is caller-supplied input on a public endpoint, and it is treated as hostile regardless of how trustworthy the site that sent it is.