Stop Saying 'Can't Reproduce': Tracing an Error Back to the Session That Caused It
The error happened. You can't reproduce it. But the session replay shows exactly what the user did—and it's one click away from the stack trace.
Picture a ticket that comes in at 4:47pm on a Friday.
"Users are reporting they can't complete checkout. Error message says something about payment. Can't reproduce on my machine."
"Can't reproduce." Three syllables that turn a 5-minute fix into a 3-day detective hunt. Three syllables that make you question whether users are making things up. (They're not. They never are.)
You pull up Sentry and find the error: TypeError: Cannot read properties of undefined (reading 'cardNumber'). 147 occurrences in the last hour. The stack trace points to line 234 of PaymentForm.tsx, a perfectly normal call to the form state. Nothing obviously wrong.
You check the browser breakdown. Safari 17.4 on macOS. Firefox 125 on Windows. Chrome 124 on Android. No pattern. All on /checkout/payment. A mix of new and returning users. Current production, no recent deploys.
The error is real — 147 users don't hallucinate the same TypeError — but you can't make it happen. Clicking through the checkout flow a dozen times works perfectly every time. Safari, Firefox, Chrome, mobile emulators: nothing.
This is the part where you start doubting yourself. Maybe you're testing wrong. Maybe there's a deploy you missed. Maybe you should just go home and pretend you didn't see the ticket.
Now suppose session replay is already on the same SDK, with the same session ID.
One click on the error event. "View Session Replay." The recording jumps to 14:32:47 — exactly when the error fired.
You watch a user fill out the shipping form. Normal. They click "Continue to Payment." The payment form loads. They start typing their card number. And then — they tab away to check something. They come back. The form is blank. They click the input field. Nothing. They click "Pay Now" without re-entering the card.
TypeError: Cannot read properties of undefined (reading 'cardNumber').
The bug in this scenario: the payment SDK loses focus state when the browser tab goes inactive for more than 30 seconds. When the user tabs back, the form inputs are there visually but the SDK has dropped the binding. The form data exists in React state but not in the payment SDK's internal state.
Five minutes from "can't reproduce" to root cause, because you can literally watch what the user did.
Why Separate Error Tracking and Session Replay Don't Cut It
The obvious solution: use Sentry for errors, LogRocket (or FullStory, or Datadog Session Replay) for recordings. Two tools, one problem solved. Right?
Not quite.
The integration tax. To connect Sentry and LogRocket, you need to configure both SDKs to share session context. LogRocket's Sentry integration requires you to pass LogRocket's session URL into Sentry's extra context, then enable the integration in LogRocket's dashboard. It works—eventually—but it's another thing to configure, another thing to break, another place to check when debugging your debugging tools. I've spent entire mornings debugging integrations instead of debugging my actual product. Not a great use of anyone's time.
The cost stacking. Sentry's Team plan is $26/month for 50K errors. LogRocket starts at $99/month for 10K sessions. Already you're at $125/month minimum, and those session counts are low for a production app. Scale up and you're looking at $300-500/month easily—just for the privilege of correlating two data sources that should have been unified from the start.
The timestamp dance. Even with integration enabled, you're correlating by approximate timestamp. Error at 14:32:47 maps to a replay that started at 14:31:02 and ended at 14:35:18. You scrub through 4+ minutes of footage looking for the moment. It's better than nothing. It's worse than jumping directly to the exact second.
The context gap. Sentry knows about the error. LogRocket knows about the user's actions. Neither knows about your analytics funnel, your custom events, your business context. If you want to correlate "this error caused a funnel drop-off" or "users who hit this error had 3x higher bounce rates," you're exporting to a data warehouse and writing SQL.
This workflow isn't terrible. But it raises the question: why pay two companies for data they refuse to share cleanly?
Look, I'm not saying Sentry is bad. It's not. It's excellent at what it does. Same with LogRocket. But gluing them together feels like duct-taping a solution that should just... exist.
The One-Click Fix: Unified Error + Replay
Here's what the workflow looks like when error tracking and session replay share the same session ID, the same event timeline, the same database.
Error appears in dashboard. You click it. You see:
- Stack trace (source-mapped, of course)
- Browser, OS, device
- User's session ID
- Custom properties (user tier, feature flags, whatever you track)
- "View Session Replay" button
You click the button. The replay starts at the exact moment the error fired. Not 30 seconds before. Not "somewhere in this 4-minute session." The exact frame.
You watch. You see what the user did. You understand why.
That's it. No integration configuration. No timestamp matching. No separate dashboards. The error and the replay are the same session, captured by the same SDK, stored in the same place.
For the payment SDK bug in the scenario above, watching the replay shows the tab-away behavior, which makes it quick to reproduce locally. The fix would be to re-initialize the payment SDK binding on visibility change — embarrassingly simple once you know the cause.
What This Looks Like in Practice
Here's the JustAnalytics setup for a typical React app. Add the monitoring script to your index.html:
<!-- public/index.html -->
<head>
<script
defer
src="https://justanalytics.app/monitor.js"
data-site-id="YOUR_SITE_ID">
</script>
</head>
That's it. Errors are captured automatically (unhandled exceptions, promise rejections, console.error calls). Session replay records DOM mutations. Both share the same session context.
When an error fires, it's tagged with:
- Current page URL
- Session ID
- Replay timestamp (millisecond precision)
- Whatever custom properties you've attached
In the dashboard, the error view shows a timeline. You see the error event. You see the replay segment. You click between them. The replay scrubber jumps to the error timestamp. You don't search for it. You don't guess. You just watch.
And because this is the same SDK that handles analytics funnels, you can answer questions like:
- "Did users who hit this error complete checkout?"
- "What percentage of checkout errors have replay footage?" (Hint: if you have 10% replay sampling, that's your answer)
- "What did users do immediately before hitting this error?"
Try answering those with Sentry + LogRocket + GA4. You'll need BigQuery and a free afternoon.
The Bugs This Catches
Here are the kinds of bugs unified error-to-replay linking can surface (illustrative scenarios):
The clipboard paste failure. User copied a discount code from email, pasted it into the promo code field. The paste event fired but the field showed empty. Error: ValidationError: Promo code cannot be empty. The replay showed the user paste, see nothing appear, try again, give up. Root cause: a CSS user-select: none on the parent container was preventing paste on Safari. No error in the traditional sense—just a silent UX failure that looked like user error.
The double-click disaster. User double-clicked the "Place Order" button. First click initiated the request. Second click fired before the button disabled. Both requests hit the server. Server processed both. User got charged twice. Error didn't fire in the browser—the "error" was a Slack message from support. But session replay showed exactly what happened, down to the 47ms between clicks. Fix: debounce and instant disable-on-click.
The race condition nobody believed. Redux state update fired. Component re-rendered. A child component tried to access state that hadn't propagated yet. undefined error. QA couldn't reproduce because their machines were faster. Replay showed a 200ms delay between action dispatch and state availability—enough for the component to render with stale data. The fix was a proper loading state. Classic stuff, but the replay made it undeniable.
None of these are exotic. All of them involve real users, real money lost, real support burden. And all of them would be "can't reproduce" until someone watched the footage.
The GDPR Question
"Session replay sounds like a privacy nightmare." Fair concern.
JustAnalytics masks sensitive content by default:
- All
<input>fields show*****instead of actual keystrokes - Text content is replaced with blocks unless you explicitly whitelist
- Images can be masked or placeholder'd
- Selectors you specify are masked entirely (for PII-heavy areas)
You can tune this. Some teams unmask non-sensitive inputs (like search bars) for better debugging context. Some teams mask entire sections (like account settings). The default is conservative: assume everything is sensitive, prove otherwise.
For GDPR-compliant replay configuration, the key is documenting your masking strategy and ensuring nothing identifiable leaks through. We've written a full walkthrough on that.
And because the replay data lives in the same system as your analytics—not exported to a third-party vendor—you maintain data residency control. For EU teams worried about Schrems III implications, that matters.
Sentry + LogRocket vs. Unified Platform: Honest Comparison
Let's be fair. Sentry is excellent error tracking software. LogRocket is a solid session replay tool. If you're already paying for both and have the integration working, you might not need to switch.
But here's the actual comparison:
| Factor | Sentry + LogRocket | JustAnalytics |
|---|---|---|
| Error-to-replay linking | Via integration, approximate timestamp | Native, exact timestamp, one click |
| Setup | Two SDKs, integration config, context passing | One SDK, enabled by default |
| Monthly cost (50K errors, 10K sessions) | ~$125+ combined | $49 (Pro plan, includes 1M events) |
| Shared session context | Requires configuration | Automatic |
| Analytics correlation | Requires third tool (GA4, Mixpanel, etc.) | Built-in, same session ID |
| SDK payload | Two scripts, larger total | One script, under 5KB |
The JustAnalytics approach isn't strictly better for every use case. If you need Sentry's deep integrations with 50+ frameworks, or LogRocket's enterprise features like co-browsing, those are real differentiators. This is about whether you need those features—or whether you mostly need "error happens, show me what user did."
For most teams, that's the core use case. And that's what unified does better.
The Larger Point
"Cannot reproduce" is usually "cannot imagine what the user did." We assume users follow happy paths. They don't. They tab away. They double-click. They have weird extensions. They copy-paste from weird sources. They use browsers we don't test on machines we don't own.
Users are creative. Chaotically so.
Session replay is a window into reality. Error tracking tells you what broke. Replay shows you why it broke. And when those two pieces live in the same system—same session, same timestamp, one click away—debugging stops being guesswork.
The payment SDK scenario from the opening? "Can't reproduce" to root cause in minutes. That's the difference — not a better debugger, but being able to see what the user saw.
For teams running paid acquisition through ClickzProtect, this correlation becomes critical—you need to know if errors are causing legitimate users to bounce. For call campaigns with VeloCalls, correlating web errors with call abandonment tells you whether landing pages are the problem. And for browser environment testing with JustBrowser, replay footage across browser profiles catches compatibility bugs before users do.
We've written more about why unified observability beats the five-tool stack and how to correlate errors with funnel drop-off. For framework-specific setup, see our Django middleware tutorial or Next.js 15 guide.
Frequently Asked Questions
How does JustAnalytics link errors to session replays automatically?
Both error tracking and session replay share the same session ID and event timeline. When an exception fires, we capture the exact timestamp and session context. Clicking the error in the dashboard jumps you to that moment in the replay—no manual correlation, no timestamp matching, no separate tools.
Can I get this error-to-replay linking with Sentry and LogRocket?
Yes, but it requires their paid integration ($29/month add-on for LogRocket, plus configuration). You need to pass Sentry's session ID to LogRocket and enable the integration on both sides. With JustAnalytics, it's automatic because both features run on the same SDK and share context natively.
Does session replay capture sensitive user data like passwords?
Not by default. JustAnalytics masks all input fields, text content, and sensitive elements automatically. You can configure additional selectors to mask, or whitelist specific elements you want to capture. The default is privacy-safe for GDPR and CCPA compliance.
How much does session replay add to page load time?
The full JustAnalytics SDK—including analytics, error tracking, and session replay—is under 5KB gzipped. Session replay records DOM mutations asynchronously and doesn't block rendering. Most sites see no measurable impact on Core Web Vitals.
Try JustAnalytics
All-in-one observability in one under-5KB script: cookieless analytics + error tracking + APM + session replay + uptime + structured logs. Replaces GA4 + Sentry + Datadog + Pingdom + LogRocket. Free tier (100K events/mo), Pro $49/month ($39 annual).
Author at JustAnalytics.