Private preview Grafana Cloud

Instrument Session Replay

Note

Session Replay is currently in private preview. Grafana Labs offers support on a best-effort basis, and breaking changes might occur prior to the feature being made generally available.

On this page, you’ll learn how to install and instrument Session Replay in Faro.

Before you begin

To use Session Replay, you need:

Install the Faro Instrumentation Replay package

To install Session Replay:

  1. Open your terminal.
  2. Navigate to your application folder.
  3. Run:
Bash
npm install @grafana/faro-instrumentation-replay

Instrument your application

To enable Session Replay in your application:

  1. Import the faro-instrumentation-replay package:

    js
    import { ReplayInstrumentation } from '@grafana/faro-instrumentation-replay';
    
    // Make sure to import Faro as well
    import { getWebInstrumentations, initializeFaro } from '@grafana/faro-web-sdk';
  2. Pass the ReplayInstrumentation object when initializing Faro:

    js
    initializeFaro({
      // Mandatory, the URL of the Grafana Cloud collector with embedded application key.
      // Copy from the configuration page of your application in Grafana.
      url: 'http://faro-collector-us-central-0.grafana.net/collect/{app-key}',
    
      // Mandatory, the identification label(s) of your application
      app: {
        name: 'my-app',
        version: '1.0.0', // Optional, but recommended
      },
    
      instrumentations: [
       ...getWebInstrumentations(),
       new ReplayInstrumentation()
      ],
    });

Refer to configuration options for more details on how to customize your session recordings.

Understand data masking and sub-sampling

Before you record sessions in production, it’s important to understand how Session Replay protects sensitive data and how it controls the volume of recordings you collect.

Data masking

Session Replay includes masking and privacy configuration options so that you can control exactly what is and isn’t recorded, and make sure there’s no sensitive or personal data being exposed in session recordings.

All input values and text content are masked by default, client-side, before data leaves the browser. You can make masking more selective by using the maskAllInputs and maskInputOptions properties, or by using CSS selectors combined with the maskTextSelector and blockSelector properties. You can also use the beforeSend hook to filter or transform events before sending them.

After making changes to your input masking properties, make sure to test your configuration locally or in development environments before enabling it in production.

Caution

Personally identifiable information (PII) in page URLs is not masked.

For the full list of privacy properties, refer to Privacy and masking options. For broader guidance on what data is recorded and how to meet privacy requirements, refer to Data privacy in Session Replay.

Sub-sampling

Frontend Observability with Session Replay has two independent layers of sampling:

  • Frontend session sampling: Controls which sessions Faro collects telemetry for (logs, errors, traces).
  • Session Replay sampling: Controls what fraction of those sessions also get a recording, configured via samplingRate on ReplayInstrumentation.

For example, a Faro samplingRate of 1.0 combined with a replay samplingRate of 0.1 means telemetry is collected for all sessions, but only 10% of those sessions have a recording:

typescript
initializeFaro({
  url: 'https://your-faro-endpoint.com',
  sessionTracking: {
    samplingRate: 1.0, // collect telemetry (logs, errors, web-vitals) for all sessions
  },
  instrumentations: [
    ...getWebInstrumentations(),
    new ReplayInstrumentation({
      samplingRate: 0.1, // record replay for only 10% of sessions
    }),
  ],
});
// Effective replay coverage: 1.0 × 0.1 = 10% of globally sampled sessions

To ensure you have recordings for the sessions you care about most, review any existing Frontend Session sampler logic to control which sessions are kept or dropped upstream. Refer to the Faro Sampling docs.

Configuration options

You can customize how Session Replay records sessions by passing options to ReplayInstrumentation. The following tables list the available recording, privacy and masking, and hook options, along with their types and default values.

Recording options

KeyTypeDefaultDescription
samplingRatenumber1Fraction of globally sampled sessions that are recorded. Applied on top of sessionTracking.samplingRate. Out-of-range values are clamped.
recordAfter'load' | 'DOMContentLoaded''load'When to start recording if the document is not ready yet
recordCrossOriginIframesbooleanfalseWhether to record cross-origin iframes. Each child iframe must also be instrumented for this to work
recordCanvasbooleanfalseWhether to record canvas element content
collectFontsbooleanfalseWhether to collect fonts used in the website
inlineImagesbooleanfalseWhether to record image content
inlineStylesheetbooleanfalseWhether to inline stylesheets in the recording events
inactivityThresholdMsnumber60000Pause recording after this many milliseconds of inactivity. Recording resumes automatically on the next interaction. Set to 0 to disable.

Privacy and masking options

KeyTypeDefaultDescription
maskAllInputsbooleantrueMask all input content as *
maskInputOptionsMaskInputOptions{ password: true }Selectively mask specific input types (used only when maskAllInputs is false)
maskInputFn(value: string, element: HTMLElement) => stringundefinedCustomize mask input content recording logic
maskTextSelectorstring'*'CSS selector for elements whose text content should be masked. The default value matches all elements
blockSelectorstringundefinedCSS selector for elements that should be blocked from recording. Blocked elements are replaced with a placeholder of the same dimensions
ignoreSelectorstringundefinedCSS selector for elements whose input events should be ignored

maskInputOptions

KeyTypeDescription
passwordbooleanPassword inputs
textbooleanText inputs
emailbooleanEmail inputs
telbooleanTelephone inputs
numberbooleanNumber inputs
searchbooleanSearch inputs
urlbooleanURL inputs
datebooleanDate inputs
datetime-localbooleanDatetime-local inputs
monthbooleanMonth inputs
weekbooleanWeek inputs
timebooleanTime inputs
colorbooleanColor inputs
rangebooleanRange inputs
textareabooleantextarea elements
selectbooleanSelect dropdowns

Hooks

KeyTypeDefaultDescription
beforeSend(event: eventWithTime) => eventWithTime | null | undefinedundefinedTransform or filter events before they are sent. Return null or undefined to skip sending

Examples

The following examples show common ways to configure ReplayInstrumentation. Use them as a starting point and adjust the masking and privacy options to match your application’s requirements.

Mask passwords only configuration

typescript
new ReplayInstrumentation({
  // Disable global input masking and use selective masking rules instead
  maskAllInputs: false,
  // Mask all password inputs
  maskInputOptions: { password: true },
  // Override default CSS selector to stop masking text content
  maskTextSelector: undefined,
})

Advanced privacy configuration

typescript
new ReplayInstrumentation({
  // Disable global input masking and use selective masking rules instead
  maskAllInputs: false,
  // Mask all text and email inputs, but allow number inputs
  maskInputOptions: {
    password: true,
    text: true,
    email: true,
    tel: true,
    textarea: true,
  },
  // Mask elements with specific CSS classes
  maskTextSelector: '.sensitive-data, .pii',
  // Block elements completely from recording
  blockSelector: '.payment-form, .credit-card-info',
  // Ignore certain elements (won't be recorded at all)
  ignoreSelector: '.analytics-widget',
  // Filter or transform events before sending
  beforeSend: (event) => {
    // Example: Skip events that might contain sensitive data
    // type 3 = IncrementalSnapshot, source 9 = CanvasMutation
    if (event.type === 3 && event.data?.source === 9) {
      return null; // Skip this event
    }
    return event; // Send the event as-is
  },
});

Best practices

Override maskTextSelector default value to display elements

The maskTextSelector option accepts a CSS selector string and masks any matching elements in your Session Replay recordings. The default value is '*', which means it’ll match and mask all elements on a page, regardless of other options.

To make sure your masking configuration options work correctly when using maskAllInputs and maskInputOptions, override the maskTextSelector default value:

typescript
new ReplayInstrumentation({
  // Disable global input masking and use selective masking rules instead
  maskAllInputs: false,
  // Mask all password and email inputs
  maskInputOptions: {
    password: true,
    email: true,
  },
  // Override default CSS selector to display other inputs
  maskTextSelector: null,
})

Use maskTextSelector to mask all elements with a CSS class

The maskTextSelector option accepts a CSS selector string and masks any matching elements in your Session Replay recordings.

To selectively mask specific elements, add a class such as masked to any element you want redacted, then pass that class as the selector. This works regardless of which CSS framework you use:

js
new ReplayInstrumentation({
  // Disable global input masking and use selective masking rules instead
  maskAllInputs: false,
  // Mask all text and email inputs, but allow number inputs
  maskInputOptions: {
    password: true,
    text: true,
    email: true,
    tel: true,
    textarea: true,
  },
  // Mask elements with specific CSS classes
  maskTextSelector: '.masked',
});