An analytics number you can't trust is worse than no number, because you'll act on it. A review of both analytics SDKs turned up several defects that affected every tenant identically — which makes them our bugs, not your configuration. All are fixed. Here's what was wrong.
Machines were being counted as people
Product analytics had no bot filter at all. Crawlers and headless browsers hitting an in-app surface were recorded as anonymous users with real sessions.
A crawler on your login page is not product usage, so every machine now goes fully silent in product analytics — no events, no session, no feature-flag evaluations. Automated browsers used for testing are covered too.
This is deliberately stricter than web analytics, where a named AI assistant reading a page is real readership and gets counted as such.
Your historical numbers may have moved
We removed the historical machine events from both regions rather than leaving known-bad rows in place.
If you compare a chart today against a screenshot from last week, some counts will be lower. Nothing was lost — what came out was machine traffic that should never have been counted. The lower number is the accurate one.
96% of captured errors weren't errors
Measured over seven days, the overwhelming majority of captured exceptions came from a browser extension running in visitors' browsers — not from any page. Genuine errors sat three orders of magnitude below the noise.
Extension-generated errors, browser-extension origins, and a small set of notices the spec explicitly says aren't error conditions are now filtered before they're sent. The bar for the filter list is narrow and stated in code: it has to be thrown by something other than your code and carry no diagnostic value. A real error that merely resembles one of these is still captured.
Events stopped disappearing on bad networks
A batch that exhausted its retries used to be logged and thrown away — so a tunnel, hotel Wi-Fi, or a server hiccup could quietly eat identify, revenue and goal events mid-session. Those events are now stored and sent on the next load, with duplicate protection so a replayed batch can't double-count. If a visitor has opted out, nothing is stored at all.
Two smaller ones worth naming
identify()traits were being stripped. A common trait likenamewas silently dropped for every customer. Traits now pass through untouched.- Feature flags on shared devices. Calling
reset()cleared the user but left the previous person's targeted flag variants live in memory and in storage. The cache is now cleared immediately and re-evaluated as anonymous.
If your snippet is already installed, you have all of this — the SDKs update themselves. Nothing to change.