Skip to content

Electron Monitoring

The Windows SDK integrates with Electron through the Native Bridge: Browser RUM and Browser Logs in the Renderer collect page data, and the Electron Main Process passes the data to the Windows Native Core, which manages application ID, session, sampling, global context, persistent queue, and upload.

Choose a mode based on the initialization owner of the Native SDK:

Mode Use Cases vcpkg Feature SDK Owner
Mixed Mode Embedding Electron pages in C++ desktop applications electron-adapter C++ Host
Full Mode The application itself is Electron electron-bridge guance_windows_electron_bridge.exe

The two modes cannot be used together. The page side shares the same Preload, attachWindow(), and Renderer initialization method.

This method is different from the Electron standalone access for Web RUM. In the Windows SDK integration, the Renderer does not upload data directly, nor does it configure the real application ID, report address, or Client Token.

The data flow is as follows:

Electron Renderer
  @cloudcare/browser-rum / @cloudcare/browser-logs collector
          |
          | FTWebViewJavascriptBridge.sendEvent(JSON)
          v
Secure Preload -> Whitelist IPC -> Electron Main Process
          |
          v
Windows Native Core (initialized by C++ Host or Bridge EXE)
  Native RUM / Log / Session / Sampling / Context / Persistence / Upload

Integrating Electron

Installing Dependencies

In the Renderer project that needs to be monitored, install the Browser SDK:

npm install @cloudcare/browser-rum @cloudcare/browser-logs@^3.3.6

If you do not collect Browser Logs, you can skip installing @cloudcare/browser-logs.

Follow the Quick Start to configure the GuanceCloud vcpkg registry. The current Electron Adapter only supports dynamic x64-windows.

Full Mode uses electron-bridge:

{
  "dependencies": [
    {
      "name": "guance-windows-native",
      "default-features": false,
      "features": ["electron-bridge"]
    }
  ]
}

Mixed Mode uses electron-adapter:

{
  "dependencies": [
    {
      "name": "guance-windows-native",
      "default-features": false,
      "features": ["electron-adapter"]
    }
  ]
}

In the directory containing vcpkg.json, run:

vcpkg install --triplet x64-windows

When integrating, only use the following public entry points:

  • electron/main/index.cjs: Entry point for Full Mode and Mixed Mode in the Main Process;
  • electron/preload/standalone.cjs: Use directly when the application has no existing Preload;
  • electron/preload/install.cjs: When the application already has a Preload, this file is merged into the business Preload by the bundler.

Do not copy, modify, or directly reference files under electron/internal/.

During development, load the Adapter from the vcpkg_installed directory of the project; after packaging, load from process.resourcesPath:

const path = require("node:path");
const { app } = require("electron");

const sdkDirectory = app.isPackaged
  ? path.join(process.resourcesPath, "guance-windows-native")
  : path.resolve(
      __dirname,
      "../../../vcpkg_installed/x64-windows/tools/guance-windows-native",
    );

const mainAdapterPath = path.join(
  sdkDirectory,
  "electron",
  "main",
  "index.cjs",
);

The relative path of the development directory should be adjusted according to the application structure. Do not rely on the current working directory or hardcode the absolute path of the development machine.

Initializing the Native Bridge

Mixed Mode

The C++ Host initializes the Windows SDK first, then binds the Bridge Server to the existing guance_sdk_handle:

guance_sdk_handle sdk = guance_sdk_init(&config);

guance_electron_bridge_server_options options{};
guance_electron_bridge_server_options_init(&options);
options.pipe_name = "my-app-rum";
options.logging_enabled = 1;
options.session_replay_enabled = 0;
options.replay_privacy_level = "mask";

guance_electron_bridge_server_handle bridge =
    guance_electron_bridge_server_start(sdk, &options);

// When the application exits, stop the Bridge Server first, then shut down the SDK.
guance_electron_bridge_server_stop(bridge);
guance_sdk_shutdown(sdk);

The Electron Main Process connects to the same named pipe:

const { ipcMain } = require("electron");
const { connectMixedMode } = require(mainAdapterPath);

const rumBridge = await connectMixedMode({
  ipcMain,
  pipeName: "my-app-rum",
  enableAppLaunch: true,
});

In Mixed Mode:

  • Do not start guance_windows_electron_bridge.exe, otherwise a second SDK Handle will be created;
  • Electron no longer needs to pass application ID, DataKit/Dataway, cache, or upload configuration;
  • The C++ Host must ensure that the lifecycle of the SDK Handle is longer than that of the Bridge Server;
  • When collecting Browser Logs, you need to enable Native custom logging simultaneously and set logging_enabled to 1.

Full Mode

When the application itself is an Electron app, the Main Process starts and manages the Bridge EXE:

const { app, ipcMain } = require("electron");
const { startFullMode } = require(mainAdapterPath);

const rumBridge = await startFullMode({
  ipcMain,
  nativeDirectory: sdkDirectory,
  enableAppLaunch: true,
  nativeSettings: {
    applicationId: "<rum-application-id>",
    datakitUrl: "http://127.0.0.1:9529",
    service: "electron-desktop-client",
    environment: "prod",
    version: app.getVersion(),
    cachePath: path.join(app.getPath("userData"), "native-rum-cache"),
    sampleRate: 1,
    loggingEnabled: true,
    loggingSampleRate: 1,
    replayEnabled: false,
    replaySampleRate: 1,
    replayPrivacy: "mask",
    debug: false,
  },
});

The sample rates for Native RUM, Log, and Replay are all values from 0 to 1. Before the application exits, you need to wait for rumBridge.stop() to complete.

connectMixedMode() and startFullMode() enable enableAppLaunch by default. The Adapter automatically generates launch_cold and launch_hot Actions based on the Electron application lifecycle, the first frame of trusted windows, and the Browser View context. Set it to false if you do not need automatic start Actions. To ensure that cold start is associated with the first Browser View, start or connect the Bridge as early as possible and call attachWindow() immediately after creating the window.

Integrating Preload with Windows

Every window that needs to be monitored must load the Guance Preload and register as a trusted window via attachWindow(). Maintain the following Electron security configurations:

  • contextIsolation: true;
  • nodeIntegration: false;
  • sandbox: true.

When the application has no existing Preload, use standalone.cjs directly:

const standalonePreloadPath = path.join(
  sdkDirectory,
  "electron",
  "preload",
  "standalone.cjs",
);

const window = new BrowserWindow({
  webPreferences: {
    preload: standalonePreloadPath,
    contextIsolation: true,
    nodeIntegration: false,
    sandbox: true,
  },
});

const detachWindow = rumBridge.attachWindow(window);
window.webContents.once("destroyed", detachWindow);

When the application already has a Preload, configure electron/preload/install.cjs as a build dependency for bundlers such as webpack, esbuild, etc., and call it once in the business Preload:

const { installElectronRumPreload } = require("guance-electron-preload");

installElectronRumPreload();

Here, guance-electron-preload is a build alias pointing to install.cjs, not an npm package. When sandbox: true is enabled, the final Preload output must be a bundle that can be directly loaded by webPreferences.preload.

Pages that do not need monitoring should not load the Guance Preload, nor call attachWindow(). For multi-window applications, each window must be registered independently, and the removal function returned by attachWindow() should be called when the window is destroyed.

Initializing the Renderer

Each Renderer that needs to be monitored must initialize the Browser SDK. Bridge mode does not require applicationId; datakitOrigin is only used to pass the Browser SDK initialization validation, and data will not be uploaded to that address.

import { datafluxRum } from "@cloudcare/browser-rum";
import { datafluxLogs } from "@cloudcare/browser-logs";

datafluxLogs.init({
  datakitOrigin: "http://127.0.0.1",
  forwardErrorsToLogs: true,
  forwardConsoleLogs: ["error", "warn"],
});

datafluxRum.init({
  datakitOrigin: "http://127.0.0.1",
});

const capabilities = JSON.parse(
  window.FTWebViewJavascriptBridge.getCapabilities(),
);
if (capabilities.includes("records")) {
  datafluxRum.startSessionReplayRecording();
}

When the Browser SDK detects FTWebViewJavascriptBridge, it switches to Bridge transport and does not start Browser HTTP Batch. It is recommended to control log sampling uniformly via the Native loggingSampleRate to avoid setting a low Browser sessionSampleRate that causes double sampling.

Session Replay is an experimental feature and is disabled by default

Only when both the Native SDK and Bridge configuration enable Replay does getCapabilities() return records. The Renderer must decide whether to start recording based on this capability and cannot force-enable it on its own. In Mixed Mode, the Native Replay configuration, Bridge Server configuration, and recording lifecycle must also be consistent.

Packaging Resources

When using electron-builder, Full Mode requires adding the entire SDK tool directory to the application resources:

{
  "build": {
    "extraResources": [
      {
        "from": "vcpkg_installed/x64-windows/tools/guance-windows-native",
        "to": "guance-windows-native"
      }
    ]
  }
}

Full Mode must deliver the Bridge EXE, Native DLL, and electron/ directory of the same SDK version. Mixed Mode only needs to copy tools/guance-windows-native/electron/; the Native DLL is still delivered by the C++ host's existing deployment process. Do not rely on the current working directory or the absolute path of the development machine to locate resources.

Integration Boundaries

  • The Main Process only uses the public interface of electron/main/index.cjs and does not register SDK internal IPC Channels on its own;
  • Do not expose application ID, Client Token, DataKit/Dataway address, native Session, or full Native configuration to the Renderer;
  • The Main Process only registers trusted webContents. For remote pages, you also need to restrict navigation, pop-ups, permissions, and allowed domains;
  • Tracing is still independently configured via the Windows SDK Trace API; the Electron Adapter does not inject Trace configuration into the Renderer;
  • Renderer JavaScript Errors and Long Tasks are collected by Browser RUM; unresponsive, render-process-gone, and Main Process Crash are not automatically reported by the Bridge. If needed, you should separately integrate Electron crashReporter or other Crashpad services.

Verifying the Integration

  1. In the Renderer DevTools Network, confirm there are no direct RUM or Log upload requests;
  2. Trigger View, Action, Resource, Error, Long Task, and one Browser Log, and confirm the data reaches Guance;
  3. Confirm that the data uses the application ID, Session ID, and sdk_name=df_windows_rum_sdk from the Native configuration;
  4. Confirm that the warn status of the Browser Log appears as warning in the Native Log, and custom attributes are preserved;
  5. When Replay is disabled, confirm getCapabilities() does not include records; when enabled, confirm recording data is reported normally;
  6. After closing the Electron page in Mixed Mode, confirm the C++ SDK is still running; after exiting the application in Full Mode, confirm the Bridge EXE shuts down properly.

You can refer to the Electron vcpkg Consumer Acceptance and Electron Sample in the Windows SDK repository for acceptance testing.