ETag Cache Headers
An entity tag is an ordinary HTTP caching header. A server hands the client a short opaque string alongside a response; the client offers it back on the next request as If-None-Match; the server answers “still current” rather than sending the body again. Browsers have done this for as long as there have been browsers, and it is how most of the web avoids re-downloading things it already has.
Pushbroom uses one to tell whether two page views belonged to the same visit.
The mechanism
When the collector first runs on a page, it asks /cache for a visit identifier. The response is a freshly generated random UUID, with an entity tag of "{uuid}.{timestamp}".
On the next page, the browser offers that tag back. The endpoint reads the timestamp out of it, sees the visit is still inside its window, answers 304, and re-issues the same tag. The page views recorded in between are filed as one visit.
The issue time travels inside the tag itself. That is deliberate: it means the server can tell how old a visit is without keeping a record of that visit anywhere.
Yes, this is the technique
Handing a client a value and reading it back later is what a cookie does, and an entity tag can be used to do the same job. It has been. There is a body of writing about using cache headers to re-identify people who have cleared their cookies, and it is about exactly this header.
Pointing at the absence of a Set-Cookie line is not an argument, so we are not going to make that one. The argument is the constraints, and all of them are checkable against src/routes/cache/+server.js and the collector that talks to it.
First-party only. The tag is issued by the endpoint your own site’s script calls, against the origin your site sent. There is no third-party context here, because there is no request Pushbroom makes from anywhere but your own pages.
Two hours, absolute. The window runs from the moment the identifier was minted and does not extend on activity — the 304 branch re-issues the original timestamp rather than a fresh one. Somebody reading for three hours gets a second visit. There is no version of this that accumulates, and no way to configure one.
Bounded on the server. The lifetime is not a hint the browser is trusted to honour. A tag older than the window is refused and a new identifier is minted, so a client holding onto an old one gains nothing by it.
It is joined to nothing. The identifier is a random UUID. Nothing about the visitor goes into making it — not an address, not a user agent, not anything about the device — so there is nothing to work backwards from. It is not matched against a profile, an account, an email address or a previous visit, because Pushbroom keeps none of those.
One site. A tag is minted against the requesting origin and belongs to it. Subdomains are separate origins and get separate, unrelated identifiers. There is no identifier space shared between the sites Pushbroom measures, including between two sites owned by the same person.
A visitor can refuse it. A browser sending Global Privacy Control, or one where the site has called pushbroom.block(), never requests an identifier at all — so none is minted and nothing is stored on the device. See opting out.
What it can and cannot do
It can tell you that four page views were one visit. It cannot tell you who, it cannot tell you that last Tuesday’s visit was the same person, and it cannot follow anyone to another site. Those are not settings; the data required to do any of them is never collected.
None of the above is a legal conclusion, and this page does not offer one.
References
Last updated