Off unless you configure it. This is the only place in the product where a literal string a visitor typed is stored and indexed. Everything else Loghound keeps is a measurement, a status code, a hashed identifier or a path. A search term is content.
A facetable, indexed, multi-valued field on both the hit and the session document. So “what did people search for” becomes a real dimension — countable, filterable, drillable, reachable from the value browser — exactly like Country or Browser. The Overview page gets a What they searched for card, and any value in it scopes the whole dashboard when you click it.
The query string has always been on the hits core as stored only, not indexed, no docValues. You can see it on one document and you can facet on none of it, because a query string is unbounded attacker-controlled text with a near-unique value per request, and indexing it would build a term dictionary the size of the corpus. Search terms are its opposite by construction: a handful of values, pulled out by name, from a list you wrote.
Two halves, and they do different jobs. In config/loghound.php:
'beacon' => [
'query_params' => ['q'],
],And on the measured page — which the settings page fills in for you once the configuration is set:
<script src="https://loghound.example.com/b.js?v=1" data-params="q" defer></script>
data-paramsis a privacy measure. It keeps the rest of the URL — the session token, the reset code — from leaving the visitor’s browser at all.- The server list is the decision about what is stored. The payload is attacker-chosen, so the server applies its own whitelist on arrival regardless of what the page sent. A parameter you have not named is discarded before anything is written anywhere.
The same list also feeds the log parser, which is the half that needs no beacon at all: for a host whose access log this installation reads, the same named parameters are pulled out of the request line. So a search page on this machine and a search page on another one both fill the same field, and a mixed install compares like with like.
| Rule | Why |
|---|---|
| Control characters stripped, invalid UTF-8 repaired | It travels into a Solr document, a JSON response and an HTML table |
| Internal whitespace collapsed | Two spellings that look identical on screen must be one value, not two |
| Lower-cased | The field exists to be counted. A dimension listing three casings of one word as three rows answers the question worse than one that lists it once. The original casing is not kept anywhere |
| Longer than 96 characters → dropped, not truncated | Truncating would coin a facet value nobody ever searched for, and the value browser would then show it as though somebody had |
| At most 8 per payload or log line, 20 distinct per session | A visitor who runs four hundred searches must not make one session document four hundred values wide |
| Always a bound value, never spliced into a Solr parameter | The same rule as every other untrusted string in the product |
Counted per session, not per search: a visitor who ran the same search six times contributes one. That is the number worth having — “how many people looked for this” — rather than the one that flatters, and the card says which it is showing.
A search term can be a person’s own name, a medical question, or a competitor’s name typed into your site by their employee. It lands on the session document, appears in the panel, lives in the search index and sits in every backup of it until retention deletes the session — the same lifecycle as an identity, and for the same reason it is off by default.
Name only the parameters your search box actually uses, and never a parameter that could carry anything else. That is why the setting is a whitelist of names rather than a switch marked “collect the query string”. Real sites routinely carry session tokens, email addresses and password-reset codes in query strings, and an analytics tool that collects them wholesale has created a breach its customer did not agree to.
Privacy covers what to tell your visitors about it.