# Customize Session Replay Sampling with a Custom React Hook

> Build a custom React hook to control Session Replay sampling rates by page, element, or action in your React or Next.js app — capture exactly the replays you want.

**URL:** https://sentry.io/cookbook/customize-session-replay-sampling-hook/

---

Create a custom hook in React that lets you set Session Replay sampling rates by page, element, or action — so you capture exactly the sessions you care about.

**Time:** 10-15 minutes | **Difficulty:** Intermediate

## What You'll Learn

- Disabled global session sampling to avoid conflicting instructions

- Built a custom React hook to control Session Replay sampling

- Scoped replay capture to specific pages, sections, or actions

**Topics:** Session Replay

**SDKs:** React, Next.js

## Before you start

**SDKs & packages**

- [@sentry/browser](https://www.npmjs.com/package/@sentry/browser) (or [@sentry/nextjs](https://docs.sentry.io/platforms/javascript/guides/nextjs/)), minimum version 7.27.0

- The [Session Replay integration](https://docs.sentry.io/platforms/javascript/session-replay/) installed and `replayIntegration()` added to your Sentry init

- Node 12+ and a browser newer than IE11

**Accounts & access**

- [Sentry account](https://sentry.io/signup/) with a React or Next.js project

- A Trial, Developer, Business, or Enterprise plan

**Knowledge**

- Basic [React](https://docs.sentry.io/platforms/javascript/guides/react/) / [Next.js](https://docs.sentry.io/platforms/javascript/guides/nextjs/) experience

- An understanding of your app's traffic volume

## Steps

### 1. Disable replaysSessionSampleRate

Since you'll be implementing a manual sample rate, set `replaysSessionSampleRate` to `0`. This makes sure you catch only the replays you want and don't introduce conflicting sampling instructions. Keep `replaysOnErrorSampleRate` set so error-triggered replays continue to be captured.

```javascript
Sentry.init({
  dsn: process.env.SENTRY_DSN,
  // Disable - using useSessionReplay instead
  replaysSessionSampleRate: 0,
  // Define how likely Replay events are sampled when an error occurs.
  replaysOnErrorSampleRate: 1.0,
});
```

[Session Replay sampling docs](https://docs.sentry.io/platforms/javascript/session-replay/understanding-sessions/)

### 2. Add a hook to control replay sampling

Add this wherever you keep your hooks. You can use it in your app's pages to define **where** you want to sample, **how often**, and to inject additional context. The hook applies your sample rate, then stops any buffered session and starts a fresh recording scoped to the current view. On unmount it flushes the recording and restarts buffer mode so error-triggered replays keep working on other pages.

```typescript
"use client";

import { useEffect } from "react";
import * as Sentry from "@sentry/nextjs";

export interface UseSessionReplayOptions {
  enabled?: boolean;
  sampleRate?: number;
}

export function useSessionReplay(options: UseSessionReplayOptions = {}) {
  const { enabled = true, sampleRate = 1.0 } = options;

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

    // Apply sample rate - randomly decide if this session should be recorded
    const shouldRecord = Math.random() < sampleRate;
    if (!shouldRecord) return;

    const replay = Sentry.getReplay?.();
    if (!replay) {
      console.warn(
        "Sentry replay integration not found. Ensure replayIntegration() is configured."
      );
      return;
    }

    // Stop any existing buffered session to avoid including data from other
    // pages, then start a fresh recording that only captures post-hydration
    // events. Await stop() so start() runs after the previous session ends.
    replay.stop().then(() => {
      replay.start();
    });

    // On unmount, stop and flush, then restart buffer mode so error-triggered
    // replays keep working on subsequent pages.
    return () => {
      replay.stop().then(() => {
        replay.startBuffering();
      });
    };
  }, [enabled, sampleRate]);
}
```

[Session Replay setup guide](https://docs.sentry.io/platforms/javascript/session-replay/)

### 3. Wrap your layout's children with the SessionReplayProvider

The hook uses `useEffect`, so it can only run in a Client Component. Wrap it in a small `"use client"` provider, then wrap your layout's children with `SessionReplayProvider`. By wrapping different layouts or sections, you can individually control the sampling rate for each part of your application.

```typescript
// components/SessionReplayProvider.tsx
"use client";

import {
  useSessionReplay,
  type UseSessionReplayOptions,
} from "@/lib/use-session-replay";

export function SessionReplayProvider({
  children,
  ...options
}: UseSessionReplayOptions & { children: React.ReactNode }) {
  useSessionReplay(options);
  return <>{children}</>;
}

// app/layout.tsx
import { SessionReplayProvider } from "@/components/SessionReplayProvider";

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        <SessionReplayProvider sampleRate={0.5}>
          {children}
        </SessionReplayProvider>
      </body>
    </html>
  );
}
```

[Next.js Session Replay guide](https://docs.sentry.io/platforms/javascript/guides/nextjs/session-replay/)

## Summary

**You capture replays on your terms.**

A custom hook records session replays exactly when and where you want them, instead of relying on a single global sample rate across your whole app.

## Pro Tips

- Check the [Replays view](https://sentry.io/orgredirect/organizations/:orgslug/explore/replays/) after deploying to confirm the hook is recording exactly the pages you scoped it to.

- Set `sampleRate` higher on low-traffic, high-value flows (like checkout or onboarding) and lower on high-traffic marketing pages to control volume.

- During development, pass `sampleRate={1.0}` to capture every session, then dial it down before shipping to production.

- Keep `replaysOnErrorSampleRate` at `1.0` so error-triggered replays are always captured, even on pages where the hook isn't active.

## Common Pitfalls

- Calling the hook from a Server Component won't work — `useEffect` requires a `"use client"` component.

- Leaving `replaysSessionSampleRate` above `0` creates conflicting instructions; the global rate supersedes the hook.

- Masking and blocking of text, inputs, and media are controlled by `replayIntegration()` options, not this hook — the hook only controls *when* to record.

- Forgetting to call `startBuffering()` on cleanup breaks error-triggered replays on subsequent pages.

## FAQ

**Can I call this directly inside a Next.js layout.tsx or page.tsx?**

Only if that file is a Client Component. The hook uses `useEffect`, so a Server Component can't call it. The standard move is a small `"use client"` wrapper component that calls the hook and renders children.

**Why do I need to disable replaysSessionSampleRate?**

`replaysSessionSampleRate` sets a general sampling rate across your whole application. Keeping it intact while also using the custom hook creates conflicting sampling instructions, and the general sampling rate would supersede what you defined with the hook.

**Why does the hook call replay.stop() before replay.start()?**

To drop any buffered data from earlier pages so the new recording only captures post-hydration events for the current view — a clean, scoped session rather than a mix of pages.

**What happens when the component unmounts or I navigate away?**

Cleanup stops the recording and then calls `startBuffering()`, which puts Replay back into buffer mode so error-triggered replays keep working on subsequent pages.

**Are there privacy or PII considerations?**

Yes. Masking and blocking of text, inputs, and media are governed by your `replayIntegration()` options, not this hook. The hook only controls when to record; what is captured is still your integration config's job.

## Next Steps

- [product/session-replay](https://sentry.io/product/session-replay/)

- [Configure Session Replay privacy](https://docs.sentry.io/platforms/javascript/session-replay/privacy/): Control what gets masked or blocked in your replays with the integration's privacy options — masking is governed by your config, not the sampling hook.

- [Understand replay sampling](https://docs.sentry.io/platforms/javascript/session-replay/understanding-sessions/): Learn how session-based and error-based sampling work so you can tune capture rates for your traffic.

---

*Source: [sentry.io/cookbook/customize-session-replay-sampling-hook/](https://sentry.io/cookbook/customize-session-replay-sampling-hook/)*
