Session Replay Sampling: Record Enough to Catch Bugs

Watch the replay at 0:14. She's on the checkout page, third attempt now, and the "Place order" button has just gone grey. No spinner, no error toast, nothing. She clicks it anyway. Then again. Then she opens the browser dev tools for half a second, closes them, and leaves. I've watched maybe forty of these this quarter, and every one is a session we did capture. The scary ones are the sessions we didn't.

That's the whole tension of session replay sampling: recording everything is expensive and mostly boring, but recording too little means the one replay that would've explained a bug is the one you threw away. So the real question isn't "what percentage should I sample?" It's "which sessions can I afford to lose?"

The short answer: sample the boring majority at a low flat rate, but capture 100% of the sessions that already smell like trouble: errors, rage clicks, funnel exits, dead clicks on a paywall. Let signal, not a dice roll, decide what gets kept.

Why flat percentage sampling quietly fails you

Flat sampling is the default because it's simple. Record 10% of sessions, done. And for aggregate UX questions ("do people find the filter panel?") it's genuinely fine. You don't need every session to see a pattern that shows up in one visitor out of three.

Where it falls apart is rare, high-value events. A checkout bug that fires for 1% of sessions is invisible in aggregate but catastrophic in revenue. Flat sampling treats that broken session exactly like the ten thousand happy ones: a 10% coin flip. Nine times out of ten, the replay you'd kill for is gone before anyone files the ticket.

Sentry's team put it well in their 2025 sampling write-up, arguing that a blanket percentage wastes budget on sessions with nothing wrong, and recommending you use an explicit trigger like replay.start() to record only during critical flows such as checkout instead (Sentry Blog, 2025). Same instinct as mine, from the error-monitoring side rather than the UX side.

The capture-on-signal framework

Here's how I set it up. Two tiers, and you tune them independently.

Tier one, the baseline sample. A low flat rate on everybody, purely so you have a representative sample of "normal" to compare against. 5% to 10% is plenty. This is your control group. You're not trying to catch bugs here; you're trying to know what healthy looks like.

Tier two, always record on signal. 100% capture whenever a session trips a signal you actually care about:

  • A JavaScript error or an API 500 fires.
  • A rage click or dead click (three-plus rapid clicks on the same dead element).
  • The user drops out of a funnel step you're watching (abandoned cart, half-filled signup).
  • A feature flag or new release is active for that user (you want every replay of the thing you just shipped).

The mechanism that makes tier two work without recording everyone is a ring buffer. The session records into memory continuously but doesn't upload; when a signal fires, the buffered seconds before the trigger plus everything after get shipped. Sentry's implementation keeps the last 60 seconds in roughly a 2-5MB in-memory buffer and only uploads if the error is sampled (Sentry docs, 2025). That pre-roll is the part that matters. The bug is rarely interesting; the fifteen seconds of the user fighting with your form before it broke is the whole story.

Most mature replay stacks now expose both dials. In Sentry's SDK it's literally two numbers: replaysSessionSampleRate for the baseline and replaysOnErrorSampleRate for the signal tier, with the documented recommendation being 0.1 and 1.0 respectively (Sentry, 2025). PostHog, LogRocket, FullStory, and Kixo each have their own flavour of "record less overall, but never miss an error session." The knobs differ; the philosophy converged.

The confidence math nobody shows you

Alright, napkin math, because "sample more" is useless without a number.

Say a bug appears in a fraction p of sessions, and you record n sessions that could contain it. Assuming sessions are roughly independent, the probability you catch at least one is the binomial complement:

P(catch) = 1 − (1 − p)ⁿ

That's the standard single-event detection formula (Martin Bland, University of York). Rearrange it for the question you actually have ("how many recordings do I need to be 95% sure I catch this thing?") and you get a rule of thumb clean enough to keep in your head:

To be 95% confident of catching a bug that occurs in fraction p of sessions, record about 3 ÷ p sessions. (For 99% confidence, use ~4.6 ÷ p.)

Run it through some real frequencies:

Bug frequency (p) Recordings needed for 95% catch Recordings for 99%
1 in 10 (10%) ~29 ~44
1 in 100 (1%) ~299 ~459
1 in 1,000 (0.1%) ~2,995 ~4,603
1 in 10,000 (0.01%) ~29,956 ~46,050

Now overlay your sample rate. If a bug hits 1% of sessions and you flat-sample at 10%, you need about 300 recorded sessions to be 95% sure you've got one, which means roughly 3,000 raw sessions have to pass through first. On a site doing 30,000 sessions a day, fine, you'll see it tomorrow. On a B2B app doing 800 sessions a day? You're waiting most of a week, and that's for a bug you can feel is happening now.

Drop to a 0.1% bug and flat 10% sampling wants ~30,000 recorded sessions, ~300,000 raw. That's the moment flat sampling becomes a joke and capture-on-signal stops being optional. Route every error session to 100% and your "n" for that bug jumps toward the real occurrence count overnight, because you stopped rolling dice on the exact sessions that matter.

The academic version of this is unforgiving, by the way. Work on binomial detection notes that with only 22 subjects your probability of spotting a 1%-rate event is about 19.8%, versus 90.2% for a 10%-rate event. Rare things need far more samples than intuition suggests (Bland). Your gut will always under-sample the rare bug.

One honest caveat: this assumes sessions are independent and the bug is memoryless. Real bugs cluster: a bad deploy, a single flaky region, one browser version. Clustering usually helps you (once you catch one, related ones pour in) but it wrecks the tidy probability if you try to use these numbers as a guarantee. Treat the table as a floor, not a contract.

What this does to your bill

Sampling is a budget lever first and a data-quality lever second, and the two pull in opposite directions, which is the entire problem.

The pricing shapes matter here. PostHog gives you 5,000 recordings a month free, then bills $0.005 per recording, and explicitly lets you drop the sample rate to 50% to stretch the allowance across the month (PostHog docs, 2026). LogRocket's free tier is 1,000 sessions a month, with the Team plan starting at $69/month for up to 10k sessions per a 2025 LiveSession pricing breakdown (LiveSession, 2025). Kixo runs MAU-bracketed per-project plans on a B2B contract rather than per-recording metering. Different billing units, same decision: every recorded session is a line item, so the ones you keep should earn their keep.

Here's the part people miss. Capture-on-signal is usually cheaper than a naive flat rate at the same bug-catch confidence, not more expensive. You're spending your recording budget on error and funnel-exit sessions, the ones with debugging value, instead of spreading it evenly across ten thousand people who bounced off your homepage in two seconds. Lower baseline, 100% on signal, and you typically record fewer total sessions while catching more of what you were paying to catch.

A rough monthly frame:

Strategy What you record Best for
Flat 100% Everything Low traffic, or you truly can't predict signals yet
Flat 10-50% Random slice Aggregate UX research, heatmaps, "do people find X"
Capture-on-signal ~5-10% baseline + 100% of error / rage / funnel-exit Debugging + UX at scale, tight budget
Flow-triggered Only checkout/onboarding/new-feature sessions You know exactly which flow you're studying

If you're small and cheap, flat 100% at low volume is honestly fine and you should stop overthinking it. The framework earns its complexity once your recording count starts showing up as a number the finance team notices.

Sampling and privacy aren't the same knob

Quick but load-bearing point, because people conflate them. Sampling decides how many sessions you keep. Masking decides what's visible inside a session. They're independent, and you need both.

Recording 100% of error sessions means you'll capture people mid-task, sometimes with sensitive fields on screen. That's a masking job, not a sampling one: password fields, payment inputs, PII redacted at capture time so the sensitive bytes never leave the browser. Every serious replay tool (Sentry, PostHog, FullStory, Kixo) masks inputs by default now. Turning up your capture rate is exactly when you double-check those masking rules, not after.

Getting your sample rate straight starts with what a "session" even is

You can't sample sessions cleanly until you agree on what one is. If your definition drifts (a 30-minute idle timeout here, a per-tab session there) then "10% of sessions" and "100% of error sessions" are measuring different denominators, and your confidence math is quietly wrong. It's worth pinning down before you tune any rate; our friends over at the Product Analytics Handbook have the definitive breakdown of what actually counts as a session and why the 30-minute timeout exists.

And if a term in your replay tool's sampling config makes you squint (dead click, rage click, buffer mode), the behavior analytics glossary has plain-language definitions for the signals you'll be triggering on.

Where I'd start on Monday

If you're setting this up from scratch, don't agonise. Baseline at 10%. Error sessions at 100%. Add rage-click and funnel-exit triggers once you've watched enough replays to know which flows hurt. Then look at your monthly recording count against the confidence table above and adjust the baseline down if you're comfortably catching the bugs that matter.

The goal was never to record everything. It's to make sure that the next time someone clicks a dead "Place order" button three times and leaves, the replay is sitting in your dashboard the next morning, pre-roll and all, instead of gone with the 90% you didn't keep.