Skill v1.0.0
currentAutomated scan100/100name: subtext-session description: Session replay tools for analyzing Fullstory session recordings. Sparse API catalog — tools are self-describing. metadata: version: "1.0.0"
Session Replay
PREREQUISITE: Readsubtext-sharedfor MCP conventions.
API catalog for the session replay tools (all prefixed review-). One gesture — zoom — over two data sets: the signal stream (temporal) and the snapshot (spatial). Opening a session hands back a map: an always-on orientation header, never a zoom level.
MCP Tools
| Tool | Description | |
|---|---|---|
review-search | Find sessions across the org by what happened in them — a predicate tree over navigate/network/custom signals within a time window. See subtext-search for the query language. | |
review-list-sessions | Find reviewable sessions — numbered URLs + timestamps. With no arguments, the org's most recent captures. With email_address/user_uid, one user's sessions, paged with before. | |
review-open | Open a session for analysis. Returns a handle (client_id) plus the map and a digest rollup. | |
review-summary | Static "what happened" — the default zoom (all kinds @ standard), frozen. No map, no handle. Stateless, cheapest call. Use for a quick read before deciding whether to open. | |
review-zoom | The live lens. Pass a resolution map and/or a t0_ms/t1_ms time window — returns the matching signal slice. | |
review-snapshot | The screen at a moment — screenshot + component tree + boxes, rooted at an optional component_id. | |
review-close | Close the session and free resources; records a short usage summary. |
Discovering Parameters
Parameter schemas are visible in the tool definition at call time.
Session Input
review-open accepts six mutually-exclusive identifiers. Pick the one that matches what you have on hand — they're all first-class:
session_url— a full Fullstory session URL. The most common form — a customer-shared link, a Slack paste, or a session from the app UI.trace_id— the 12-char base62 id from a priorreview-openresponse.trace_url— a full trace URL copied from the browser or returned by a live tool.device_id+session_id— both required together. Use when you have the raw ids but no URL.email_address/user_uid— looks up the user's most recent session.
All six paths return the same handle. Capture the client_id from the response so follow-on review-zoom/review-snapshot/review-close calls don't need to re-resolve the session.
review-open's email_address/user_uid jumps straight to that user's most recent session. To see more than one, or to search back through their history, use review-list-sessions instead.
Finding a user's sessions
review-list-sessions with no arguments lists the org's most recently captured sessions — no filtering, no paging.
Pass email_address or user_uid to scope it to one user instead. That response reports newest/oldest — the creation-time range it covered — and, when more history exists, a note to pass oldest back as before to page further back. before is only valid alongside email_address/user_uid; the org-wide list isn't time-scoped.
Ticket-triage recipe: given a report against a known user, review-list-sessions by their email_address/user_uid to get candidates, review-summary each to find the one matching the report, then review-open it to investigate.
When the report names a behavior rather than a user — "the payment call is failing" — reach for review-search instead; it filters on signals, which review-list-sessions does not do. See subtext-search.
The map
review-open's response includes a map — a cheap counting fold over the signal layer, never a body dump:
## Map · 114 signals · 0.0s–353s · 2 pagesflow: /ui ▸ /settings/overview ▸ /subtext/sessions ▸ /subtext/session/asrkinds: navigation 18 · interaction 36 · network 58 (2 err) · console 2 (2 err)tags: error:4
The map is whole — rendered once, over the entire session. Zooming into {navigation: "standard"} later doesn't touch it: error:4 stays in the map's counts regardless of what you go on to zoom into. Read the map first; it tells you what exists before you pay for a zoom.
The resolution contract
review-zoom takes:
resolution?: { [scope | kind | tag]: "digest" | "standard" | "machine" | "detail" }t0_ms?: number // narrow the zoom to a time windowt1_ms?: number
Grain ladder, coarse → fine:
| grain | what you see | |
|---|---|---|
digest | one rollup line per (section × kind) — network ×19 (1 err) | |
standard (default) | the readable transcript — bursty/repeated signals merged into one line | |
machine | every signal, nothing merged | |
detail | every signal plus its payload — headers, bodies, stack traces |
- Omit `resolution` → everything at
standard. - Provide it → an explicit allow-list. Unlisted kinds are excluded from the slice (never from the map).
- Overlap → finest-wins. A signal matching more than one key takes the finest grain among them — order-independent, and it can only ever show more, never hide something.
Keys are scopes (navigation, interaction, network, console, …), kinds (click, network, exception, classified, …), or tags — they resolve the same way. error/warn/exception are intrinsic (derived from a signal's own fields); a project's .sightmap/ can author more: a component's tags: rides onto any signal that targets it (e.g. defect on a checkout-error element), and a signals: rule can generate a brand-new classified signal when a match fires against another signal's fields — surfacing a classification buried in a payload (a 200 response whose body says a payment declined) as its own selectable line, without touching the signal it fired on.
Zoom recipes
// what went wrong, anywherereview-zoom resolution={ error: "standard" }// what happened in this sessionreview-zoom resolution={ navigation: "standard", interaction: "standard" }// devtool-level detailreview-zoom resolution={ network: "machine", console: "machine" }// network readable, but every error deep — finest-wins, no override neededreview-zoom resolution={ network: "standard", error: "detail" }// a project-authored classification (a .sightmap/ tag or signals: rule), deepreview-zoom resolution={ defect: "detail" }
Snapshot
review-snapshot takes client_id + timestamp, plus:
component_id— optional; roots both the image clip and the tree subtree, so "focus here" means one thing.lens—visible(default),interactive, orfull. Governs which elements populate the tree/boxes, not the pixels.include— any ofimage,tree,boxes.expand_pct— grows thecomponent_idclip outward by this percent (0–100) for surrounding context.upload— store the screenshot and return a shareable signed URL.full_page— capture the whole scrollable page instead of the viewport. Requiresincludeto containimage; can't be combined withcomponent_id. These images are big — pair withupload. Ignored for mobile session pages.
No network/console excerpts are stapled onto a snapshot — signals only come from review-zoom. Want the requests or logs around a moment? Zoom that window.
Tips
- Read the map before you zoom. It's free and tells you whether there's anything worth looking at.
- Start every zoom at
standard(or omitresolutionentirely) unless you already have a hypothesis about which kind matters. erroras a resolution key is a floor, not a special case — it only ever raises detail wherever it applies.- Use
review-snapshotfor "what did the screen look like," not for signals — it's a different data set. - Always close sessions when done to free server resources.
See Also
subtext-shared— MCP conventionssubtext-search— finding sessions by what happened in them (review-search)