Skip to content

Commit 83d76e2

Browse files
committed
docs(rum): align Electron guide with v0.2.1 behavior
1 parent 5cc62b8 commit 83d76e2

8 files changed

Lines changed: 203 additions & 52 deletions

File tree

en/rum/sdk/electron/advanced-config.mdx

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ await init({
3030
| `clientToken` | `string` | Yes || Client token |
3131
| `service` | `string` | Yes || Service name; must match the value used when uploading source maps |
3232
| `site` | `string` | No | `browser.flashcat.cloud` | Reporting site, used directly as the intake host. Self-hosted deployments set their own domain; for a plain-HTTP intake see [When a proxy is required](#when-a-proxy-is-required) |
33-
| `env` | `string` | No || Environment identifier such as `production` or `staging` |
33+
| `env` | `string` | No || Environment identifier such as `production` or `staging`. It currently enters the span envelope, which is not uploaded; main-process RUM events do not carry it. Configure the renderer separately in `flashcatRum.init()` |
3434
| `version` | `string` | No || Application version; must match the value used when uploading source maps |
3535
| `proxy` | `string` | No || Custom reporting endpoint, see [Self-hosted deployments and proxies](#self-hosted-deployments-and-proxies) |
3636
| `allowedWebViewHosts` | `string[]` | No | `[]` | **Additional** hosts allowed to report through the bridge. A window's own host is always allowed, so configure this only to accept events from third-party pages in a `<webview>` / `BrowserView` |
@@ -179,6 +179,40 @@ import { stopSession } from '@flashcatcloud/electron-sdk';
179179
stopSession();
180180
```
181181

182+
## Identify the signed-in user
183+
184+
Call `setUser()` after sign-in so subsequent main-process events and bridged renderer events carry the same `usr` identity. Call `clearUser()` on sign-out; `getUser()` returns the current identity.
185+
186+
```ts
187+
import { clearUser, getUser, setUser } from '@flashcatcloud/electron-sdk';
188+
189+
setUser({
190+
id: 'user-123',
191+
name: 'Alice',
192+
email: 'alice@example.com',
193+
});
194+
195+
console.log(getUser()); // Returns a copy: { id, name, email }
196+
197+
clearUser();
198+
```
199+
200+
| Field | Required | Description |
201+
|-------|----------|-------------|
202+
| `id` | Yes | Non-empty string written to `usr.id` |
203+
| `name` | No | String written to `usr.name` |
204+
| `email` | No | String written to `usr.email` |
205+
206+
The SDK accepts only these three fields. If `id` is missing or either optional field is not a string, it ignores the entire call and prints a warning. When a main-process identity exists, it **replaces** the renderer event's `id` / `name` / `email` as a unit instead of merging fields. `usr.anonymous_id` is always preserved so the same device remains identifiable across sign-in states.
207+
208+
<Warning>
209+
Main-process `setUser()` covers main-process events and regular RUM events forwarded over the bridge, but it does not rewrite Session Replay segments uploaded directly by the renderer. With replay enabled, call renderer-side `flashcatRum.setUser()` / `flashcatRum.clearUser()` in the same sign-in and sign-out flow.
210+
</Warning>
211+
212+
<Note>
213+
`clearUser()` affects subsequent events only; it does not rewrite data already reported. The SDK stores point-in-time identity history as plain text in `app.getPath('userData')/_dd_user_history`, allowing a native crash parsed on the next startup to retain the user who was signed in when it occurred. Protect the `userData` directory according to your local-data and privacy policy.
214+
</Note>
215+
182216
## Operation monitoring (preview)
183217

184218
Track critical business workflows with paired start and end calls. The backend correlates them by `name` (and an optional `operationKey`) and emits `vital` events.
@@ -209,7 +243,7 @@ failOperation('upload', 'abandoned', { operationKey: 'cover_photo' });
209243
| `options.context` | Custom attributes merged into the event `context` |
210244
| `options.description` | Description written to `vital.description` |
211245

212-
Because correlation happens on the backend, an operation **can start in one process and finish in the other** — for example `startOperation` when the renderer's checkout button is clicked, and `succeedOperation` once the main process has placed the order.
246+
These APIs are provided by the main-process `@flashcatcloud/electron-sdk` package. The currently required `@flashcatcloud/browser-rum` `0.0.7` does not expose matching Operation APIs. If a workflow starts in a renderer, use your application's own preload / IPC surface to call the main-process API, then call the matching completion method in the main process.
213247

214248
<Warning>
215249
This API is in preview and its signatures may change before the stable release.
@@ -364,13 +398,16 @@ The built-in normalization treats the application root as the single anchor. Whe
364398
await init({
365399
//
366400
normalizeStackPath: (absolutePath) => {
401+
// The callback receives the raw frame URL before built-in normalization;
402+
// normalize Windows separators first.
403+
const framePath = absolutePath.replace(/\\/g, '/');
367404
// …/public/dist/renderer.js → /dist/renderer.js (swallow the intermediate public/ segment)
368-
const emitted = /\/public(\/dist\/.+)$/.exec(absolutePath);
405+
const emitted = /\/public(\/dist\/.+)$/.exec(framePath);
369406
if (emitted) {
370407
return emitted[1];
371408
}
372409
// a linked internal package, kept relative to the application root
373-
const linked = /(\/node_modules\/@acme\/widgets\/dist\/.+)$/.exec(absolutePath);
410+
const linked = /(\/node_modules\/@acme\/widgets\/dist\/.+)$/.exec(framePath);
374411
return linked ? linked[1] : undefined; // everything else → the built-in app:///
375412
},
376413
});
@@ -426,7 +463,7 @@ stack.replace(
426463
);
427464
```
428465

429-
When you do need custom mapping, prefer [`normalizeStackPath`](#custom-path-mapping): it receives an absolute path that is already unified across platforms, and it applies to both processes.
466+
When you do need custom mapping, prefer [`normalizeStackPath`](#custom-path-mapping), which applies to both processes. The callback receives the **raw frame URL before built-in processing**; it may contain `file://`, percent escapes, or Windows backslashes, so your mapping must handle the path forms your application emits.
430467
</Warning>
431468

432469
<Note>

en/rum/sdk/electron/compatible.mdx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ This page describes the Electron SDK support scope and current limits so you can
2929
| Other bundlers | No plugin | You must guarantee the instrument entry point runs before `require('electron')` and keep `dd-trace` and the SDK external |
3030

3131
<Warning>
32-
When the main process is bundled, the matching plugin is **required**. Otherwise the bundler's `require` hoisting breaks the `dd-trace` module hook order: the SDK still initializes and reports main-process data, but `BrowserWindow` preload injection fails and renderer processes never receive the bridge object.
32+
When the main process is bundled, the matching plugin is **required**. It preserves the instrument entry order, keeps `dd-trace` and the SDK as runtime dependencies, and copies the SDK's own preload into the packaged output; missing any of these steps can break main-process network tracing or the renderer bridge. The Electron SDK registers its preload per `session`; this does not depend on `dd-trace` wrapping `BrowserWindow`.
3333
</Warning>
3434

3535
## Renderer page loading
@@ -52,6 +52,7 @@ A window's own host is always on the bridge allowlist, so **every loading method
5252
| Main-process view | Supported | One view per main-process instance |
5353
| Node uncaught exceptions / promise rejections | Supported | `process.on('uncaughtException' \| 'unhandledRejection')` |
5454
| Main-process HTTP requests | Supported | Traced by `dd-trace` for `http`/`https`, `fetch`, and `net.fetch`, converted to `resource` |
55+
| Signed-in user identity | Supported | The main process exposes `setUser` / `getUser` / `clearUser` and attaches identity to main-process and bridged renderer events |
5556
| Native crash capture | Supported | Electron `crashReporter` writes minidumps, parsed and uploaded on the next startup |
5657
| Renderer / child process terminations | Supported | Listens for `render-process-gone` / `child-process-gone`, covering terminations that produce no dump |
5758
| Native crash symbolication | Supported | Requires uploading Breakpad symbol files, see [Upload native crash symbols](/en/rum/sdk/electron/advanced-config#upload-native-crash-symbols) |
@@ -72,7 +73,9 @@ A window's own host is always on the bridge allowlist, so **every loading method
7273
| APM / distributed tracing | Flashduty has no span intake today. IPC and child-process command spans collected by `dd-trace` are dropped locally; only HTTP spans become RUM `resource` events |
7374
| Log reporting | Log-type events sent over the bridge from renderers are not forwarded to the backend in this version |
7475
| Main-process Web Vitals | The main process is a Node.js runtime with no DOM or rendering pipeline, so it produces no LCP / INP / CLS, long task, or user action data. The console hides the performance section for main-process views |
75-
| Session renewal signal | Only renderer `click` actions extend the session. A purely background main process enters a new session after 15 minutes without interaction |
76+
| Main-process RUM has no `env` | `env` is currently written only into the span envelope that is not uploaded; it is not attached to main-process RUM events. Renderer events keep the `env` from `flashcatRum.init()` |
77+
| No renderer Operation API | The currently required `@flashcatcloud/browser-rum` `0.0.7` does not expose `startOperation` / `succeedOperation` / `failOperation`. Renderer-triggered workflows must call the main-process API through the application's own preload / IPC surface |
78+
| Session renewal signal | Only renderer `webContents` input events `mouseDown`, `mouseWheel`, `keyDown`, and `rawKeyDown` renew the session. Background activity does not; RUM events after expiry are discarded until the next valid input creates a new session |
7679
| Upload scheme fixed to HTTPS | The `https://` in the `https://<site>/api/v2/rum` template is hardcoded. If a self-hosted intake serves plain HTTP only, changing `site` does not help — use `proxy`. See [Advanced configuration](/en/rum/sdk/electron/advanced-config#when-a-proxy-is-required) |
7780
| No stack on termination events | `render-process-gone` / `child-process-gone` events carry no call stack — the main process cannot unwind a process that is already gone |
7881
| Paint metric correction covers `BrowserWindow` only | `WebContentsView` and `<webview>` have no `show` event, so the SDK cannot observe when they become visible and their paint metrics are reported as they are. In addition, the FCP / LCP of a view whose window was never `show()`n are discarded rather than reported — see [Advanced configuration · FCP and LCP of pre-warmed windows](/en/rum/sdk/electron/advanced-config#fcp-and-lcp-of-pre-warmed-windows) |

en/rum/sdk/electron/data-collection.mdx

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ description: "Learn which event types, fields, and upload behavior the Electron
55
keywords: ["RUM", "Electron SDK", "data collection", "main process", "renderer process", "crash"]
66
---
77

8-
Electron RUM data comes from two processes and is uploaded by the main process. This page describes what each process collects.
8+
Electron RUM data comes from two processes. Regular RUM events are uploaded by the main process, while Session Replay segments are uploaded directly by the renderer. This page describes what each process collects.
99

1010
## Collection overview
1111

@@ -18,7 +18,7 @@ Electron RUM data comes from two processes and is uploaded by the main process.
1818
| Native crashes (minidump) | Main process | Enabled | `error` (`is_crash: true`) |
1919
| Renderer / child process terminations | Main process | Enabled | `error` (`is_crash: false`) |
2020
| Main-process HTTP requests | Main process | Enabled | `resource` |
21-
| Operation monitoring | Main / renderer | Manual (preview) | `vital` |
21+
| Operation monitoring | Main process | Manual (preview) | `vital` |
2222
| Page views, user actions, front-end resources, JS errors, Web Vitals | Renderer process | Enabled | `view` / `action` / `resource` / `error` |
2323
| SDK internal telemetry | Main process | Enabled (20% sampled) | `telemetry` |
2424

@@ -36,19 +36,26 @@ RUM events produced **by the main process itself** are enriched with the followi
3636
| `source` | Always `electron` |
3737
| `view.id` | The active view when the event occurred |
3838
| `view.name` / `view.url` | Always `main process` / `electron://main-process` |
39+
| `usr.anonymous_id` | Device identifier generated and persisted by the SDK |
40+
| `usr.id` / `usr.name` / `usr.email` | Signed-in user identity added after `setUser()` is called |
3941
| `ddtags` | Includes `sdk_version:<SDK version>` |
4042
| `_dd.format_version` | Always `2` |
4143

44+
<Note>
45+
Main-process RUM events currently do not carry `env`. The `env` configuration is only written into the span envelope that is not uploaded; renderer events keep the `env` from their own `flashcatRum.init()` configuration.
46+
</Note>
47+
4248
## How renderer events are identified
4349

44-
When the bridge is working, the main process does **not** rewrite the `source` of renderer events. It overrides three fields and adds one:
50+
When the bridge is working, the main process does **not** rewrite the `source` of renderer events. It overrides two fields and adds two; if a main-process user is set, it also replaces the user identity:
4551

4652
| Field | What the main process does |
4753
|-------|----------------------------|
4854
| `session.id` | Overridden with the main-process session ID |
4955
| `application.id` | Overridden with the configured application ID |
5056
| `container.source` | Added as `electron` |
5157
| `container.view.id` | Added as the current main-process view ID |
58+
| `usr` | When `setUser()` has been called, replaces the renderer identity with the main-process `id` / `name` / `email` while preserving `usr.anonymous_id`; otherwise leaves the renderer value unchanged |
5259

5360
The renderer's own `source`, `view`, `service`, and other attributes are preserved. The two kinds of events are therefore identified differently:
5461

@@ -62,9 +69,25 @@ Filtering on `source:electron` alone in the Explorer returns **main-process even
6269
</Warning>
6370

6471
<Note>
65-
When the bridge is broken (the main process has not integrated the SDK, or it is bundled without the plugin so the preload is never injected), the renderer behaves as a standalone web application and uploads directly: `source` is still `browser`, but there is **no `container` field** and the session is unrelated to the main process. See [What a broken bridge looks like](/en/rum/sdk/electron/sdk-integration#what-a-broken-bridge-looks-like).
72+
When the bridge is broken (for example, the main process never runs `instrument`, or the packaged application is missing the SDK / preload runtime files), the renderer behaves as a standalone web application and uploads directly: `source` is still `browser`, but there is **no `container` field** and the session is unrelated to the main process. See [What a broken bridge looks like](/en/rum/sdk/electron/sdk-integration#what-a-broken-bridge-looks-like).
6673
</Note>
6774

75+
## User identity
76+
77+
At startup, the SDK generates `usr.anonymous_id` and stores it at `app.getPath('userData')/_dd_anonymous_id`. This device identifier remains stable across sessions, application restarts, and login state; the main process manages signed-in identity separately through `setUser()`.
78+
79+
| State | `usr` on events |
80+
|-------|-----------------|
81+
| Before `setUser()` | Contains only `anonymous_id`; it is not copied into `id` |
82+
| After `setUser({ id, name?, email? })` | Contains both the device `anonymous_id` and the signed-in user's standard fields |
83+
| After `clearUser()` | Future events omit `id` / `name` / `email`; `anonymous_id` remains unchanged |
84+
85+
The main process resolves the user at the **time the event occurred**, not when it is uploaded. For example, a native crash parsed on the next startup is still assigned to the user who was signed in when the crash happened. Identity history is stored in `userData/_dd_user_history`; a new process does not automatically restore the previous run's current signed-in user, so call `setUser()` again after confirming login state.
86+
87+
Regular bridged renderer events follow the main-process identity: when the main process has a user, its standard identity fields replace the renderer's; otherwise an identity set through the renderer's `flashcatRum.setUser()` is preserved. Session Replay segments upload directly from the renderer and bypass this step. When Replay is enabled, also call renderer-side `flashcatRum.setUser()` / `flashcatRum.clearUser()` in the login and logout flows.
88+
89+
See [Advanced configuration · Identify the signed-in user](/en/rum/sdk/electron/advanced-config#identify-the-signed-in-user) for the API.
90+
6891
## Session
6992

7093
The main process owns the session lifecycle. Session state is persisted in the `_dd_s` file under `app.getPath('userData')`, so an unexpired session survives an application restart.
@@ -73,12 +96,14 @@ The main process owns the session lifecycle. Session state is persisted in the `
7396
|------|-------|
7497
| Inactivity timeout | 15 minutes |
7598
| Maximum session duration | 4 hours |
76-
| Activity signal | `click` actions bridged from the renderer |
99+
| Activity signal | Electron `webContents` input events: `mouseDown`, `mouseWheel`, `keyDown`, and `rawKeyDown` |
77100
| On expiry | Sends a final view update with `is_active: false` and deletes `_dd_s` |
78101
| On renewal | After expiry, the next activity signal creates a new session and a new view |
79102

80103
<Note>
81-
Only renderer clicks currently extend the session. If your application runs main-process background work for a long time without UI interaction, the session expires after 15 minutes and later main-process events belong to a new session.
104+
Renewal listens directly to Electron input events; it does not depend on the Browser SDK, bridge status, or `trackUserInteractions`. Mouse movement, pointer entry/exit, and key-up events do not count because they can occur without intentional interaction or already have a corresponding press event.
105+
106+
If the application performs only background main-process work without these UI inputs, the session expires after 15 minutes. RUM events after expiry are discarded until the next valid input creates a new session; background work does not start one by itself.
82107
</Note>
83108

84109
## Main-process view
@@ -244,7 +269,9 @@ The main process is a Node.js runtime with no DOM and no rendering pipeline, so
244269

245270
## Operation monitoring (preview)
246271

247-
`startOperation` / `succeedOperation` / `failOperation` track the start and end of critical business workflows (login, checkout, file upload) and emit `vital` events. The backend correlates start and end steps by `name` and an optional `operationKey`, so an operation **can start in one process and finish in the other**.
272+
The main-process `startOperation` / `succeedOperation` / `failOperation` APIs track the start and end of critical business workflows (login, checkout, file upload) and emit `vital` events. The backend correlates start and end steps by `name` and an optional `operationKey`.
273+
274+
The currently required `@flashcatcloud/browser-rum` `0.0.7` does not expose matching Operation APIs. For a workflow triggered in a renderer, use your application's own preload / IPC surface to call the main-process API.
248275

249276
| Field | Description |
250277
|-------|-------------|

0 commit comments

Comments
 (0)