AI agents: read this page as markdown at /docs/custom-checks/built-in-snapshot-types.md, or start from the full AI-readable index at /llms.txt.

Built-in snapshot types

Meticulous captures some snapshot types automatically during replay — no application code required. Your custom check reporter downloads them alongside any snapshots you record yourself and compares base vs head per session.

Contact Meticulous to enable snapshots

Built-in snapshots are not enabled by default. Reach out to the Meticulous team at support@meticulous.ai to turn on the snapshot types you need for your project.

Snapshot types Meticulous collects for you

Snapshot typeWhat it captures
network-requestsEvery fetch / XHR issued during replay
react-component-rendersPer-component breakdown of which React components re-rendered and how often, sampled at each screenshot

These built-in types capture data snapshots. Meticulous also recognizes custom-recording as a reserved name — that is a project capability flag that enables recordCustomSnapshot, not a snapshot file you download. See Recording custom snapshots.

Do not use these names for your own snapshotType values when calling recordCustomSnapshot.

Common snapshot shape

Every snapshot — built-in or customer-recorded — is a JSON object with:

  • stageDuringSession — which comparison screenshot in the session timeline this entry belongs to (for example screenshot-after-event-00012 or final-state). Meticulous tags each entry with the next screenshot taken after the captured activity, so you can group data per visual diff stage when debugging a check.
  • data — the payload for that entry (schema depends on the snapshot type).
  • versionNumber (optional) — only present on customer-recorded snapshots when you pass one to recordCustomSnapshot. Built-in snapshots omit this field.

Snapshots for a test run are stored per replay under custom-checks-snapshots/ — one uncompressed .json file per type (for example network-requests.json). Your reporter downloads them via getSnapshotsFromTestRun from the @alwaysmeticulous/custom-checks SDK; you do not read these files from S3 directly.

When you call getSnapshotsFromTestRun, each returned snapshot also includes:

  • sessionId — the session the snapshot was captured in, so you can align the same session on base and head.
  • type — the snapshot kind (for example network-requests), so you can filter by it.
  • sessionDescription — a short, human-readable summary of what the user was doing in that session (for example Added an item to the cart), generated by Meticulous and handy for labelling sessions in your report. It is null when the session has no description (for example older sessions, or sessions that have not been selected for testing), so treat it as optional.
const { baseSnapshots, headSnapshots } = await getSnapshotsFromTestRun({
  client,
  testRunId,
  snapshotTypes: ["network-requests", "react-component-renders"],
});

network-requests

Snapshot type: network-requests

When it is captured: Every fetch or XHR the page issues during replay. Each request becomes one array entry, tagged with the session stage active when the request was made.

What each entry contains:

FieldDescription
urlRequest URL
methodHTTP method
requestHeadersRequest headers (HAR shape)
requestBodyRequest body, if any
statusStatus code of the stubbed response served during replay, or null if the request was not matched to a recorded request
responseHeadersResponse headers (HAR shape)
matchedtrue if the request was matched and stubbed; false if it was left unmatched

Large request bodies follow the replay timeline's truncation rules: oversized bodies are ellipsized with an MD5 of the remainder so content changes remain detectable without storing the full payload.

Example entry:

{
  "stageDuringSession": "screenshot-after-event-00003",
  "data": {
    "url": "https://app.example.com/api/graphql",
    "method": "POST",
    "requestHeaders": [{ "name": "content-type", "value": "application/json" }],
    "requestBody": "{\"query\":\"...\"}",
    "status": 200,
    "responseHeaders": [{ "name": "content-type", "value": "application/json" }],
    "matched": true
  }
}

react-component-renders

Snapshot type: react-component-renders

When it is captured: Meticulous installs a React DevTools-style hook before your app's react-dom initializes. On each React commit it walks the committed fiber tree and attributes the work to the components that actually re-rendered (React's PerformedWork flag), recording a per-component breakdown at each comparison screenshot. No application code required; a no-op on non-React pages.

What each entry contains:

FieldDescription
componentsPer-component cumulative render counts by this stage, most-active first and capped to the busiest components

Each components entry:

FieldDescription
nameThe component's display name (e.g. UserMenu), or null when the name was minified away by your production build
sourceOriginal source location of the component as <path>:<line>:<col> (resolved from your source maps), or null when it could not be resolved
commitsCumulative number of commits in which this component re-rendered, by this stage

Use source (not name) to align components across base and head: production builds often minify names differently between builds, but the resolved source path is stable. Each entry counts one render per instance, so a component rendered in many places (a list row, an icon) can have a high commits value. What matters for a regression is the delta vs base: a component whose commits jumps on head pinpoints which component is responsible — for example from a missing memoization or an unstable prop or context value.

Example entry:

{
  "stageDuringSession": "screenshot-after-event-00007",
  "data": {
    "components": [
      { "name": "ResultRow", "source": "src/search/ResultRow.tsx:11:0", "commits": 220 },
      { "name": "ResultsList", "source": "src/search/ResultsList.tsx:24:0", "commits": 38 },
      { "name": null, "source": "node_modules/some-lib/Tooltip.js:8:0", "commits": 9 }
    ]
  }
}