What the recorders capture
What the browser extension, the web recorder and the Expo recorder capture, where recordings go, which credential they carry and how masking works.
Recording data
This page describes the recording flow. The browser extension is maintained in the vitrinka repository; the Expo SDK and the web recorder (@vitrinka/web) are maintained in the kit repository. Their capture methods differ, as shown below.
Where data goes
Recording data is uploaded to the vitrinka server you configure. Software updates and downloads use separate distribution services; this is not a claim that the application makes no other network requests.
GET /api/v1/recorder/policy recording and masking settings
GET /api/v1/recorder/me who the recorder records as, and its HUD preferences
PATCH /api/v1/recorder/me save the HUD preferences (size, verbose)
POST /api/v1/sessions/:id/chunk rrweb chunks (with a seq query parameter)
POST /api/v1/sessions create a recording session
POST /api/v1/sessions/:id/events the event stream (batched)
POST /api/v1/sessions/:id/shot screenshot keyframes
POST /api/v1/sessions/:id/tags tags on the session
PATCH /api/v1/sessions/:id status (recording | paused | done)
GET /api/v1/sessions/:id the session's own row, to reconcileThese are the recording endpoints. Setup, pairing, listing and resuming sessions also use the server API.
Credentials
A recorder carries a vkr_ recorder token, and that token reaches only the endpoints above — the policy, its own record, creating a session, and, on a session that same token started, its capture leaves, tags, status and read-back. It never lists sessions, reads a session's events or replay, reads a board or touches tasks, and it never reads, closes or writes into a session another credential started — a member's, another project's, or one another recorder token started, even one linked by the same person. Such a call answers 403 with the fix: start a new session (an admin-minted key asking for another project's session gets 404). A leaked token records into its workspace and reads back nothing but the status of the sessions it started. After a recorder is linked again, and across the upgrade that brought this rule, a session started under the old token cannot be continued; start a new one. A token is either linked from a device by approving a short code (bound to the person, expiring 30 days after its last use) or minted by an admin for one project, for unattended builds nobody can link by hand. The browser extension can also use a vkp_ personal token. Tokens are listed and revocable under Settings → Tokens.
When recording happens
Only during a session you explicitly start — and for Expo, only in a build that was allowed to carry the recorder at all.
- Expo — compile time — the recorder exists only in builds whose profile the config plugin allowlists and that set
EXPO_PUBLIC_VITRINKA_URL; every other build strips it from the bundle. No token is baked in: the tester links the device, and only an unattended build carries an admin-minted recorder key. - Expo — run time — inside an enabled build, capture runs only between you pressing record and stop. A machine-driven session started over the Expo devtools channel shows a visible HUD indicator.
- Web — scoped — the recorder mounts only when its
urlis set, and records only on a page whose host matches a project domain rule; a production rule refuses it unless the rule opts in (Settings → Projects → Routing → in-app recorder). - Browser — scoped — capture runs only in tabs matching the project's configured domains, and only while a session you started is live. The popup always shows the recording state.
What is captured, per session
| Channel | Expo recorder | Web recorder | Browser extension |
|---|---|---|---|
| Screenshots | Keyframes on navigation and touch, throttled. | None — the rrweb DOM stream, inputs masked, is the keyframe. | Keyframes plus an rrweb DOM stream. |
| Interactions | Tap coordinates, the pressed element's label, and the route. | Clicks with the element's short selector, its rectangle and a redacted text snippet; every route change. | Clicks and navigation. |
| Network | Method, URL, status, duration, and capped request/response bodies. | Fetch and XHR calls, headers, URLs and bodies passed through the same redaction as the Expo recorder. | API calls including bodies, via CDP. |
| Console | Errors and warnings. | Errors and unhandled rejections. | Errors. |
| Notes | Notes you type in the HUD. | Notes and annotations, on an element or a dragged region. | Notes and ⌖ snaps typed in the on-page HUD (Alt+Shift+N, Alt+Shift+A). |
Redaction
With the default policy, recorders mask sensitive network fields before upload. The server also applies its policy when it receives events. Coverage depends on the recorder and the data format; see Recorder redaction for policy settings and exceptions.
- What counts as secret —
password,token,authorization,cookie,apikey, and multi-word forms likeaccessTokenorrefreshToken. - Workspace policy — the recorders fetch masking settings from
GET /api/v1/recorder/policy. Administrators can add patterns for their application's data.
Do not rely on masking to remove every sensitive detail from screenshots or page content. Text masking and image handling vary by recorder and settings. Use test data when recording.
Retention and access
Recorded sessions live on your vitrinka server, under its access rules. The recorders themselves keep only an undelivered upload tail on the device, which is removed once it is delivered or the session is discarded.