Skip to content
Merged
Show file tree
Hide file tree
Changes from 43 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
373f4a9
feat(web-session-recording): support session recording with rrweb
Blinkuu Jul 14, 2025
4dd30ae
Merge branch 'main' into feature/rrweb-session-recording
Blinkuu Jul 17, 2025
30a5e24
fix(web-session-recording): remove redundant options
Blinkuu Jul 17, 2025
783c9c2
fix(web-session-recording): build issues
Blinkuu Jul 17, 2025
85db523
chore(web-session-recording): add poc of injecting faro from k6 with …
Blinkuu Jul 17, 2025
f3036e8
Merge branch 'main' into feature/rrweb-session-recording
Blinkuu Jul 22, 2025
9c8dbd2
feat(web-session-recording): make faro init event-based
Blinkuu Jul 22, 2025
6aa7bc3
chore(web-session-recording): change defaults
Blinkuu Jul 22, 2025
59bb0e1
refactor(instrumentation-session-recording): move session recording u…
Blinkuu Jul 23, 2025
15647fd
Merge branch 'main' into feature/rrweb-session-recording
Blinkuu Jul 23, 2025
179dddd
chore(instrumentation-session-recording): update changelog.md
Blinkuu Jul 23, 2025
255c605
feat(instrumentation-session-recording): update event name
Blinkuu Jul 23, 2025
fb49acf
feat(instrumentation-session-recording): simplify implementation
Blinkuu Jul 23, 2025
cc9c05f
fix(instrumentation-session-recording): remove checkout options
Blinkuu Jul 24, 2025
a278e23
fix(instrumentation-session-recording): add missing default options
Blinkuu Jul 24, 2025
3eedcc3
fix(instrumentation-session-recording): push processed event
Blinkuu Jul 24, 2025
31d909c
feat(instrumentation-session-recording): change event name
Blinkuu Jul 24, 2025
50dd526
chore(instrumentation-sessino-recording): improve typing
Blinkuu Jul 24, 2025
48186b9
chore(instrumentation-session-recording): modify for local testing
Blinkuu Aug 8, 2025
4d31386
Merge branch 'main' into feature/rrweb-session-recording
Blinkuu Sep 9, 2025
565472b
Merge branch 'main' into feature/rrweb-session-recording
Blinkuu Sep 11, 2025
77c174c
chore(deps): yarn install
Blinkuu Sep 11, 2025
a47544e
feat(web-session-recording): add checkout handling
Blinkuu Oct 14, 2025
0d0a958
chore: remove sample k6 script
Blinkuu Nov 17, 2025
9c6e8ed
Merge branch 'main' into feature/rrweb-session-recording
Blinkuu Nov 17, 2025
1e35537
chore(deps): update @grafana/faro-core in @grafana/faro-instrumentati…
Blinkuu Nov 17, 2025
f7c6951
chore: Update README.md
Blinkuu Nov 17, 2025
ed02b0f
chore: Address GitHub Copilot comments
Blinkuu Nov 17, 2025
bd8ac63
chore: remove eventSeq
Blinkuu Nov 17, 2025
9f66174
chore: Remove CLAUDE.md
Blinkuu Nov 17, 2025
ac71a82
chore: Remove commented code
Blinkuu Nov 17, 2025
8f8111d
fix: adress linter issues
Blinkuu Nov 17, 2025
b4ffa60
Merge branch 'main' into feature/rrweb-session-recording
Blinkuu Nov 25, 2025
8a7da7d
fix: update references path in tsconfig.cjs.json
Blinkuu Nov 25, 2025
9fff3dc
chore: remove redundant information from readme
Blinkuu Nov 25, 2025
d1ea363
chore: improve docs
Blinkuu Nov 25, 2025
9b369a8
fix: improve handling of beforeSend hook
Blinkuu Nov 25, 2025
86f27e9
chore: rename to faro-instrumentation-replay
Blinkuu Nov 25, 2025
1207c42
chore: format tsconfig.cjs.json
Blinkuu Nov 25, 2025
fdf74bc
test: add more unit tests
Blinkuu Nov 25, 2025
c243fc1
feat: export mask input options type from index.ts
Blinkuu Nov 25, 2025
040c95d
fix: make stopFn null by on initialization
Blinkuu Nov 25, 2025
c7152c6
fix: update default checkout settings
Blinkuu Nov 25, 2025
d6c4258
test: match defaults in tests
Blinkuu Nov 25, 2025
b41c40c
chore: update readme
Blinkuu Nov 25, 2025
96cdd77
chore: update readme
Blinkuu Nov 25, 2025
8996b75
Merge branch 'main' into feature/rrweb-session-recording
Blinkuu Nov 26, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions experimental/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## Next

- Added support for experimental `ReplayInstrumentation` (`@grafana/faro-instrumentation-replay`).

## 1.13.0

- Improvement (`@grafana/faro-*`) Add required Node engines to package.json ()
Expand Down
107 changes: 107 additions & 0 deletions experimental/instrumentation-replay/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# @grafana/faro-instrumentation-replay

Faro instrumentation for session replay with rrweb.

## Installation

```bash
npm install @grafana/faro-instrumentation-replay
```

## Usage

```typescript
import { ReplayInstrumentation } from '@grafana/faro-instrumentation-replay';
import { getWebInstrumentations, initializeFaro } from '@grafana/faro-web-sdk';

initializeFaro({
url: 'https://your-faro-endpoint.com',
instrumentations: [
...getWebInstrumentations(),
new ReplayInstrumentation({
maskInputOptions: {
password: true,
email: true,
},
maskAllInputs: false,
recordCrossOriginIframes: false,
}),
],
});
```

## Configuration Options

### Privacy & Masking Options

- **`maskAllInputs`** (default: `false`): Whether to mask all input elements
- **`maskInputOptions`** (default: `{ password: true }`): Fine-grained control over which input types to mask.
Available options:
- `password` - Password inputs
- `text` - Text inputs
- `email` - Email inputs
- `tel` - Telephone inputs
- `number` - Number inputs
- `search` - Search inputs
- `url` - URL inputs
- `date`, `datetime-local`, `month`, `week`, `time` - Date/time inputs
- `color` - Color inputs
- `range` - Range inputs
- `textarea` - Textarea elements
- `select` - Select dropdowns
- **`maskSelector`**: Custom CSS selector to mask specific elements
- **`blockSelector`**: CSS selector to completely block elements from recording
- **`ignoreSelector`**: CSS selector to ignore specific elements

### Recording Options

- **`recordCrossOriginIframes`** (default: `false`): Whether to record cross-origin iframes
- **`recordCanvas`** (default: `false`): Whether to record canvas elements
- **`collectFonts`** (default: `false`): Whether to collect font files
- **`inlineImages`** (default: `false`): Whether to inline images in the recording
- **`inlineStylesheet`** (default: `false`): Whether to inline stylesheets

### Hooks

- **`beforeSend`**: Custom function to transform or filter events before they are sent.
Return the modified event or `null`/`undefined` to skip sending

## Privacy and Security

This instrumentation records user interactions on your website. Make sure to:

1. **Enable appropriate masking options** - By default, only password inputs are masked.
Configure `maskInputOptions` to mask additional sensitive fields
2. **Use CSS selectors** - Use `maskSelector` to mask sensitive content, `blockSelector` to completely exclude elements
3. **Implement filtering** - Use the `beforeSend` hook to filter or transform events before sending
4. **Review your privacy policy** - Ensure you have proper user consent for session recording
5. **Test your configuration** - Verify no sensitive information is captured in recordings

### Example: Advanced Privacy Configuration

```typescript
new ReplayInstrumentation({
// 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
maskSelector: '.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
if (event.type === 3 && event.data?.source === 'CanvasMutation') {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Super NIT: why not export a constant for readability. E. g. SENSITIVE_EVENT

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not clear at this point which events are really sensitive. This is just an example to show how one can use the beforeSend hook.

return null; // Skip this event
}
return event; // Send the event as-is
},
});
```
7 changes: 7 additions & 0 deletions experimental/instrumentation-replay/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const { jestBaseConfig } = require('../../jest.config.base.js');

module.exports = {
...jestBaseConfig,
roots: ['experimental/instrumentation-replay/src'],
testEnvironment: 'jsdom',
};
58 changes: 58 additions & 0 deletions experimental/instrumentation-replay/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{
"name": "@grafana/faro-instrumentation-replay",
"version": "2.0.2",
"description": "Faro instrumentation for session replay with rrweb",
"keywords": [
"observability",
"apm",
"rum",
"dem",
"session-replay",
"rrweb",
"browser"
],
"license": "Apache-2.0",
"author": "Grafana Labs",
"homepage": "https://github.com/grafana/faro-web-sdk",
"repository": {
"type": "git",
"url": "https://github.com/grafana/faro-web-sdk.git",
"directory": "experimental/instrumentation-replay"
},
"main": "./dist/cjs/index.js",
"module": "./dist/esm/index.js",
"types": "./dist/types/index.d.ts",
"files": [
"dist",
"README.md",
"LICENSE"
],
"scripts": {
"start": "yarn watch",
"build": "run-s 'build:*'",
"build:compile": "run-p 'build:compile:*'",
"build:compile:cjs": "tsc --build tsconfig.cjs.json",
"build:compile:esm": "tsc --build tsconfig.esm.json",
"build:compile:bundle": "run-s 'build:compile:bundle:*'",
"build:compile:bundle:create": "rollup -c ./rollup.config.js",
"build:compile:bundle:remove-extras": "rimraf dist/bundle/dist",
"watch": "run-s watch:compile",
"watch:compile": "yarn build:compile:cjs -w",
"clean": "rimraf dist/ yarn-error.log",
"quality": "run-s 'quality:*'",
"quality:test": "jest",
"quality:format": "prettier --cache --cache-location=../../.cache/prettier/webSessionReplay --ignore-path ../../.prettierignore -w \"./**/*.{js,jsx,ts,tsx,css,scss,md,yaml,yml,json}\"",
"quality:lint": "run-s 'quality:lint:*'",
"quality:lint:eslint": "eslint --cache --cache-location ../../.cache/eslint/webSessionReplay \"./**/*.{js,jsx,ts,tsx}\"",
"quality:lint:prettier": "prettier --cache --cache-location=../../.cache/prettier/webSessionReplay --ignore-path ../../.prettierignore -c \"./**/*.{js,jsx,ts,tsx,css,scss,md,yaml,yml,json}\"",
"quality:lint:md": "markdownlint README.md",
"quality:circular-deps": "madge --circular ."
},
"dependencies": {
"@grafana/faro-core": "^2.0.2",
"rrweb": "^2.0.0-alpha.18"
},
"publishConfig": {
"access": "public"
}
}
3 changes: 3 additions & 0 deletions experimental/instrumentation-replay/rollup.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const { getRollupConfigBase } = require('../../rollup.config.base.js');

module.exports = getRollupConfigBase('instrumentationReplay');
17 changes: 17 additions & 0 deletions experimental/instrumentation-replay/src/const.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { type ReplayInstrumentationOptions } from './types';

export const defaultReplayInstrumentationOptions: ReplayInstrumentationOptions = {
maskAllInputs: false,
maskInputOptions: {
password: true,
},
maskTextSelector: undefined,
blockSelector: undefined,
ignoreSelector: undefined,
collectFonts: false,
inlineImages: false,
inlineStylesheet: false,
recordCanvas: false,
recordCrossOriginIframes: false,
beforeSend: undefined,
};
2 changes: 2 additions & 0 deletions experimental/instrumentation-replay/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { ReplayInstrumentation } from './instrumentation';
export type { ReplayInstrumentationOptions, MaskInputOptions } from './types';
Loading
Loading