The /err beacon
Every error goes to POST /err. The payload is:
First-occurrence-per-session dedup
The snippet keeps a per-session set of(phase, experimentId)
tuples that have already reported. The first occurrence sends. The
second, third, and Nth occurrences in the same session do not.
This exists because a broken variant that runs on every page load
would otherwise flood the endpoint. One report per session is enough
signal for diagnosis without the flood.
The phases
- apply, an error inside
onApply. - cleanup, inside
onCleanup. - route-handler, inside the runtime’s SPA route change handler.
- variant-js, inside the variant’s top-level JS (not wrapped in a handler).
- async, a rejected Promise the variant kicked off with no
.catch. - global-js, inside the Global JS block.
Where errors show up on your side
- Sentry, if you have SENTRY_DSN configured (Enterprise), errors land in your Sentry project.
- Dashboard health panel, the site’s Snippet health panel shows a count of recent errors and lets you drill into the most recent ones with their stacks.
- Dev debugger,
window.__abtestly.debug()on the affected page shows the error in the events buffer alongside the events that preceded it. Best for reproducing.
What happens after an error
An error inapply or variant-js does not stop the runtime.
The runtime catches, logs, and moves on. Other experiments on the
page still get evaluated and applied. The specific variant that
threw simply did not apply.
An error in global-js also does not stop the runtime. The variants
that were expecting Global JS to define something might throw
themselves as a consequence, but each is caught independently.
Errors from your own analytics adapter calls
If your GA4 or Segment or Amplitude SDK is missing or throws, the analytics adapters catch it and report as an error under phasevariant-js (the wrapping is
conservative). One first-occurrence report per session.
What is not in /err
- Bucketing decisions. “Visitor did not enter test” is not an error; it is a normal decision. Debug those with the dev debugger.
- Failed beacons. The
/ebeacon usessendBeaconwith akeepalive fetchfallback. If both fail, the runtime does not self-report, that would require the same broken network to succeed at/err. - User-perceived issues. “The layout looks wrong” or “the button is off-center”, those are QA problems, not runtime errors. Use the QA overlay.
Rate limiting
/err is not user-authenticated, so the dedup on our side is the
only rate limit. If you push a variant that throws on every page
load, expect one report per (session, experiment), a burst of new
visitors in the first minute after a bad publish will produce a burst
of reports.
If you know you are pushing something risky, republish quickly when
you notice, the dedup resets per session, so subsequent visitors
will not report against the fixed version.