> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.doc-detective.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.doc-detective.com/_mcp/server.

# stopRecord

> Stop capturing a video of test execution.

The `stopRecord` action stops a video recording started by an earlier [`record`](record) action and saves the video file.

You can choose which recording to stop:

* **Most recent (boolean or null):** `stopRecord: true` or `stopRecord: null` stops the most recently started recording that's still active (last in, first out). Use this when only one recording is active, which is the common case.
* **By name (string):** `stopRecord: "<name>"` stops the active recording with a matching `name`. Use this to stop a specific recording when several overlap.
* **By name (object):** `stopRecord: { "name": "<name>" }` is the object form of targeting a recording by `name`.

When you target by name, Doc Detective stops that recording wherever it falls in the active set, not just the most recent one. For more about running several recordings at once, see [Multiple overlapping recordings](record#multiple-overlapping-recordings).

The same untargeted and named forms stop recordings of every kind. Browser, desktop app window, and mobile device-screen recordings all live on the same stack. For device recordings, `stopRecord` is also the point where the video transfers from the device and saves. It converts to `.webm` or `.gif` when the target path calls for it.

> Note: To finalize and save a recording started with the `record` action, include a `stopRecord` step. An untargeted `stopRecord` skips recordings created by [`autoRecord`](record#automatic-recordings); Doc Detective finalizes those automatically at the end of the context.
>
> For comprehensive options, see the [`stopRecord`](/reference/schemas/stoprecord) reference.

**Outputs:** when a recording saves, the action exposes the following values in its `outputs` object. To capture any of them for later steps, use the step-level `variables` object with the matching expression. Metadata fields are best-effort. When Doc Detective can't read the saved file's metadata, it omits those fields without failing the step:

* `$$recordingPath`: the absolute path of the saved video file.
* `$$format`: the saved file's format (`mp4`, `webm`, or `gif`).
* `$$duration`: the video's duration in seconds.
* `$$width` and `$$height`: the video's dimensions in pixels, after any window or viewport crop.
* `$$fps`: the video's frame rate.

When the recording ran with [checkpoints](record#recording-checkpoints) enabled, the outputs also include:

* `$$checkpoints`: per-checkpoint results (file name, variation, whether the baseline was missing).
* `$$maxCheckpointVariation`: the highest variation across the span's checkpoints. Beyond the configured `maxVariation`, the step returns WARNING.
* `$$seededBaselines`: how many baselines this stop seeded (first run only; `0` when every checkpoint compared against an existing baseline).
* `$$checkpointErrors`: how many checkpoints couldn't be captured or compared, such as an aspect-ratio mismatch against the baseline. Any errors also return WARNING, because an incomparable checkpoint is a drift signal rather than a clean pass.

With [`overwrite: "aboveVariation"`](record#refreshing-stale-recordings-automatically):

* `$$changed`: whether the span meaningfully changed and the recording (plus its baselines) was refreshed. `false` means the fresh capture was discarded and the existing file kept.
* `$$changeReasons`: why the recording refreshed (drift, added/removed steps, missing file). Present only when `changed` is `true`.
* `$$baselineFailures`: how many checkpoint baselines Doc Detective couldn't write during a refresh. It's present only when at least one failed. The video refreshed but its baselines didn't fully follow, so the next run treats the mismatch as drift and refreshes both again.

With [`verify` guards](record#verifying-the-video-file-itself):

* `$$resolutionMatch`: whether the video's dimensions match the expected resolution (±2 pixels). Present only when the `resolution` guard ran.
* `$$allBlack`: whether black frames cover 95% or more of the video. Present only when the `notBlack` guard ran. A violated guard fails the step.

In a headless run of an `aboveVariation` or checkpointed span (the recording itself is skipped):

* `$$stale`: whether the committed recording appears stale, meaning its baselines no longer match the current content. `true` also returns WARNING and fires a post-run hint suggesting a headed re-run.

A skipped `stopRecord` (no active recording, or a recording that never started) reports no outputs.

## Examples

This example starts recording, performs an action, and then stops the recording.

```json
{
  "tests": [
    {
      "steps": [
        {
          "description": "Start recording.",
          "record": "./output/session_video.mp4"
        },
        {
          "description": "Navigate to the site.",
          "goTo": "https://example.com"
        },
        {
          "description": "Stop the recording.",
          "stopRecord": true
        }
      ]
    }
  ]
}
```

This example stops a specific recording by name while another recording is still running.

```json
{
  "tests": [
    {
      "steps": [
        {
          "description": "Start the login clip.",
          "record": {
            "path": "./output/login.mp4",
            "name": "login"
          }
        },
        {
          "description": "Navigate to the site.",
          "goTo": "https://example.com"
        },
        {
          "description": "Stop the login clip by name.",
          "stopRecord": "login"
        }
      ]
    }
  ]
}
```