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, submission, validation errors.
- Network requests and console errors, for context during playback.
The recording stream is sampled adaptively. Idle moments are compressed; bursts of activity capture in full fidelity.
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.
To turn off default masking globally (e.g. on internal staging environments), pass maskInputs: false to init.
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 *** 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. |
| data-pl-record | Override an ancestor's data-pl-ignore for this subtree. Use sparingly. |
| data-pl-allow | On an input, capture its value unmasked. Use only for explicitly non-sensitive fields. |
<!-- 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>
<!-- Capture a known-safe search input -->
<input type="text" name="search" data-pl-allow />
Per-page controls
To skip recording on entire pages (e.g. account-settings pages with dense PII):
if (location.pathname.startsWith("/account/")) {
PennyLens.recordSession(false);
}
You can flip it back on for other navigations within the same SPA session:
PennyLens.recordSession(true);
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.
init({
siteId: "YOUR_SITE_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 | 7 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.
Auto-bookmarked friction events
The dashboard automatically jumps the replay scrubber to moments worth watching:
- Rage clicks — three or more clicks on the same element within 1.5 seconds.
- Dead clicks — clicks on elements that don't respond (no event handlers, no navigation).
- U-turn scrolls — rapid down-and-back scrolling, a signal the user couldn't find what they wanted.
- Form errors — validation failures, even if the user later corrected them.
- JavaScript errors — uncaught exceptions during the session.
Bookmarks appear as orange dots on the scrubber. Click any dot to jump there.
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, deleting the user (via dashboard or API) purges all associated recordings within 30 days.
- Subprocessors with access to recording storage are listed in the Privacy Policy.
Next steps
- JavaScript SDK — full method reference
- User identification — linking sessions to known users
- Privacy Policy — data handling and subprocessor list