b.js reads exactly nine things: six attributes on the script tag, two globals and one function. Nothing else is looked at.
An option can be set perfectly and still have its value discarded on the server, because storing a declaration is a policy decision the operator makes and storing a measurement is not. Each option below says which switch decides that. The panel’s Settings › Beacon card shows the same reference with that answered from your configuration, which is the only place it can be answered concretely.
data-endpoint attribute always — the script uses it itselfThe collector URL, when it is not a sibling of b.js.
data-endpoint="https://loghound.example.com/collect.php"
data-hb attribute alwaysHeartbeat interval in milliseconds. A beat is sent only when engaged time actually advanced, so an idle tab produces one, not hundreds.
data-hb="30000"
data-idle attribute alwaysHow long after a real interaction a visitor still counts as engaged. This is the definition of the Engaged clock.
data-idle="60000"
data-ident attribute beacon.store_identity — false by default, so this is discarded until you turn it onAn identity your site attaches. Never guessed. See identity.
data-ident="<?= htmlspecialchars($user->email, ENT_QUOTES) ?>"
data-signed-in attribute beacon.store_signed_in — true by defaultWhether the visitor was signed in. Splits every number in the panel into signed-in and anonymous.
data-signed-in="<?= $user->isSignedIn() ? '1' : '0' ?>"
data-params attribute beacon.query_params — empty by default, and the server’s list is authoritativeQuery parameter names whose values are kept as search terms. Nothing else in the query string is read.
data-params="q,category,sort"
window.LoghoundIdent global beacon.store_identityThe same value as data-ident, for a template where adding an attribute to the tag is awkward but setting a variable above it is not.
<script>window.LoghoundIdent = "ada@example.com";</script>
window.LoghoundSignedIn global beacon.store_signed_inThe same value as data-signed-in.
<script>window.LoghoundSignedIn = true;</script>
window.loghound.identify(ident, signedIn) function both switches aboveAttach either value after the page has loaded — a single-page application that signs somebody in without a navigation, which no attribute can express.
window.loghound.identify(user.email, true);
data-hb and data-idle mirror beacon.heartbeat_ms and beacon.idle_timeout_ms in the configuration, and the settings page renders the snippet with your configured values already in it. The rest have no configuration counterpart on the page — your template supplies them per request — but whether Loghound stores what they carry is decided entirely on the server.
<script src="https://loghound.example.com/b.js?v=1"
data-hb="15000"
data-idle="30000"
data-signed-in="1"
data-params="q"
defer></script>And the server-side half that decides what is kept, in config/loghound.php:
'beacon' => [
'heartbeat_ms' => 15000,
'idle_timeout_ms' => 30000,
'store_identity' => false,
'store_signed_in' => true,
'query_params' => ['q'],
'allowed_hosts' => [],
],allowed_hosts is the one key there that answers to no tag attribute at all. It names the hostnames whose beacons may create a session, have their hostname recorded as a virtual host, and have their search terms kept. Empty is the right default for a machine that only measures sites whose access logs it already reads. Put the snippet on a site this installation has no log for and you have to add that hostname here, or the beacon is accepted, answered 204, and quietly kept out of every number — which looks exactly like a broken tag. The standalone page has the whole rule, including how a listed host is told apart from anybody else claiming to be it.
b.js runsThe six data- attributes are read off the script tag itself, so where they sit in the document cannot be wrong. The two globals can be: window.LoghoundIdent and window.LoghoundSignedIn are read once, at the moment b.js executes, so a script that sets them after that has set them for nothing — the beacon has already sent its first payload and neither value is in it. With defer on the tag, b.js runs only after the document is parsed, which means anywhere in the page is early enough.
<!-- right: the globals are set before b.js executes --> <script> window.LoghoundIdent = "<?= htmlspecialchars($user->email, ENT_QUOTES) ?>"; window.LoghoundSignedIn = <?= $user->isSignedIn() ? 'true' : 'false' ?>; </script> <script src="https://loghound.example.com/b.js?v=1" defer></script>
For a value that genuinely is not known until later — a single-page application that signs somebody in without a navigation — the globals are the wrong instrument and window.loghound.identify(ident, signedIn) is the right one. It may be called at any point after b.js has run, and it sends nothing by itself: the values ride the next heartbeat.
window.loghound.identify(user.email, true);
The option list, with each default, accepted range and the key that decides whether what it sends is stored, is a contract in the Loghound specification: it belongs in the documentation, in the settings card, and in the script, and the three must not be able to drift. A test in the repository derives the list from b.js mechanically and fails when either of the other two falls behind.
Somebody installing a beacon reads the settings card. An option that exists only in a JavaScript comment and a markdown file is undocumented for the person who needs it — and the card answers what no document can: whether this installation will keep what an option sends.