# Session Recording

Record and replay user sessions to see exactly how users interact with your application. Session recordings capture DOM mutations, mouse movements, scrolls, clicks, and console logs.

***

## Installation

The session recorder is a separate package from the analytics SDK:

```bash
npm install userlens-session-recorder
```

***

## Quick Start

{% tabs %}
{% tab title="React" %}

```tsx
import { useEffect, useRef } from "react";
import SessionRecorder from "userlens-session-recorder";

export function SessionRecorderProvider({
  userId,
  children,
}: {
  userId: string;
  children: React.ReactNode;
}) {
  const recorderRef = useRef<SessionRecorder | null>(null);

  useEffect(() => {
    if (!userId) return;

    recorderRef.current = new SessionRecorder({
      WRITE_CODE: process.env.NEXT_PUBLIC_USERLENS_WRITE_CODE!,
      userId,
    });

    return () => {
      recorderRef.current?.stop();
    };
  }, [userId]);

  return <>{children}</>;
}
```

{% endtab %}

{% tab title="Vanilla JavaScript" %}

```javascript
import SessionRecorder from "userlens-session-recorder";

const recorder = new SessionRecorder({
  WRITE_CODE: "your-write-code",
  userId: "user-123",
});
```

{% endtab %}

{% tab title="UMD (Script Tag)" %}

```html
<script src="https://unpkg.com/userlens-session-recorder@1.0.4/dist/userlens-session-recorder.umd.js"></script>
<script>
  var SessionRecorder = UserlensSessionRecorder.default;

  var recorder = new SessionRecorder({
    WRITE_CODE: "your-write-code",
    userId: "user-123",
  });
</script>
```

{% endtab %}
{% endtabs %}

***

## Configuration

```typescript
import SessionRecorder from 'userlens-session-recorder';

const recorder = new SessionRecorder({
  WRITE_CODE: string,              // Required: Your Userlens Write Code
  userId: string,                   // Required: Unique user identifier
  recordingOptions: {
    TIMEOUT?: number,               // Session timeout in ms (default: 30 minutes)
    BUFFER_SIZE?: number,           // Events before upload (default: 10)
    maskingOptions?: MaskingOption[], // Input masking (default: ["passwords"])
  },
});
```

### Configuration Options

| Option                            | Type              | Default            | Description                                    |
| --------------------------------- | ----------------- | ------------------ | ---------------------------------------------- |
| `WRITE_CODE`                      | `string`          | Required           | Your Userlens Write Code                       |
| `userId`                          | `string`          | Required           | Unique identifier for the user                 |
| `recordingOptions.TIMEOUT`        | `number`          | `1800000` (30 min) | Inactivity timeout before starting new session |
| `recordingOptions.BUFFER_SIZE`    | `number`          | `10`               | Number of events to buffer before uploading    |
| `recordingOptions.maskingOptions` | `MaskingOption[]` | `["passwords"]`    | Input masking configuration                    |

### Masking Options

Control what input data gets masked in recordings:

```typescript
type MaskingOption = "passwords" | "all";
```

| Option        | Description                               |
| ------------- | ----------------------------------------- |
| `"passwords"` | Only mask password input fields (default) |
| `"all"`       | Mask all input fields                     |

**Examples:**

```typescript
// Only mask password fields (default)
new SessionRecorder({
  WRITE_CODE: "xxx",
  userId: "user-123",
  recordingOptions: {
    maskingOptions: ["passwords"],
  },
});

// Mask all inputs (for sensitive applications)
new SessionRecorder({
  WRITE_CODE: "xxx",
  userId: "user-123",
  recordingOptions: {
    maskingOptions: ["all"],
  },
});
```

***

## Session Management

### Session Timeout

Sessions automatically end after 30 minutes of inactivity (configurable via `TIMEOUT`). When a user returns after the timeout, a new session is created.

```typescript
// Set timeout to 10 minutes
new SessionRecorder({
  WRITE_CODE: "xxx",
  userId: "user-123",
  recordingOptions: {
    TIMEOUT: 10 * 60 * 1000, // 10 minutes
  },
});
```

### Stopping Recording

Call `stop()` when you want to end the recording session:

```typescript
// Stop recording (e.g., on logout)
recorder.stop();
```

This will:

* Stop capturing DOM events
* Clear buffered events
* Remove session data from localStorage

***

## React Integration

### With User Context

```tsx
"use client";

import { useEffect, useRef } from "react";
import SessionRecorder from "userlens-session-recorder";
import { useAuth } from "./auth-context";

export function SessionRecorderProvider({
  children,
}: {
  children: React.ReactNode;
}) {
  const { user } = useAuth();
  const recorderRef = useRef<SessionRecorder | null>(null);

  useEffect(() => {
    // Only record for authenticated users
    if (!user?.id) {
      recorderRef.current?.stop();
      recorderRef.current = null;
      return;
    }

    recorderRef.current = new SessionRecorder({
      WRITE_CODE: process.env.NEXT_PUBLIC_USERLENS_WRITE_CODE!,
      userId: user.id,
      recordingOptions: {
        maskingOptions: ["passwords"],
      },
    });

    return () => {
      recorderRef.current?.stop();
    };
  }, [user?.id]);

  return <>{children}</>;
}
```

### With UserlensProvider

Use alongside the analytics SDK:

```tsx
"use client";

import { useEffect, useRef, useMemo } from "react";
import UserlensProvider from "userlens-analytics-sdk/react";
import SessionRecorder from "userlens-session-recorder";

export function UserlensWrapper({
  userId,
  children,
}: {
  userId: string;
  children: React.ReactNode;
}) {
  const recorderRef = useRef<SessionRecorder | null>(null);

  // Analytics config
  const config = useMemo(
    () => ({
      userId,
      userTraits: {},
      eventCollector: {
        callback: (events) =>
          fetch("/api/userlens/events", {
            method: "POST",
            body: JSON.stringify(events),
          }),
      },
    }),
    [userId]
  );

  // Session recording
  useEffect(() => {
    if (!userId) return;

    recorderRef.current = new SessionRecorder({
      WRITE_CODE: process.env.NEXT_PUBLIC_USERLENS_WRITE_CODE!,
      userId,
    });

    return () => {
      recorderRef.current?.stop();
    };
  }, [userId]);

  return <UserlensProvider config={config}>{children}</UserlensProvider>;
}
```

***

## What Gets Recorded

Session recordings capture:

| Captured        | Description                                    |
| --------------- | ---------------------------------------------- |
| DOM mutations   | Element additions, removals, attribute changes |
| Mouse movements | Cursor position over time                      |
| Scrolling       | Page and element scroll positions              |
| Clicks          | Click events with element context              |
| Input changes   | Text input (respects masking options)          |
| Console logs    | Browser console output                         |
| Page visibility | Tab focus/blur events                          |

***

## Data & Privacy

### Local Storage

The SDK uses localStorage to persist session data:

| Key                         | Purpose                    |
| --------------------------- | -------------------------- |
| `userlensSessionUuid`       | Current session identifier |
| `userlensSessionLastActive` | Timestamp of last activity |
| `$ul_WRITE_CODE`            | Encoded Write Code         |

### Network Requests

Recordings are uploaded to `https://sessions.userlens.io` in chunks based on `BUFFER_SIZE`.

***

## Troubleshooting

### Recordings Not Appearing

1. **Check userId is set** - Recording requires a valid userId
2. **Verify WRITE\_CODE** - Ensure your Write Code is correct
3. **Check console for errors** - Look for SDK error messages
4. **Verify network requests** - Check for requests to `sessions.userlens.io`

### "Userlens SDK error: unavailable outside of browser environment"

The SDK requires a browser environment. If using SSR (Next.js, etc.), ensure the recorder only initializes client-side:

```tsx
'use client'; // Required for Next.js App Router

useEffect(() => {
  // This runs only in the browser
  const recorder = new SessionRecorder({ ... });
}, []);
```

### High Memory Usage

If you notice high memory usage, reduce the buffer size:

```typescript
new SessionRecorder({
  WRITE_CODE: "xxx",
  userId: "user-123",
  recordingOptions: {
    BUFFER_SIZE: 5, // Upload more frequently with smaller batches
  },
});
```

***

## API Reference

### SessionRecorder

```typescript
class SessionRecorder {
  constructor(config: SessionRecorderConfig);
  stop(): void;
}
```

### SessionRecorderConfig

```typescript
interface SessionRecorderConfig {
  WRITE_CODE: string;
  userId: string;
  recordingOptions?: SessionRecordingOptions;
}

interface SessionRecordingOptions {
  TIMEOUT?: number;
  BUFFER_SIZE?: number;
  maskingOptions?: MaskingOption[];
}

type MaskingOption = "passwords" | "all";
```

***

## Next Steps

* [**Custom Events**](/userlens-analytics/guides/custom-events.md) - Track custom user actions
* [**API Reference**](/userlens-analytics/guides/api-reference.md) - Full HTTP API documentation
* [**Troubleshooting**](/userlens-analytics/guides/troubleshooting.md) - Common issues and solutions


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://userlens.gitbook.io/userlens-analytics/guides/session-recording.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
