Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
18 changes: 18 additions & 0 deletions docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,15 @@
"zh/rum/sdk/web/faq"
]
},
{
"group": "Electron",
"pages": [
"zh/rum/sdk/electron/sdk-integration",
"zh/rum/sdk/electron/advanced-config",
"zh/rum/sdk/electron/compatible",
"zh/rum/sdk/electron/data-collection"
]
},
{
"group": "Android",
"pages": [
Expand Down Expand Up @@ -1628,6 +1637,15 @@
"en/rum/sdk/web/faq"
]
},
{
"group": "Electron",
"pages": [
"en/rum/sdk/electron/sdk-integration",
"en/rum/sdk/electron/advanced-config",
"en/rum/sdk/electron/compatible",
"en/rum/sdk/electron/data-collection"
]
},
{
"group": "Android",
"pages": [
Expand Down
319 changes: 319 additions & 0 deletions en/rum/sdk/electron/advanced-config.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,319 @@
---
title: "Electron SDK advanced configuration"
description: "Configure the full initialization options, batching, proxy, manual reporting APIs, and source map upload for the Electron RUM SDK"
keywords: ["RUM", "Electron SDK", "advanced configuration", "proxy", "source map", "manual reporting"]
---

This page describes the advanced options and manual reporting APIs of the Electron main-process SDK. Renderer-side advanced configuration is identical to the Web SDK — see [Web SDK advanced configuration](/en/rum/sdk/web/advanced-config).

## Full initialization options

```ts
import { init } from '@flashcatcloud/electron-sdk';

await init({
applicationId: '<YOUR_APPLICATION_ID>',
clientToken: '<YOUR_CLIENT_TOKEN>',
service: 'my-electron-app',
site: 'browser.flashcat.cloud',
env: 'production',
version: app.getVersion(),
telemetrySampleRate: 20,
batchSize: 'MEDIUM',
uploadFrequency: 'NORMAL',
});
```

| Option | Type | Required | Default | Description |
|--------|------|----------|---------|-------------|
| `applicationId` | `string` | Yes | — | RUM application ID |
| `clientToken` | `string` | Yes | — | Client token |
| `service` | `string` | Yes | — | Service name; must match the value used when uploading source maps |
| `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) |
| `env` | `string` | No | — | Environment identifier such as `production` or `staging` |
| `version` | `string` | No | — | Application version; must match the value used when uploading source maps |
| `proxy` | `string` | No | — | Custom reporting endpoint, see [Self-hosted deployments and proxies](#self-hosted-deployments-and-proxies) |
| `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` |
| `telemetrySampleRate` | `number` | No | `20` | SDK internal telemetry sample rate (0–100); set to `0` to disable |
| `batchSize` | `'SMALL' \| 'MEDIUM' \| 'LARGE'` | No | `MEDIUM` | Batch size per upload |
| `uploadFrequency` | `'RARE' \| 'NORMAL' \| 'FREQUENT'` | No | `NORMAL` | Upload interval |
| `defaultPrivacyLevel` | `'mask' \| 'allow' \| 'mask-user-input'` | No | `mask` | Privacy level forwarded to renderers; Session Replay is not supported in this version, so it currently has no effect |

<Note>
`init()` is asynchronous. It returns `false` when validation fails (for example a missing required option). The SDK does not start in that case and prints the specific reason to the console.
</Note>

## Batching and upload frequency

Uploads are disk-buffered: events are written to batch files under `app.getPath('userData')`, rotated once `batchSize` is reached, and uploaded at the `uploadFrequency` interval. A file is deleted only after a successful upload.

| `batchSize` | Size | When to use |
|-------------|------|-------------|
| `SMALL` | 16 KiB | Low event volume, you want data to appear quickly |
| `MEDIUM` (default) | 512 KiB | General purpose |
| `LARGE` | 4 MiB | High event volume, you want fewer requests |

| `uploadFrequency` | Interval | When to use |
|-------------------|----------|-------------|
| `RARE` | 30 seconds | Poor connectivity or power-sensitive applications |
| `NORMAL` (default) | 10 seconds | General purpose |
| `FREQUENT` | 5 seconds | Integration debugging and fast verification |

<Tip>
During integration, temporarily use `batchSize: 'SMALL'` with `uploadFrequency: 'FREQUENT'` so events reach the console faster, then revert to the defaults before shipping.
</Tip>

## Self-hosted deployments and proxies

### Just set `site`

For a self-hosted deployment whose intake speaks HTTPS, set `site` to your own domain — no proxy needed:

```ts
await init({
// ...
site: 'rum.example.internal',
});
```

The upload endpoint becomes `https://rum.example.internal/api/v2/rum`.

### When a proxy is required

The SDK builds its upload URL from the template `https://<site>/api/v2/rum`, and **the `https://` scheme is hardcoded**. `site` therefore cannot cover these cases, which require `proxy`:

- The internal intake serves **plain HTTP** only, with no HTTPS
- The upload path is not `/api/v2/rum` and a gateway has to rewrite it
- Clients cannot reach the intake directly and need a single egress point

```ts
await init({
// ...
proxy: 'https://rum-proxy.example.internal/forward',
});
```

The resulting request is `POST <proxy>?ddforward=%2Fapi%2Fv2%2Frum`. Your proxy must forward the request body to `/api/v2/rum` on your Flashduty instance, preserving the `DD-API-KEY` header. The body is newline-delimited JSON with a `Content-Type` of `text/plain;charset=UTF-8` — do not rewrite it.

<Note>
Once `proxy` is set, `site` no longer contributes to the upload URL and can be omitted.
</Note>

<Warning>
With `proxy` set, the SDK uses the proxy host to detect and skip its own reporting requests, preventing a collection loop. Make sure the proxy value is a complete absolute URL.
</Warning>

## Report errors manually

Exceptions you catch yourself in the main process are not collected automatically. Report them explicitly:

```ts
import { addError } from '@flashcatcloud/electron-sdk';

try {
await syncWorkspace();
} catch (error) {
addError(error, {
context: { component: 'sync', workspaceId: 'ws-1001' },
});
}
```

| Option | Type | Description |
|--------|------|-------------|
| `context` | `Record<string, unknown>` | Custom attributes written to the event `context` |
| `startTime` | `number` | Timestamp of the error, defaults to now |

Manually reported errors carry `error.source` of `custom` and `error.handling` of `handled`, so you can distinguish them from uncaught exceptions in the Explorer.

## Stop the current session

To cut a session short — for example on user logout — call `stopSession()`. The current session expires immediately, and the next activity signal starts a new one.

```ts
import { stopSession } from '@flashcatcloud/electron-sdk';

stopSession();
```

## Operation monitoring (preview)

Track critical business workflows with paired start and end calls. The backend correlates them by `name` (and an optional `operationKey`) and emits `vital` events.

```ts
import { startOperation, succeedOperation, failOperation } from '@flashcatcloud/electron-sdk';

startOperation('checkout');
try {
await runCheckout();
succeedOperation('checkout');
} catch (error) {
failOperation('checkout', 'error');
}

// Parallel operations sharing a name are distinguished by operationKey
startOperation('upload', { operationKey: 'profile_pic' });
startOperation('upload', { operationKey: 'cover_photo' });
succeedOperation('upload', { operationKey: 'profile_pic' });
failOperation('upload', 'abandoned', { operationKey: 'cover_photo' });
```

| Parameter | Description |
|-----------|-------------|
| `name` | Required; only letters, digits, and `_` `.` `@` `$` `-` are allowed |
| `failureReason` | One of `'error'`, `'abandoned'`, or `'other'` |
| `options.operationKey` | Distinguishes parallel operations sharing a name |
| `options.context` | Custom attributes merged into the event `context` |
| `options.description` | Description written to `vital.description` |

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.

<Warning>
This API is in preview and its signatures may change before the stable release.
</Warning>

## Upload source maps

Released Electron applications usually minify their JavaScript, so error stacks only contain minified file names and line/column numbers. Uploading source maps lets Flashduty show the original source location in the error details.

<Warning>
In the current version, **only renderer JavaScript stacks** can be resolved. Main-process stacks use the native Node.js V8 format, which the backend JavaScript stack parser does not recognize yet, so they are displayed as-is. Uploading source maps does not change how main-process errors are displayed.
</Warning>

### The matching rule

**The prefix you upload must correspond to the path in the error stack.**

The backend matches on the **path portion** of the URL only — scheme and host are ignored, so `file:///dist/renderer.js`, `app:///dist/renderer.js`, and `/dist/renderer.js` are equivalent. Integration therefore has two steps:

1. Run the CLI in the directory holding your source maps and **declare a prefix** with `--minified-path-prefix`
2. **Rewrite the stack paths** in the renderer's `beforeSend` hook so they align with the prefix you uploaded

### Why the second step is needed

In a packaged Electron application, the paths in an error stack are the **runtime installation paths**. They are unknown at build time and differ per machine:

| Platform | Actual path in the stack | Predictable at build time? |
|----------|--------------------------|----------------------------|
| macOS | `/Applications/My.app/Contents/Resources/app.asar/dist/renderer.js` | No — the user may install to `~/Applications` |
| Windows | `C:/Users/<username>/AppData/Local/Programs/<app>/resources/app.asar/dist/renderer.js` | No — contains the user name |
| Linux AppImage | `/tmp/.mount_XXXXXX/resources/app.asar/dist/renderer.js` | No — changes on every launch |

Uploading with an installation path as the prefix would match exactly one machine. So the unstable prefix has to be **normalized to a fixed virtual prefix** before the event is sent, making every machine's stack look the same.

### Step 1: generate and upload source maps

Enable source map output in your renderer build configuration:

<CodeGroup>
```ts vite.config.ts
export default defineConfig({
build: { sourcemap: true },
});
```

```js webpack.config.js
module.exports = {
mode: 'production',
devtool: 'source-map',
};
```

```ts build.ts
await esbuild.build({
sourcemap: true,
});
```
</CodeGroup>

Run the [Flashduty CLI](https://github.com/flashcatcloud/flashcat-cli) in the directory containing the source maps, declaring your chosen virtual prefix (`/dist` here):

```bash
flashcat-cli sourcemaps upload \
--service my-electron-app \
--release-version 1.0.0 \
--minified-path-prefix /dist \
--api-key <YOUR_API_KEY> \
./out/renderer
```

<Warning>
Do not ship `.map` files inside the distributed application. Remove them from the output directory after uploading and before packaging the asar, to avoid leaking your source code.
</Warning>

### Step 2: align the prefix in beforeSend

Add `beforeSend` to the renderer initialization to replace installation paths in error stacks with the **same** `/dist` prefix:

```ts renderer.ts
import { flashcatRum } from '@flashcatcloud/browser-rum';

// Must match the --minified-path-prefix used at upload time
const MINIFIED_PATH_PREFIX = '/dist';

flashcatRum.init({
applicationId: '<YOUR_APPLICATION_ID>',
clientToken: '<YOUR_CLIENT_TOKEN>',
service: 'my-electron-app',
site: 'browser.flashcat.cloud',
version: '1.0.0',
sessionSampleRate: 100,
beforeSend: (event) => {
if (event.type === 'error' && event.error.stack) {
// Normalize "…<any install path>/dist/renderer.js" to "/dist/renderer.js"
event.error.stack = event.error.stack.replace(
/(?:file:\/\/)?[^\s()]*?\/dist\//g,
`${MINIFIED_PATH_PREFIX}/`
);
}
},
});
```

<Warning>
`MINIFIED_PATH_PREFIX` in the code and `--minified-path-prefix` on the upload command **must match exactly**. These are the only two places that need to agree — get them wrong and nothing matches: the source maps upload successfully, but stacks are never resolved.
</Warning>

<Tip>
Replace `/dist/` in the regular expression with the actual path segment of your build output directory. After the change, confirm in the console error details that stacks now take the stable `/dist/renderer.js` form before verifying resolution.
</Tip>

<Note>
`beforeSend` can only modify a subset of event fields, and `error.stack` is one of them. The callback needs no return value; returning `false` discards the whole event. See [Web SDK advanced configuration](/en/rum/sdk/web/advanced-config) for the full contract.
</Note>

### When normalization is unnecessary

If your renderer pages are loaded from a **stable URL**, stack paths are already identical across machines. Skip step 2 and upload with the real prefix:

| Loading method | URL in the stack | `--minified-path-prefix` |
|----------------|------------------|--------------------------|
| Dev server | `http://localhost:5173/assets/index.js` | `http://localhost:5173/assets` |
| Remote page | `https://app.example.com/assets/index.js` | `https://app.example.com/assets` |
| Custom protocol | `app://assets/index.js` | `app://assets` |

<Tip>
A custom protocol (register `app://` with `protocol.handle()` and call `loadURL('app://index.html')`) also makes paths stable by construction, and is an alternative to normalization. It only affects source map paths — the bridge works fine under `file://` and needs no change to how pages are loaded.
</Tip>

<Warning>
`--service` and `--release-version` must exactly match the `service` and `version` passed to the SDK. Make source map upload part of your release build and re-upload on every version.
</Warning>

For more details, see [Source mapping and error tracking](/en/rum/error-tracking/source-mapping).

## Related pages

<CardGroup cols={3}>
<Card title="SDK integration" icon="plug" href="/en/rum/sdk/electron/sdk-integration">
Integrate both the main process and renderer processes.
</Card>

<Card title="Compatibility" icon="shield-check" href="/en/rum/sdk/electron/compatible">
Review the support scope and current limits.
</Card>

<Card title="Data collection" icon="database" href="/en/rum/sdk/electron/data-collection">
See which event types and fields each process contributes.
</Card>
</CardGroup>
Loading