Session recordings
PennyLens captures session recordings by serializing DOM mutations through rrweb — not by recording the screen. Recordings are pixel-perfect, render at native resolution on any device, and weigh a fraction of what a video-based replay tool produces.
This page covers what's captured by default, how to control it per-element and per-page, and how retention works across plans.
What's captured
By default, every session records:
- Full DOM at session start, then mutation deltas as the user interacts.
- Click, scroll, mouse movement, and viewport resize events.
- Form interactions — focus, blur, completion timing, and submission.
What's not captured
We never capture:
- Form values matched by our redaction rules — passwords, card numbers, social security numbers.
- Contents of
<input type="password">regardless of name. - Audio, video, or media streams.
- Raw IP addresses (anonymized at ingestion).
Default masking
All <input>, <textarea>, and <select> values are masked in the recording stream by default. The user's interactions — where they typed, when they tabbed away, how long the field took to complete — are preserved. The values themselves are not.
This is a hard default: input masking cannot be turned off, on any plan or environment, including internal staging.
Per-element controls
Decorate elements with data-pl-* attributes to override the default behavior:
| Attribute | Effect |
| --- | --- |
| data-pl-mask | Mask the element's text content (replaces visible text with placeholder characters in the recording). Useful for displayed PII like full names or addresses. |
| data-pl-ignore | Exclude the element from recordings entirely — neither the DOM node nor any mutations on it are captured. |
Both attributes propagate to descendants — applying one to a container covers everything inside it.
<!-- Mask user-displayed PII -->
<div data-pl-mask>Welcome back, Alex Rivera</div>
<!-- Hide an entire payment widget -->
<form data-pl-ignore>
<input type="text" name="card-number" />
</form>
Disabling recording entirely
To skip recordings across the whole site, pass sessionRecording: false to init — the recording layer never attaches and the SDK runs in events-only mode.
PennyLens.init({
projectId: "YOUR_API_KEY", // your API key from Settings, not the project id
sessionRecording: false,
});
The other capture layers (events, heatmaps, scroll depth, form analytics) continue to work.
Retention
Retention windows by plan:
| Plan | Recording retention | | --- | --- | | Free | 30 days | | Pro | 30 days | | Business | 90 days |
After expiry, the recording itself is deleted. Aggregate metrics derived from it — heatmaps, click density, scroll depth — are kept under the longer events-retention window.
Seekable timeline
The replay scrubber shows a color-coded marker for every click, page view, scroll, and form interaction in the session — hover a marker for its label and timestamp, or click it to jump straight there instead of scrubbing blind.
Rage clicks and dead clicks are detected separately as project-wide AI insights (see Product) — they don't yet appear as individual scrubber markers inside a single recording.
Privacy and compliance
- All recordings are stored encrypted at rest (AES-256) in your project's chosen region.
- Recordings are streamed only to authenticated dashboard users with access to the project.
- For GDPR right-to-deletion requests, contact privacy@pennylens.com — recordings and associated events are purged within 30 days. See the Privacy Policy for the full deletion pipeline.
- Subprocessors with access to recording storage are listed in the Privacy Policy.
Next steps
- JavaScript SDK — full method reference
- User identification — the current state of
identify() - Privacy Policy — data handling and subprocessor list