# Session replay recording settings

> The Session replay tab controls what a project records. This page gives each control's purpose, default, and what applies it: server, recorder or nothing.

> **In short**
>
> - Each project has one recording policy. The **Web**, **iOS** and **Android** tabs show that one policy.
> - Only owners and admins can save in the app. Sequential support can also save a new version. The summary line then shows "—" in place of a name. Each save creates a new version.
> - A change needs no redeploy. Websites apply it on the next page load. Mobile apps apply it on the next launch that reaches the network. The server applies its settings immediately.
> - The server applies **Recording**, **Platforms**, **Max MB** and DevTools. The recorder applies **Sampling**, **Skip sessions under (ms)**, **Max minutes**, **URLs** and **Masking**. A modified recorder can bypass these five.
> - Heatmap data is on by default. The **Heatmaps** box on the **Web** tab turns it on or off. See [Heatmap data](#heatmap-data).
> - **Concurrent** and the **Screens** deny list are saved, but they do nothing today.

## What it is for

Session replay records what real people see and do in your product. These settings decide how much of it Sequential keeps. Use them to:

- Stop all recording now, without a code change. For example, do this if a release shows customers' addresses without masking.
- See which buttons users clicked, but never what they typed.
- Record every production session, but only a tenth of staging.
- Keep pages such as checkout out of recordings.

## How it works

Every save of the recording policy creates a new version: v1, v2 and so on.

The mobile tabs grey out the controls that mobile apps do not use. But all three tabs share one policy. For example, **Sampling** set on the iOS tab also applies to the web.

### When a change takes effect, and the replay badge

Recorders fetch the policy themselves, so a change needs no redeploy.

| Who applies it | When a change takes effect |
|---|---|
| Sequential's web recorder | On the next page load |
| Mobile apps | On the next launch that reaches the network |
| The server | Immediately, for each upload as it arrives |

The web recorder fetches the policy on every page load, before it records anything. A mobile app fetches the policy at launch and keeps a copy. The server also applies some settings to every upload as it arrives.

- A production project that nobody has changed shows "defaults · never changed".
- When Sequential creates a staging or development project, it sets its sampling to 10 %. So the project starts at v1, saved in its creator's name.
- Each recording shows the policy version of its first upload. The replay's header shows it as a link, for example **policy v4**, back to this tab.
- On the web, the link shows the version that the recorder fetched for the session's first page. So a session that spans a save keeps the earlier version.
- On mobile, the link shows the version that was current when the first upload arrived. This can be newer than the copy that the app used.
- Recordings made before the first save of the policy show no policy link.

If a web replay is masked in a way you did not expect, check its version. Mobile masking comes from your app's SDK, not from this policy.

## Change a setting

Every role can open the tab. Only owners and admins can save in the app. Sequential support can also save a new version. See [Roles and permissions](/docs/roles-and-permissions).

1. Go to Settings → Projects → your project → **Session replay**.
2. Check the summary line for the policy in effect.
3. Make your changes on the **Web**, **iOS** or **Android** tab.
4. Click **Save**. If the change loosens what is recorded, the **Loosen masking?** sheet opens.
5. If the sheet opens, it shows your project's slug, for example "Type `web-shop` to confirm." Type the slug in **Project slug**, or click **Copy** next to it and paste it. The text must match exactly. A space at the end keeps **Apply** unavailable.
6. Click **Apply**.

If you try to leave the tab before you save, a bar asks "You have unsaved changes in Session replay. Leave without saving?" Click **Stay** to keep your changes, or **Leave** to discard them. If you reload or close the browser tab, your browser asks instead.

If a change records more, you cannot undo it for the recordings made under it. So the sheet asks for the slug. Sequential writes every save to the [Audit log](/docs/audit-log), with the reasons for any loosening.

### The summary line and the version line

An example of the summary line: "Recording ● On · 100 % of sessions · strict masking · 30 d · up to 50 at once · DevTools: errors, console, network, performance".

The line under the tabs shows the version that each platform last fetched. For example: "web on v5 · 2 min ago · iOS never · Android never".

The line does not update on its own. To check it, reload the page. The line can also be up to a minute behind the real fetches.

### What the tab shows while you edit and save

- Members and viewers see the form greyed out, with "Ask an owner or admin to change this."
- An archived project shows **Off** in the summary line.
- The bottom bar lists your changes after "Unsaved changes:". To undo all unsaved changes before you save, click **Discard**.
- After each save, a message confirms the new version: "Recording policy v5 saved — web applies on the next page load, mobile on the next app launch".

**If someone else saved first**

If someone else saved while you were editing, Sequential refuses your save with "Changed by … — Reload to see their change". If Sequential support saved, the message reads "Changed by someone … — Reload to see their change".

**Reload** loads their version and drops your edits. Make your edits again.

## The controls

| Control | What it is for | Default |
|---|---|---|
| **Recording** | Stop all recording at once | On |
| **Platforms** | Choose where the project records | All ticked |
| **Sampling** | Record a share of sessions, to control volume | 100 % |
| **Skip sessions under (ms)** | Leave out very short visits, such as bounces | 2000 |
| **Max minutes** | Stop a tab left open all day from recording all day | 60 |
| **Max MB** | Stop one runaway session from growing without limit | 25 |
| **URLs** lists | Keep pages out, or record only part of your product | Empty |
| **Masking** | Choose how much of each page you can see in a replay | **Strict** |
| **DevTools** | Record the technical context behind a replay | All on, except **Debug** and **Record message text** |

**Max minutes**, **Max MB**, **URLs** and **Masking** work on the web only.

### Where each control applies, and what applies it

Defaults are what a new project starts with. Your project's own values are on the tab.

- **Server** means that Sequential applies the setting to every upload as it arrives, whatever the recorder was told.
- **Recorder** means that Sequential's web recorder applies it, or your app's SDK on mobile. The server does not check it again.

| Control | Default | Applies to | Applied by |
|---|---|---|---|
| **Recording** | On | Web and mobile | Server |
| **Platforms**: **Web**, **iOS**, **Android** | All ticked | Each platform | Server |
| **Sampling** | 100 %. New non-production projects start at 10 % | Web and mobile | Recorder |
| **Skip sessions under (ms)** | 2000 | Web and mobile | Recorder |
| **Max minutes** | 60 | Web only | Recorder |
| **Max MB** | 25 | Web and mobile | Server |
| **Concurrent**: shown in the summary as "up to 50 at once". Not in use | 50 | — | Nothing. Saved but not enforced |
| **URLs** allow and deny lists | Empty | Web only | Recorder |
| **Screens** deny list: takes screen names. Not in use | Empty | **iOS** and **Android** tabs | Nothing yet. Saved but not applied |
| **Masking** | **Strict** | Web only | Recorder, in the user's browser. The server masks attribute values, addresses, input values and DevTools addresses again |
| **DevTools** | All on, except **Debug** and **Record message text** | Web. Also mobile for **Network requests**, and for **Console** while **Record message text** is on | Server, and the recorder |
| **Heatmaps** (Web tab): heatmap data, where sampled visitors click and how far they scroll | On | Web only | Server. The recorder loads the heatmap code only while it is on, and the server stores heatmap data only while it is on |
| Replay retention (no control): how long replays stay available. One of 7, 30, 90, 180 or 365 days. The organisation's period, set by Sequential. A server-wide limit can make it shorter | 30 days | Web and mobile | Server. Sequential stops playing the replay. The storage deletes the recording files about 2 days later |

### Recording and platforms

While **Recording** is **Off**:

- The web recorder does nothing.
- Sequential tells mobile apps not to record.
- Sequential refuses every upload immediately.

Pages that are already open keep running the recorder that they loaded. Sequential stores nothing that they send. When you archive a project, Sequential also turns recording off.

Sequential refuses uploads from a platform that is not ticked. React Native and Flutter apps have no tick box of their own. They record while **iOS** or **Android** is ticked, and they never appear in the line under the tabs.

### Sampling and session caps

**Sampling**

- Each project has its own rate. For example, a staging project can record 10 % while production records 100 %.
- New staging and development projects start at 10 %.
- Beside the slider, "≈ N sessions/month at last week's traffic" estimates the result. It counts the sessions of the last 7 days. Events without a session id are not a session, so they do not count.
- On websites, the recorder decides once per session. So it records a session across several pages completely or not at all.
- A new rate applies to new sessions only.

**Skip sessions under (ms)**

- A value of 0 turns it off.
- On websites, the clock restarts at each page load. So a page that the user leaves sooner sends nothing, even in the middle of a session.
- If users move quickly between pages, keep this value low.

**Max minutes**

- On websites, it also counts from each page load. So it limits each page, not the whole session.

**Max MB**

- The server adds up the size of the recording data that it stores for the session, across its pages. It counts the data before compression. It refuses more data past the limit. On websites, the recorder then stops.
- The limit also applies to mobile apps.
- If Sequential's counter is unavailable, it does not apply the limit.
- The count starts again when a session sends nothing for 2 hours.
- An example of a runaway session is a page with constant animation.

### URL patterns

**Allow (one per line)** and **Deny (one per line)** take path patterns.

- Patterns match the page's path only, with no domain or query string. `https://example.com/checkout` never matches.
- `/checkout/**` matches `/checkout/pay`, but not `/checkout` itself. To keep a whole section out, list both `/checkout` and `/checkout/**`.
- `*` matches within one path segment. `**` matches across segments. So `/account/*/billing` matches `/account/42/billing`.
- If a page matches both lists, the deny list wins. If the allow list has entries, a page must match one of them.
- Each list takes up to 200 patterns, with at most 100 wildcards and 8,192 characters in total.

**When a user moves within your app**

- A user can move to a denied path, or to a path that a non-empty allow list does not include. The recorder notices within about a second. It sends what it has captured, then stops. It stays stopped until the next full page load, even if the user moves back.
- That last second can include the start of the denied page, masked as usual. If a page must never appear, open it with a full page load. Also mask or block its content.
- If a page loads on a path that the lists exclude, nothing records during that page load. This stays true after the user moves within your app to an allowed path. Recording starts at the next full page load on an allowed path.

### Masking presets

Masking happens in the user's browser, before anything is sent.

| Preset | What it does |
|---|---|
| **Strict** (default) | Masks all text and every input. Blocks images, SVG, video, audio, iframes and embeds. Masks attribute values, except structure, id references and known state values. Cuts addresses to their domain, and the page address to its route with id-like parts masked. You see the layout and where people clicked, not what they read. |
| **Balanced** | Masks every input. Masks text only inside elements with the `data-sq-mask` or `data-sq-private` attribute or the `sq-mask` class. Records images and SVG. Still blocks video, audio, iframes and embeds. Records attribute values and the full page address as they are. |
| **Custom** | Any other combination. |

**Advanced selectors** holds **Mask all inputs**, **Mask text selector**, **Block selector**, **Record canvas**, **Collect fonts** and **Attribute text**. The two selector fields take CSS selectors, separated by commas. If you choose **Strict** or **Balanced**, Sequential overwrites all six. If you edit any of them, the preset changes to **Custom**, and the summary line shows "custom masking" after you save.

From 10 October 2026, the recorder always gets `[data-sq-private]` in its **Mask text selector**, also when the field is empty and masks no other text. You do not need to add it, and the field does not show it. Under **Strict**, the selector is `*`, which masks all text already.

**Canvas snapshots.** From 10 October 2026, when **Record canvas** is on, the recorder records each canvas as a series of snapshots, not as its drawing calls. By default, it takes 2 snapshots a second, as WebP images at quality 0.6. A canvas that does not change adds nothing to the recording after its first snapshot. Two project settings change this: `replay.masking.canvas_fps`, a whole number from 1 to 10 snapshots a second, and `replay.masking.canvas_quality`, from 0.1 to 1.0. The app has no control for them yet. An owner or admin sets them through the settings API, with PATCH `/api/projects/:id/config`. The API refuses a value outside these ranges, and the recorder uses the default when it gets no valid value. A preset does not change them, and a change to them keeps the preset.

**Attribute text** has three choices: **Strict** ("Mask attribute text and link paths"), **URLs** ("Remove link queries and fragments only") and **Off** ("Record attributes as the page has them"). The **Strict** preset uses **Strict**, and **Balanced** uses **Off**. **URLs** is a **Custom** choice only. **Attribute text** also sets how DevTools shortens network addresses and code locations. See [Masking and redaction](/docs/masking-and-redaction).

Both presets mask what users type, the value of a checkbox or radio button that a user picks, the name of a file that a user picks and the value of hidden fields.

Masked text keeps its place and shows as solid blocks (█). A blocked element leaves an empty box of the same size. Add `data-rr-block` to any element that must never be captured. Both presets block it.

Sequential never re-masks a recording later. Each recording keeps the masking that it was made with. See [Masking and redaction](/docs/masking-and-redaction).

### DevTools captures

| Capture | What it records |
|---|---|
| **JavaScript errors** | Uncaught exceptions and unhandled promise rejections, with stack traces. Web only. |
| **Console** | Calls at the levels you tick. By default **Errors**, **Warnings**, **Info** and **Logs**, not **Debug**. |
| **Network requests** | Each request's method, URL, status, timing and size. Never its headers or body. |
| **Performance** | Core Web Vitals and page-load timing, per page load. Web only. |

The server applies your current DevTools settings to every upload. So when you turn a capture off, Sequential stops storing it immediately. This includes data from an older recorder or a mobile app.

Replays recorded while a capture is off do not show as clean for that kind. They carry no count for it, never a zero. So the **With JS errors** and **With failed requests** filters cannot return them. The session list says how many sessions in the range it could not check for that filter.

On mobile, logs on iOS and network timing on Android also need a setting in the app itself. See [Mobile apps](/docs/mobile) and [DevTools](/docs/devtools).

> **Console text can hold personal data**
>
> **Record message text** is off by default. If you turn it on, Sequential stores whatever your app writes to the console. Anyone who can open the project's replays can read it: every role, viewers included. If you turn it off later, Sequential keeps the text that it already stored.

### Record message text

**Without it**, a web console entry keeps its level, how often it was logged and where. Warnings and errors also keep a stack trace. The entry does not keep the words that were logged.

**With it**, you also get the words, such as "payment failed: card_declined" or an API error body. The words are often why the entry matters.

**Redaction:** Sequential replaces these with `[redacted]`:

- JWTs
- Bearer and Basic credentials
- email addresses
- card numbers
- values under names like `password` or `token`

No rule catches a name, a postal address or a one-time link in a log line.

When you tick it, the tab warns: "Message text is free-form and no rule can reliably redact it. Turn this on only if your app never logs secrets or personal data."

- Keep it off for production until you have checked what your app logs.
- Settings are per project, so a separate staging project can keep it on.
- While **JavaScript errors** is on, Sequential keeps exception messages either way.
- On iOS and Android, Sequential asks the app for logs only while **Record message text** is on.

### Network request settings

- **Keep query values for** lists the query parameter names whose values you want to keep. Sequential records every other query value as `[redacted]`.
- **Don't record requests to** takes patterns, one per line. `*` stays within a path segment and `**` crosses segments.
- Unlike the **URLs** lists, these patterns match the request's full address without its query string. So include the domain, as in `https://api.example.com/health`, or start with `**`, as in `**/health`.

### Changes that open the sheet

The sheet is titled **Loosen masking?**, also when only DevTools settings change. It opens when a save would:

- stop masking inputs, stop masking all text, or turn text masking off. A move from **Strict** to **Balanced** counts.
- remove anything from **Block selector**, or turn on **Record canvas**.
- remove an entry from a **URLs** or **Screens** deny list.
- turn on **JavaScript errors**, **Console** or **Network requests**, add a console level, or turn on **Record message text**.
- add a name to **Keep query values for**, or remove a pattern from **Don't record requests to**.
- lower **Attribute text**: from **Strict** to **URLs** or **Off**, or from **URLs** to **Off**. A move from **Strict** to **Balanced** counts.

### Changes that widen recording without asking

These changes record more, but the sheet does not open:

- turning **Recording** or a platform on.
- raising **Sampling**, **Max minutes** or **Max MB**.
- lowering **Skip sessions under (ms)**.
- adding entries to a **URLs** allow list that already has some, or clearing it.
- turning on **Collect fonts** or **Performance**.
- replacing one **Mask text selector** with another, unless the old one masked all text.

## Heatmap data

Sequential collects heatmap data for a sample of recorded web sessions: where visitors click and how far they scroll, as page structure and counts, with no text. The **Heatmaps** page shows its click counts and scroll depth. See [Heatmaps](/docs/sessions-and-replay#heatmaps). For what it holds, see [Heatmap data](/docs/privacy-overview#heatmap-data).

The **Heatmaps** box is on the **Web** tab. It says: "Counts clicks and scroll depth from a sample of recorded web sessions: numbers only. The page picture comes from a masked recording and is visible to people who can watch replays."

- **On by default** for each project that records websites.
- **Agents.** From 15 October 2026, the switch also covers agents. With heatmap data off, `list_heatmap_pages` and `get_heatmap` answer `off`, with the reason.
- **The switch.** Only owners and admins can change it. Members and viewers see it read-only. The **Turn on in settings** button on the **Heatmaps** page opens this box. Turning it on opens a sheet, "Turn on heatmaps for …?", that says what is counted and who sees the page picture. Nothing is saved until you click **Turn on**. Turning it off asks nothing and saves at once. For the sheet's full text, see [Turn heatmap data on or off](/docs/privacy-overview#turn-heatmap-data-on-or-off).
- **The switch saves on its own.** It saves a new version at once, without **Save**, and leaves your other unsaved edits as they are. The **Audit log** records it as `project.config_changed`.
- **Sample.** **Auto**: "the server picks the rate from your recorded traffic". **Fixed**: a percentage of recorded sessions, from 0.1 to 100. **Sample** saves with the rest of the tab when you click **Save**. It is disabled while heatmaps are off. See [Limits](/docs/limits#heatmap-data).
- **It needs Recording and Web.** While **Recording** or **Web** is off, the switch and **Sample** are disabled. The box says "Recording is off, so no heat is collected." or "Web recording is off, so no heat is collected."
- **From the next page load.** The web recorder stops loading the heatmap code on the next page load. Sequential's servers stop storing heatmap data from open pages once they read the new setting.
- **The page picture stops too.** While heatmap data is off, a request for a page picture answers `off`. See [The page picture](/docs/privacy-overview#the-page-picture).
- **Save keeps the switch as it is stored.** **Save** sends the stored on or off value back, with the form's **Sample**.
- **To check it,** expand **What SDKs receive** and look for `heatmaps` under `replay`.
- **Through the API.** A script signed in as an owner or admin can set `replay.heatmaps.enabled` with PATCH `/api/projects/:id/config`. It must send the whole settings document, with `If-Match`. See [Turn heatmap data on or off](/docs/privacy-overview#turn-heatmap-data-on-or-off).

## What it needs

- **Websites:** Sequential's recorder, from [Session replay (web)](/docs/session-replay) or started by the [Sequential SDK](/docs/sequential). Web replays come only from this recorder, whichever analytics SDK you use.
- **Mobile apps:** PostHog's iOS or Android SDK, sending to Sequential. See [Mobile apps](/docs/mobile).

## Limits

- **Saved, not enforced:** **Concurrent** and the **Screens** deny list do nothing today. The **What SDKs receive** panel lists fields that nothing acts on today.
- **A modified recorder can bypass recorder-only settings.** So can anyone who sends data with your project's public replay key.
- **Mobile masking is not on this tab.** Your app's SDK sets it.
- **Not retroactive.** Settings apply to new recordings only.
- **Replays stop playing first, and the files go later.** By default, after 30 days you cannot play a replay. The storage deletes the recording files about 2 days after that. If you delete the project, its recordings become unreadable at once, and the storage deletes the files later.
- **Per project, not per visitor.** For a visitor's consent choice, see [Sequential SDK](/docs/sequential), or add the recorder tag only after the visitor consents ([Session replay (web)](/docs/session-replay)).
- **No version history view.** The tab shows the current version only.
- `/checkout/**` does not match `/checkout` itself. To keep a whole section out, list both `/checkout` and `/checkout/**`.
- **URLs** patterns match the path only. A pattern with a domain, such as `https://example.com/checkout`, never matches.
- In a single-page app, recording stops after a move to an excluded path. It starts again only at the next full page load on an allowed path.
- A replay can include about one second of a denied page after an in-app move. If a page must never appear, open it with a full page load.
- On websites, **Skip sessions under (ms)** and **Max minutes** count from each page load. A short page sends nothing, even in the middle of a session.
- Some changes record more but do not open the **Loosen masking?** sheet. Examples are raising **Sampling** and clearing a **URLs** allow list.
- **Don't record requests to** matches the full address. A path-only pattern such as `/health` never matches. Use `https://api.example.com/health` or `**/health`.
- While **JavaScript errors** is on, Sequential keeps exception messages, even with **Record message text** off.

### Limits in detail

**Concurrent and Screens**

- **Concurrent** is editable, and the summary shows it as "up to 50 at once". But nothing reads it, so it does not limit how many sessions record at once. To control volume, use **Sampling** and the session caps.
- On the **iOS** and **Android** tabs, **Deny (one per line)** takes screen names. The tab says: "Saved now — not yet applied to mobile recordings."

**What SDKs receive**

The panel lists the session budget, `events_retention_days`, the IP setting, the property deny and hash lists, and the allowed origins and bundle ids. `events_retention_days` is the organisation's events retention period, and Sequential applies it: see [Retention and deletion](/docs/retention-and-deletion). Sequential applies the allowed origins to every request that sends data. Owners and admins change them in the **Allowed websites** card on **Sources & keys**. See [Organisations and projects](/docs/organisations-and-projects). The others do not restrict who can send data or which properties Sequential keeps. The one exception is heatmap data: if the allowed origins list hosts, Sequential drops heatmap data from pages on other hosts.

**Recorder-only settings**

The server does not check **Sampling**, **Skip sessions under (ms)**, **Max minutes**, **URLs** or text masking again. It does mask attribute values, addresses, input values and DevTools addresses again, under the current settings of the project.

**Mobile masking**

The mobile tabs say "Compile-time in the PostHog mobile SDK — not remote-configurable."

**Not retroactive**

Tightening masking or turning a capture off does not change what is already stored.

**Retention**

The summary line shows how long replays stay available: by default 30 days ("30 d"), counted from when the first part of the recording arrived at Sequential. Lines under it show the organisation's two periods, for example "Events kept · Set by Sequential: 30 days" and "Replays kept · Set by Sequential: 30 days". If the server sets a shorter limit, the summary and the lines show the limit. See [A server-wide limit](/docs/retention-and-deletion#a-server-wide-limit). The organisation sets both periods for all its projects. The tab has no control for them, and only Sequential support can change them. A shorter period deletes nothing: stored recordings keep their old period. Through the settings API, a change of either period gets 409 `retention_set_by_organisation` and saves nothing. After the period, you cannot play the recording in Sequential. See [Retention and deletion](/docs/retention-and-deletion).

**Version history**

Owners and admins see each save under **Recent changes** on the project's **Overview** tab, as a sentence such as "Ana changed the project settings (v5)". The audit log also shows each save, with what changed.

## Related

- [Find and replay sessions](/docs/sessions-and-replay)
- [DevTools](/docs/devtools)
- [Masking and redaction](/docs/masking-and-redaction)
- [Retention and deletion](/docs/retention-and-deletion)
- [Session replay (web)](/docs/session-replay)
- [Mobile apps](/docs/mobile)
- [Roles and permissions](/docs/roles-and-permissions)
- [Audit log](/docs/audit-log)
