Integrating Error Tracking With Your Analytics
Why errors belong next to traffic
A deploy goes out. Conversions drop 8%. Your analytics shows the drop; your error tracker shows a spike in a checkout exception. Separately, each is a shrug. Together, it is a cause.
Getting them into one place is mostly an integration problem, and it has a few well-worn edges.
The adapter pattern
Do not write "the Sentry integration". Write an adapter interface and make Sentry the first implementation:
{
provider: 'sentry',
label: 'Sentry',
pollAll: ({ silent }) => /* … */,
handleWebhook: (payload, rawBody, signature) => /* … */,
}Everything provider-agnostic — encrypted credential storage, upsert and dedup, poll orchestration, webhook routing — lives outside the adapter. Adding Rollbar or Bugsnag then becomes one file rather than a second subsystem.
The routing follows: POST /api/integrations/:provider/webhook dispatches through a registry instead of hardcoding a path per vendor.
Poll and webhook, not one or the other
Webhooks are near-instant but unreliable: they get missed, retried out of order, or silently dropped when an endpoint has an outage.
Polling is reliable but delayed.
Use both. Webhooks for latency, a periodic poll as the reconciling backstop. The poll is what makes the system self-healing — a missed webhook is corrected within one cycle rather than lost forever.
Verify webhook signatures
An unauthenticated webhook endpoint accepts anything anyone posts:
const expected = crypto.createHmac('sha256', secret)
.update(rawBody).digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature))) {
return res.status(401).end();
}Two details. Verify against the raw body, not the parsed object — JSON re-serialisation changes bytes and breaks the HMAC. And use timingSafeEqual, because a plain === leaks the signature through timing.
That means the webhook route needs its own body parser with a verify hook to capture the raw bytes, mounted before any global JSON parser.
Adaptive polling
Polling every project every five minutes wastes calls on projects that produce one error a week.
Back off when nothing changes: start at the base interval, double it after each idle poll up to a ceiling, and reset to the floor the moment something arrives. A busy project stays current; a quiet one drops to hourly on its own.
Back off hard on auth failures — hours, not minutes. A revoked token will not fix itself, and retrying every five minutes just fills the logs.
Store what you will report on
Do not mirror the provider's full payload. Store the fields your reports use — title, level, status, count, users affected, regression flag, release, first and last seen — and link out for the rest. Mirroring everything means tracking their schema changes forever.
Try InsightsTrack free
Open-source, self-hosted, privacy-first analytics — explore the live demo, no install required.
Open live dashboard