> ## Documentation Index
> Fetch the complete documentation index at: https://docs.notte.cc/llms.txt
> Use this file to discover all available pages before exploring further.

# Recordings

> Record and replay your browser sessions for debugging and analysis

<Tip>
  STOP. Do not read past this section until you have read and followed [/quickstart.md](/quickstart.md).

  Goal: produce a reliable SDK automation script. The intended authoring flow is generate then edit, not write browser automation from scratch.

  Do not hand-write SDK code with element IDs, selectors, or form fields from memory. Element IDs, selectors, and field mappings must come from a live `observe()` call, CLI `notte page observe` output, or generated workflow code. Guessed browser targets fail on real pages.

  Use the Notte skill and CLI to inspect the live site, validate actions/selectors, handle auth/session state, and export workflow code with `notte sessions workflow-code` before using SDK docs or SDK code.

  SDK reference pages are for understanding, running, or editing generated workflow code. They are not the starting point for manually authoring the initial browser automation. SDK-first code is guesswork on real-world pages with dynamic selectors, auth state, CAPTCHAs, and anti-bot behavior.
</Tip>

Notte automatically records every action in your browser sessions, allowing you to download video replays for debugging and analysis. Calling `session.replay()` returns a `ReplayResponse` containing a presigned URL for the MP4 file, which you can download with `replay.download()`.

## Quick Start

Get a recording after your session ends:

{/* @sniptest testers/sessions/recordings/quick_start.py */}

```python quick_start.py theme={null}
from notte_sdk import NotteClient

client = NotteClient()

with client.Session() as session:
    session.execute(type="goto", url="https://example.com")
    session.execute(type="click", selector="button.submit")
    session.execute(type="fill", selector="input[name='email']", value="user@example.com")
    # All actions automatically recorded

# Get replay after session ends
replay = session.replay()
replay.download("session_recording.mp4")
```

## What Gets Recorded

Session recordings capture:

* **Page navigation** - All page loads and URL changes
* **User interactions** - Clicks, fills, scrolls, key presses
* **DOM changes** - Dynamic content updates
* **Visual state** - What the browser displays
* **Timing** - Real-time playback speed

## Session Replays

### Download as MP4

{/* @sniptest testers/sessions/recordings/download_mp4.py */}

```python download_mp4.py theme={null}
from notte_sdk import NotteClient

client = NotteClient()

with client.Session() as session:
    session.execute(type="goto", url="https://example.com")
    session.execute(type="click", selector="a.link")

# Download recording
replay = session.replay()

# Save to file
replay.download("my_automation.mp4")

# Or access the presigned URL directly
print(f"MP4 URL: {replay.mp4_url}")
print(f"Expires at: {replay.expires_at}")
```

### Replay by Session ID

Get a replay for any session using its ID:

{/* @sniptest testers/sessions/recordings/replay_by_id.py */}

```python replay_by_id.py theme={null}
from notte_sdk import NotteClient

client = NotteClient()

# Get replay for a specific session
replay = client.sessions.replay(session_id="your-session-id")
replay.download("session_replay.mp4")
```

## Agent Replays

After running an agent, get the replay from the session:

{/* @sniptest testers/sessions/recordings/agent_replay.py */}

```python agent_replay.py theme={null}
from notte_sdk import NotteClient

client = NotteClient()

with client.Session() as session:
    agent = client.Agent(session=session, max_steps=10)
    result = agent.run(task="Find the contact email on example.com")

# Get replay from the session
replay = session.replay()
replay.download("agent_run.mp4")
```

{/* @sniptest testers/sessions/capabilities/agent_replay_alt.py */}

```python agent_replay_alt.py theme={null}
from notte_sdk import NotteClient

client = NotteClient()

with client.Session() as session:
    pass  # session actions here

# Get replay after session ends
replay = session.replay()
replay.download("agent_run.mp4")
```

## Debugging Failed Runs

Use recordings to understand what went wrong:

{/* @sniptest testers/sessions/recordings/debug_failed.py */}

```python debug_failed.py theme={null}
from notte_sdk import NotteClient

client = NotteClient()

session_id = None

try:
    with client.Session() as session:
        session_id = session.session_id
        session.execute(type="goto", url="https://example.com")
        session.execute(type="click", selector="button.sometimes-missing")

except Exception as e:
    print(f"Automation failed: {e}")

    if session_id:
        # Get recording to see what happened
        replay = client.sessions.replay(session_id=session_id)
        replay.download(f"failed_{session_id}.mp4")
        print("Replay saved for analysis")
```

## Best Practices

### 1. Name Recordings Meaningfully

Use descriptive filenames:

{/* @sniptest testers/sessions/capabilities/name_recordings.py */}

```python name_recordings.py theme={null}
from datetime import datetime

from notte_sdk import NotteClient

client = NotteClient()

with client.Session() as session:
    session.execute(type="goto", url="https://example.com")
    replay = session.replay()
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    replay.download(f"login_test_{session.session_id}_{timestamp}.mp4")
```

### 2. Record Only on Failures

For production, save recordings only when something goes wrong:

{/* @sniptest testers/sessions/capabilities/record_on_failures.py */}

```python record_on_failures.py theme={null}
from notte_sdk import NotteClient

client = NotteClient()

try:
    with client.Session() as session:
        session.execute(type="goto", url="https://example.com")
        # ... automation ...
except Exception:
    if "session" in locals():
        try:
            replay = session.replay()
            replay.download(f"error_{session.session_id}.mp4")
        except Exception:
            pass
    raise
```

### 3. Clean Up Old Recordings

Remove old recordings to save disk space:

{/* @sniptest testers/sessions/recordings/cleanup_old.py */}

```python cleanup_old.py theme={null}
import time
from pathlib import Path


def cleanup_old_recordings(directory: str, days: int = 7):
    """Remove recordings older than specified days."""
    cutoff = time.time() - (days * 86400)

    for recording in Path(directory).glob("*.mp4"):
        if recording.stat().st_mtime < cutoff:
            recording.unlink()
            print(f"Deleted: {recording}")


cleanup_old_recordings("recordings/", days=7)
```

## Recording Limitations

### What's Recorded

* All page interactions
* Visual state changes
* Navigation and reloads
* Dynamic content

### What's NOT Recorded

* Audio
* Network request details (use CDP for this)
* Console logs (use logging)
* Session state before first action

## Storage

Recordings are:

* Stored on Notte's servers after the session ends
* Accessed via presigned URLs (returned by `session.replay()`)
* **Retained for 24 hours**
* Downloadable as MP4 via `replay.download()`

<Warning>
  Recordings are deleted after 24 hours. Download them promptly if needed for later analysis.
  Presigned URLs also expire — check `replay.expires_at` for the expiration time.
</Warning>

## Next Steps

<CardGroup cols={2}>
  <Card title="Live View" icon="eye" href="/features/sessions/live-view">
    Watch sessions in real-time
  </Card>

  <Card title="Session Lifecycle" icon="clock" href="/features/sessions/lifecycle">
    Understand session management
  </Card>

  <Card title="Playwright" icon="code" href="/features/sessions/playwright">
    Connect with Playwright via CDP
  </Card>

  <Card title="Agent Replay" icon="robot" href="/features/agents/replay">
    Agent-specific replay features
  </Card>
</CardGroup>
