Labsco
posthog logo

investigating-replay

β˜… 59

by posthog Β· part of posthog/ai-plugin

When a user asks "what happened in this session?" or provides a recording/session ID to investigate, gather all relevant context in parallel rather than making them ask for each piece.

πŸ”₯πŸ”₯πŸ”₯βœ“ VerifiedFreeQuick setup
🧩 One of 7 skills in the posthog/ai-plugin package β€” works on its own, and pairs well with its siblings.

This is the playbook your agent receives when the skill activates β€” you don't need to read it to use the skill, but it's here to audit before installing.

by posthog

When a user asks "what happened in this session?" or provides a recording/session ID to investigate, gather all relevant context in parallel rather than making them ask for each piece. npx skills add https://github.com/posthog/ai-plugin --skill investigating-replay Download ZIPGitHub59

Investigating a session recording

When a user asks "what happened in this session?" or provides a recording/session ID to investigate, gather all relevant context in parallel rather than making them ask for each piece.

Available tools

Tool Purpose posthog:session-recording-get Recording metadata (duration, counts, status) posthog:persons-retrieve Person profile (properties, distinct IDs) posthog:execute-sql Query events, errors, and page views in session posthog:query-error-tracking-issues-list Find error tracking issues linked to the session posthog:vision-observations-list Check for an existing Replay Vision AI summary posthog:vision-scanners-list Find summarizer scanners (scanner_type=summarizer) posthog:vision-scanners-scan-session Run a summarizer scanner on the session (slow, optional) posthog:vision-scanners-create Create a temporary summarizer scanner (ask first) posthog:vision-scanners-delete Delete a temporary scanner after summarizing

Workflow

Step 1 β€” Get recording metadata and person profile

Start with the recording to get metadata and the person's distinct ID:

posthog:session-recording-get
{
 "id": " "
}

The response includes distinct_id, person, duration, interaction counts, console error counts, and viewing status. Use the distinct_id to fetch the full person profile:

posthog:persons-retrieve
{
 "id": " "
}

Step 2 β€” Query same-session events

Get the timeline of what the user did during the session:

posthog:execute-sql
SELECT
 timestamp,
 event,
 properties.$current_url AS url,
 properties.$browser AS browser,
 properties.$os AS os,
 properties.$device_type AS device_type,
 properties.$screen_width AS screen_width
FROM events
WHERE $session_id = ' '
ORDER BY timestamp ASC
LIMIT 200

For sessions with many events, focus on the most informative ones:

posthog:execute-sql
SELECT
 timestamp,
 event,
 properties.$current_url AS url,
 if(event = '$exception', properties.$exception_message, null) AS exception_message,
 if(event = '$exception', properties.$exception_type, null) AS exception_type
FROM events
WHERE $session_id = ' '
 AND event IN ('$pageview', '$pageleave', '$autocapture', '$exception', '$rageclick')
ORDER BY timestamp ASC
LIMIT 100

Step 3 β€” Check for linked error tracking issues

If the recording has console errors or exceptions, find related error tracking issues:

posthog:execute-sql
SELECT DISTINCT
 properties.$exception_fingerprint AS fingerprint,
 properties.$exception_type AS type,
 properties.$exception_message AS message,
 count() AS occurrences
FROM events
WHERE $session_id = ' '
 AND event = '$exception'
GROUP BY fingerprint, type, message
ORDER BY occurrences DESC
LIMIT 10

If fingerprints are found, search for the corresponding error tracking issues to provide links and status:

posthog:query-error-tracking-issues-list
{
 "searchQuery": " "
}

Step 4 β€” Synthesize the investigation

Present the findings as a coherent narrative:

  • Who β€” person properties (name, email, country, plan, etc.)

  • What β€” sequence of pages visited and key actions taken

  • Problems β€” exceptions, console errors, rage clicks, and their frequency

  • Related issues β€” linked error tracking issues with their status (active/resolved)

  • Context β€” session duration, device/browser, activity score

Optional: AI summary via Replay Vision

If the user wants a deeper analysis without reading through events manually, offer a Replay Vision summary. Follow "check-then-scan" β€” don't scan blindly, a scanner can only observe a given session once.

Check for an existing summary. A scheduled scanner may already have one:

posthog:vision-observations-list
{
 "session_id": " "
}

Look for an observation where scanner_snapshot.scanner_type is summarizer and status is succeeded. If found, read scanner_result.model_output (title, summary, intent, outcome, friction_points, keywords) β€” done, no new scan needed.

Find a summarizer scanner if none exists yet:

posthog:vision-scanners-list
{
 "scanner_type": "summarizer"
}
  • Exactly one β†’ use it.

  • More than one β†’ show the user the scanners (name + prompt) and ask which to use.

  • None β†’ no summarizer scanner exists. See No summarizer scanner? Run a temporary one below.

Scan the session with the chosen scanner. Warn this is async and takes several minutes (rasterize + LLM):

posthog:vision-scanners-scan-session
{
 "id": " ",
 "session_id": " "
}

Retrieve the result by polling vision-observations-list (step 1) until the new observation reaches succeeded.

No summarizer scanner? Run a temporary one

If the project has no summarizer scanner, you can still produce a one-off summary with a throwaway scanner β€” but ask the user's permission before creating anything.

Ask permission to create a temporary summarizer scanner just to summarize this one session.

Create it disabled so it never sweeps on a schedule β€” a disabled scanner only runs when you trigger it on demand, so it won't touch other sessions or burn quota in the background:

posthog:vision-scanners-create
{
 "name": "Temporary on-demand summary",
 "scanner_type": "summarizer",
 "scanner_config": {
 "prompt": "Summarize what the user was trying to do, whether they succeeded, and any friction they hit."
 },
 "query": { "kind": "RecordingsQuery" },
 "model": "gemini-3-flash-preview",
 "enabled": false
}

Scan this session on demand with the new scanner, then poll for the result:

posthog:vision-scanners-scan-session
{
 "id": " ",
 "session_id": " "
}

Poll vision-observations-list until the observation reaches succeeded and read scanner_result.model_output.

Ask whether to keep or delete the scanner. Once you have the observation, ask the user if they want to keep the temporary scanner or delete it with vision-scanners-delete. Deleting is safe: the summary you just read is also emitted as an event that persists after the scanner is gone, so cleaning up the temporary scanner does not lose the result.

Tips

  • Run steps 1-3 in parallel when possible β€” they're independent queries.

  • If the recording has very few events, the session was likely very short. Note this rather than suggesting something is broken.

  • Console error count from the recording metadata is a good signal for whether to dig into exceptions. If it's 0, skip step 3.

  • The start_url from the recording tells you where the user's journey began β€” use this to frame the narrative.

  • If person is null on the recording, the user was anonymous. Person properties won't be available, but events still are.