Part III β The Speed Β· Lesson 7.2
Telemetry
In one lineCapture enough context to debug, sample enough to afford it, and scrub everything personal.
Where you've seen itA Sentry issue that reproduces a bug from the breadcrumb trail alone β route, three clicks, failed request, exception.
Diagram
THE PIPELINE β and the step people forget
βββββββββββ ββββββββββ ββββββββββ ββββββββββ βββββββββββ
β Browser ββββΊβ SCRUB ββββΊβ SAMPLE ββββΊβ BATCH ββββΊβ Backend β
β capture β β PII β β β β + send β β + dash β
βββββββββββ ββββββββββ ββββββββββ ββββββββββ βββββββββββ
β² β
never send: email, phone, sendBeacon on
card, address, auth token, visibilitychange
full URLs with tokens (survives unload)WHAT AN ERROR EVENT MUST CARRY
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β error message + stack (minified β mapped, 7.4) β
β release build id / git sha β "what shipped?" β
β route /checkout/payment β not the full URL β
β user hashed id only β never the email β
β device browser, OS, viewport, connection type β
β breadcrumbs last ~20 actions: clicks, routes, β
β fetches, console warnings β
β tags feature flags, A/B variant (4.4), locale β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Without breadcrumbs you get "it broke". With them you get "it broke
after the third filter change while the token was refreshing".SAMPLING β you cannot afford 100% of everything
errors 100% rare and high value
traces 10% enough for latency distribution
session replay 1% + 100% of sessions that errored
custom logs 1β5% + always keep the failing path
Rule: sample the boring, keep all of the broken.How it works
- Capture globally:
window.onerror,unhandledrejection, failedfetchwrappers, and framework error boundaries. The promise handler is the one most often missing. - Scrub before sending, not on the server β data you never transmit can never leak. Strip query strings, mask form values, hash user ids.
- Sample by category, keeping all errors and a slice of everything else.
- Batch and send with
sendBeacononvisibilitychange, so events survive the user closing the tab. - Fail silently. Telemetry that throws, blocks rendering, or retries aggressively is worse than no telemetry.
window.addEventListener('unhandledrejection', (e) => {
report({
type: 'unhandled_rejection',
message: String(e.reason?.message ?? e.reason).slice(0, 500),
stack: e.reason?.stack,
route: location.pathname, // path only β no query string
release: __BUILD_ID__,
userHash: hashedUserId, // never the raw identifier
});
});Trade-offs
| Capture more | Capture less |
|---|---|
| Faster root cause | Lower cost and compliance risk |
| Better breadcrumbs | Less PII exposure (3.8) |
| Bigger bills, noisier data | Blind spots during incidents |
Own-the-boundary rule: telemetry SDKs are third-party scripts with full origin access (3.7). Load them async, pin versions, and make sure a vendor outage cannot break your app.
Interview angle
"What do you log from the frontend, and what do you never log?"
- Always: error and stack, release id, route, device and connection, breadcrumbs, and feature-flag or experiment tags.
- Never: emails, phone numbers, payment data, auth tokens, or full URLs that may carry tokens in the query string.
- Scrub on the client before transmission, since server-side scrubbing still means the data left the device.
Recap
- Context is what makes an error actionable β breadcrumbs and release id above all.
- Scrub on the client, sample by category, send with
sendBeacon. - Keep 100% of errors; sample everything that's merely interesting.