Skip to content

Bugs and session replays from PostHog

Your PostHog already sees the errors your users hit, and records what they did before them. Connect it to an app and those errors arrive as bugs with the replay attached — and any bug, however it was raised, can point at the session that shows it.

Before you start

  • A PostHog project — US Cloud, EU Cloud or self-hosted — and a PostHog login that can see it.
  • For bugs from PostHog, an app in live mode: in qarunbook, App configuration → Settings → What this app is for → Tracking bugs in a live app. Replays can be attached to bugs on any connected app.
  • At least one exception already captured in the project. PostHog's event picker only lists events it has received, so $exception cannot be chosen until one has arrived.
  • To be an admin of the app in qarunbook. PostHog is on every plan.

Connect an app, step by step

  1. In PostHog

    Create a personal API key

    From your avatar, open Settings → Personal API keys and choose Create personal API key. Give it a Label, like qarunbook.

    Under Organization & project access, choose Projects and pick the project.

  2. In PostHog

    Give it read scopes, and create it

    Under Scopes, use the Search scopes box to find and set each of these to Read:

    • Query
    • Session recording
    • Error tracking
    • Project — so the card can show the project's name

    Choose Create key. PostHog may ask you to Re-authenticate first. Copy the key — PostHog shows it once. It needs nothing it can write with.

  3. In qarunbook

    Open the app's PostHog settings

    Open the app, choose App configuration, then the Integrations tab, and choose the PostHog tile under Where errors are caught.

  4. In qarunbook

    Give your PostHog, project and key, and connect

    Pick US Cloud, EU Cloud or Self-hosted (then give its https Address).

    Fill in Project id — the number after /project/ in PostHog's address bar; a project link works too — paste the key into Personal API key, and choose Connect. The key is checked against PostHog before anything is saved.

    The card now shows a Webhook URL and a Signing secret (optional), each with Copy, and the steps for PostHog. Keep it open.

  5. In PostHog

    Add an HTTP Webhook destination

    Go to Data pipelines → Destinations → New destination and choose HTTP Webhook.

    • Paste the card's Webhook URL, and leave Method as POST.
    • Leave the JSON body as PostHog's default, {"event": "{event}", "person": "{person}"}, or add "project": "{project}" as the card suggests (see the body).
    • Paste the card's Signing secret.
  6. In PostHog

    Match exceptions, and create it

    Under Match events and actions, choose Add event matcher and pick Exception ($exception) — or whichever events the card lists under Events that raise a bug.

    Choose Create & enable.

Check it works

  1. In Your tool

    Throw a test exception

    Make your app throw, or, from the browser console on a page that runs PostHog, send one: posthog.captureException(new Error("Test: qarunbook connection")).

  2. In qarunbook

    See the bug arrive

    Within seconds the app has a bug with the error's type and message, the frame it was thrown from (like at renderPrice (…/product.js:88)), the page, browser and OS, the person, and links: Watch the session (PostHog) and Event in PostHog. The card's Last delivery line shows what happened to it.

  3. In PostHog

    See the delivery

    On the destination, the Invocations tab lists each delivery. Yours reads SUCCEEDED.

PostHog's own test button works too. A test event that is not one you listen for reads ignored under Last delivery, which still proves the URL works.

How it works

  • Bugs in. A destination in PostHog posts the events you pick — every captured exception by default — to a URL made for the app. Each becomes a bug on the app with what went wrong, the page or screen, the browser, OS and app version, who it happened to, and links to the session replay, the error-tracking issue and the event.
  • Replays on any bug. A tester can paste a replay link onto any bug on a connected app, or, for a bug an outside reporter sent, look up their latest recorded session. The bug shows Watch the session (PostHog).

A bug from PostHog is the same as one raised in the app: it is filed in Linear, Jira, GitHub or GitLab if the app is connected, Slack and Microsoft Teams hear of it, it can be given a priority and people, and it counts towards Free's monthly allowance of issues. This is the integration with your PostHog.

The URL is the permission: anyone holding it can raise bugs on the app. Keep it in PostHog, and use Regenerate URL and secret, then Make a new URL, if it ends up anywhere else — the old URL stops at once.

The JSON body

PostHog's default body works. The card suggests adding the project, so a delivery from another project is recognised and ignored:

JSON body
{
  "event": "{event}",
  "person": "{person}",
  "project": "{project}"
}

With the signing secret pasted in, PostHog signs each request the Standard Webhooks way, and from the first signed delivery on, unsigned ones are refused.

What becomes the bug

A bug from an exception
TypeError: Cannot read properties of undefined (reading 'total')
at handleSubmit (src/checkout.tsx:42)

PostHog event $exception on https://shop.example.com/checkout
On: Chrome 129 · Mac OS X 14.5 · Desktop · app 2.3.1
Person: user_8f3a21

Watch the session (PostHog): https://us.posthog.com/project/12345/replay/0192a1b2-…
Error tracking issue: https://us.posthog.com/project/12345/error_tracking/0192a1b2-…
Event in PostHog: https://us.posthog.com/project/12345/events/0192a1b2-…
  • For an exception, the first line is its type and message, then the frame of your own code it was thrown from. For any other event, it is the event's name and its message or description property when it has one.
  • Where: $current_url, or $screen_name on mobile. On what: browser, OS, device and $app_version.
  • A replay link when the event had a $session_id, the error-tracking issue when PostHog grouped it into one, and the event itself.
  • Every bug from PostHog affects the platforms you pick under Mark bugs from PostHog as affecting, or every platform if you pick none.

Which events

List them under Events that raise a bug, one per line, exactly as PostHog names them, or add one of the suggestions with a click. Match the same ones in the destination, so PostHog only sends those.

  • $exception — every exception PostHog captures. The default.
  • $error_tracking_issue_created and $error_tracking_issue_reopened — one per error-tracking issue rather than one per exception, if you would rather hear of new issues than of every occurrence. PostHog sends these from error tracking's own alerts rather than from Data pipelines: add an alert there that posts to a webhook, with the same URL and body.
  • Your own, such as bug_reported from an in-app “Report a problem” button. Each one is a new bug.
  • $rageclick and $dead_click — frustration signals, one bug per page per session.

Keeping the noise down

  • Treat repeats as one bug for — Never, or 1 hour up to 7 days (1 day by default). The same exception is recognised by its error-tracking issue, else its fingerprint, else its type and message; it raises one bug, however many users hit it.
  • At most, bugs an hour caps what one connection can raise — 30 by default. Past it, deliveries are dropped until the hour is up.
  • An event PostHog delivers twice is logged once.
  • On Free, once the month's issues are used up, deliveries are not logged until the allowance comes back.

Replays on any bug

On a connected app, every bug has Attach replay for anyone with tester access. Paste the replay's link from PostHog (…/project/12345/replay/…) or just its session id, and choose Attach. It must come from the connected project; a link from another project or another PostHog is refused.

When the bug came from someone outside the team — by email, through the API, or from PostHog itself — and qarunbook knows their PostHog id or email, Find their latest session looks up their most recent recording from the last 30 days. You see when it was and how long, and attach it if it is the right one.

People and privacy

By default a bug names the person by their PostHog id or display name, and never by email: if their id is itself an email, it is hidden. Tick Keep the person's email on the bug when PostHog sends one to write the email down — it is then stored as the bug's reporter and returned by the REST API. Nothing is ever written to PostHog: the key is only used to check the connection and to look up a reporter's sessions, by their PostHog id or email, when someone asks.

Good to know

  • PostHog only brings bugs in and replays onto them. It does not create checks or sections, and nothing already in PostHog is copied across when you connect.
  • Changes to the events, repeats, cap, platforms or email setting are kept when you choose Save. Turn off bugs ignores deliveries until you choose Turn on bugs; the URL stays the same.
  • The key is stored encrypted and never shown again — the card shows only its last four characters. To use another, choose Change.
  • A self-hosted address must be reachable from the internet over https: addresses inside a private network are refused.
  • If the app goes back to testing, bugs from PostHog stop until it is live again. Replays can still be attached.
  • Disconnect stops new bugs at once; delete the destination in PostHog too. Bugs already raised keep their links.

Something unclear or missing? Write to [email protected].