Skip to content

Cassette formats

Cassettes can be stored as YAML (the default) or TOML. The format is detected from the file extension: .yaml and .yml for YAML, .toml for TOML.

YAML

The default, and the most readable. JSON bodies are stored as structured YAML:

version: 1
interactions:
  - request:
      method: POST
      uri: https://api.openai.com/v1/chat/completions
      headers:
        content-type:
          - application/json
      body:
        type: json
        content:
          model: gpt-4o
          messages:
            - role: user
              content: Hello!
    response:
      status: 200
      body:
        type: json
        content:
          id: chatcmpl-abc123
          choices:
            - message:
                role: assistant
                content: Hi there!
    recorded_at: '2026-02-20T10:30:01Z'

Compare that to VCR.py, where the same body would be one long escaped string. When the API response changes, your git diff shows exactly which field changed.

TOML

Use the .toml extension to get TOML cassettes:

with use_cassette("cassette.toml"):
    ...

TOML loads about 2 times faster than YAML and produces about 12% smaller files. The tradeoff: TOML cannot represent null values or heterogeneous arrays, so body content is stored as a JSON string instead of as structure.

Tip

Use YAML when humans read the cassettes, use TOML when you have thousands of interactions and load time matters.

Convert between formats

The cassetter CLI converts existing cassettes:

$ cassetter convert cassette.yaml cassette.toml

Convert a whole directory in place, changing extensions:

$ cassetter convert tests/cassettes/ toml

Or convert into a separate output directory:

$ cassetter convert tests/cassettes/ output/ --to toml

Rewrite cassettes in place, keeping the same format. This requires --force because it overwrites the source files:

$ cassetter convert tests/cassettes/ yaml --force

This is the command you want when migrating a VCR.py cassette corpus: every file is re-read (Cassetter understands the VCR format) and re-written in Cassetter's format. Writes go through a temp file, so an interrupted run never leaves a truncated cassette.

Conversion scrubs by default

cassetter convert applies the default security filtering to every interaction it writes: sensitive headers, query parameters, and body fields are removed or replaced, exactly as at record time. Cassettes recorded by VCR.py usually contain real authorization headers, so this matters.

If you need a byte-faithful conversion instead, opt out:

$ cassetter convert cassette.yaml cassette.toml --no-scrub

Body types

Bodies are stored with an explicit type, so replay is always faithful:

Type Content
json Structured data, stored as YAML structure
text Plain text, stored as a string
binary Anything else, stored as hex
none Empty body

Compressed responses (gzip, brotli, zstd) are decompressed before recording, so the cassette always contains readable content.