How to connect a PostHog session recording to the Sentry error it caused
There's no button for this. PostHog's session replay and Sentry's error tracking are two separate products from two separate companies, and neither one ships a field that points at the other. What connects a specific recording to a specific Sentry issue is an identifier the two systems happen to share, usually the user's email or account ID, plus a timestamp close enough to call it the same event. Finding that pair is a manual search, not a lookup.
The confusion is understandable, because PostHog's own error tracking product does this automatically, just not with Sentry. If you're using PostHog's built-in error tracking instead of Sentry, every issue arrives with the user's session replay already attached. Run Sentry as your error tracker alongside PostHog for replay, which is the common setup, and that automatic attachment doesn't exist. Below is why, the identifier that bridges the two anyway, a worked match, and the point where doing this by hand for every error stops being realistic.
Why PostHog and Sentry don't already know about each other
PostHog's error tracking docs describe the in-house version of this plainly, noting "every issue comes with the affected user's session replay, events, and properties attached, so you can see what went wrong instead of trying to reproduce it." That's real, and it's also scoped to PostHog's own error tracking product. Sentry is a different vendor with its own event pipeline, and nothing in either product's documentation describes a native handoff between a Sentry issue and a PostHog recording. If your stack has Sentry catching exceptions and PostHog watching sessions, an error the customer hit and the recording of them hitting it start out as two unrelated rows in two unrelated dashboards.
The identifier that actually bridges the two systems
Both tools already carry a version of "who," you just have to make sure it's the same value in both places.
- PostHog's
identify(). PostHog's identify docs say thedistinct_id"is usually something stable like a UID, their email, or their database ID." Callingidentify()"merges the anonymous person into the identified person, linking the two IDs together," so a recording that started before login still resolves to the same account afterward, as long asidentify()fires at some point in the session. - Sentry's
setUser(). Sentry's identify-user docs describe a user object withid,email, andusernamefields that gets "sent with Sentry events," attaching whoever triggered the error to every event captured while that context is set.
If both calls pass the same email or the same internal user ID, you have one value that shows up in a PostHog person profile and a Sentry issue's user field. That's the whole bridge. Nothing more sophisticated than the same string existing in two places.
Finding the recording yourself
- Open the Sentry issue and read the user. Sentry's search syntax supports
user.email:someone@example.comdirectly, per its searchable properties docs, so once you have the email off one event you can pull every event tied to that person. Note the timestamp of the event that matters. - Filter PostHog's recordings list on that person and a tight window. The replay filter panel accepts properties and a date range, per PostHog's guide to watching recordings, so a person property equal to that email plus a window of a few minutes around the Sentry timestamp usually narrows the list to one or two sessions.
- Watch the recording against the stack trace. Confirm the action in the recording, a click, a form submit, a page load, lines up with what the error actually says failed.
- Write the match down where the fix will happen. Sentry issues support comments in their activity feed, so paste the recording link there. Nothing syncs this automatically in either direction; if the issue reopens later, the link only survives because someone typed it in.
What the stack trace couldn't tell Ingrid
Roundtrip runs a booking platform for equipment rental shops, one screen where a customer picks a delivery window and taps Confirm to lock in a reservation. Ingrid Pruitt is the backend engineer on call the week a Sentry alert fires with TypeError: Cannot read properties of undefined (reading 'id'), six events in an hour, all on the confirm step.
Sentry issue, user field: ops@fieldworks-rental.com
Ingrid pulls the email off the issue and filters Roundtrip's PostHog recordings for that person, narrowed to the ten minutes around the error's timestamp. One session matches. It's fourteen seconds long. The customer double-clicks Confirm, the button doesn't visibly respond fast enough, and they tap the browser's Back button, then Forward, landing back on the confirm screen with a reservation token the frontend no longer has in memory.
Ingrid, in the incident thread: Found it. She's not double-booking, she's going Back mid-request and coming Forward into a page that thinks the token still exists. The undefined read is us trying to reuse a reservation object we already cleared.
She pastes the recording link into the Sentry issue's activity feed and files the fix. She moves the token into session storage instead of component state, so a Back/Forward round trip doesn't lose it. Without the recording, the stack trace alone said an object was undefined. It didn't say why a customer would end up in that state in the first place, and "add a null check" would have shipped without fixing the actual navigation pattern causing it.
What one match doesn't solve
Ingrid's lookup took a few minutes because she had one email and a narrow error rate to work from. That stops holding up for predictable reasons:
- It's a per-issue search. Every new Sentry issue that needs this treatment means pulling an email, switching tools, filtering, and watching. Ten a week is manageable. Forty is a rotation problem.
- Anonymous errors dead-end immediately. If
identify()hasn't fired yet in that session, or ifsetUser()was never called on the Sentry side, there's no shared value to filter on, and the match never starts. - The link lives in one comment. It's on the Sentry issue, not on the PostHog recording, not anywhere a support ticket about the same customer would surface it. The next person debugging a related report starts from zero.
- Nothing ranks which errors are worth this. A backend on-call engineer has no signal, before doing the lookup, for which of six open issues belongs to an account worth the ten minutes and which is a bot hitting a public endpoint.
Where Modem starts the correlation for you
Modem's PostHog integration and Modem's Sentry integration are both connected to the same account and company records Modem already tracks everywhere else. Ask Modem's agent about the confirm-step TypeError and it can pull that account's PostHog analytics, feature flags, and other error-tracking history for the same window into the same answer, because it already has the account behind the Sentry issue and the account behind the PostHog data as one record, not two. That replaces the first half of what Ingrid did by hand: copying an email out of one tool, switching to the other, and guessing how wide a window to search. Debugging starts from what the account was doing, not just the stack trace.
What it doesn't replace is watching the clip. Modem doesn't ingest PostHog's session replay video, so once it points you at the right account and the right window, opening the actual recording to confirm the double-click-then-Back pattern is still a manual step, same as it was for Ingrid. We build Modem, so weigh that against your own setup rather than taking it on faith.
What changes once a match exists, by hand or with Modem's head start, is what happens to it next. Modem keeps a Sentry error, the account it belongs to, and whatever that account has said in Slack, a support ticket, or a renewal call on one topic, so the next report from the same customer, "the booking screen glitched again," lands next to the issue Ingrid already fixed instead of opening a fresh investigation. That's the gap a comment on one Sentry issue doesn't close: the link exists exactly one place, and only for someone who already knows to look there. Pricing is unlimited users on every plan, usage-based beyond what's included, not a charge per error someone happens to trace. Related reading: how to find out which customers hit a Sentry error covers the account-resolution half of this problem, and how to tell if a PostHog rage click is the same bug as an open support ticket walks through the identical identity-matching move from the support side instead of the error-tracking side.
Before the next alert fires
Check that identify() and setUser() both run off the same value, an email is the easiest to eyeball, on every authenticated flow, not just login. That's the one setup step that decides whether the next Sentry issue takes Ingrid's few minutes to trace or dead-ends on an anonymous session with nothing to filter on.
