Skip to content

Electron Monitoring

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

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

Mode Use Cases Native Runtime Source SDK Owner
Mixed Mode (external) Electron pages embedded in a C++ desktop application Provided by the host, e.g., the vcpkg base package C++ host
Full Mode (managed) The application itself is Electron Downloaded during npm install; an explicit directory is also supported Bridge EXE managed by the Adapter

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

This approach differs from Web RUM's standalone Electron access. In the Windows SDK integration, the Renderer does not upload data directly, nor does it configure a real application ID, reporting endpoint, or Client Token.

The data flow is as follows:

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

Integrate Electron

Install Dependencies

Install the Native Adapter and Browser SDK in the Electron project:

npm install @cloudcare/electron-native-adapter @cloudcare/browser-rum @cloudcare/browser-logs

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

Browser Logs Bridge integration requires 3.3.6 or later.

The verified Electron baselines are 22.3.27 and 43.x; the declared compatibility range is ^22.3.27 || 43.x, and intermediate major versions have not been verified. Electron 22 is the legacy compatibility baseline for Windows 7 SP1, while Electron 43 requires Windows 10 or later; the combination of the target operating system and Native Runtime still needs to be verified.

npm installation and the runtime installer require Node.js 18+; users of the packaged app do not need to install Node.js separately. Windows supports x64, x86 (ia32 in Electron/Node.js), and arm64. Install the Microsoft Visual C++ v14 Redistributable and Windows Universal CRT matching the runtime architecture.

The published npm package does not bundle the Native binaries itself, but postinstall downloads and verifies the Native Runtime by platform and architecture, with no local compilation required. Full Mode automatically locates this runtime by default, so installing vcpkg first is not required. The Adapter also supports macOS; this page covers the Windows Native Bridge integration.

Important Version Notes

Adapter 0.1.0-alpha.3 adds Windows x86/arm64 runtime selection, verification, and packaging support, and pins the default Native Runtime to Windows SDK vcpkg_0.1.0-alpha.8 and macOS SDK 1.6.8-alpha.6. These are the default dependencies for this version and do not imply that later versions will always use the same Native SDK.

Adapter, the Windows SDK, and the macOS SDK are versioned independently. The actual defaults are governed by the package.json.nativeRuntime of the installed npm package.

When using only Mixed Mode, you can set the PowerShell environment variable $env:GUANCE_NATIVE_SKIP_DOWNLOAD = "1" before installation to skip downloading the unused runtime; clear this variable before switching back to a Full Mode installation.

Optional: Provide the Native Runtime via vcpkg

If the host owns the Native SDK, or you need to build the runtime yourself, configure the SDK vcpkg registry as described in Quick Start. The JavaScript Adapter is still installed separately via npm. When providing the runtime manually in Full Mode, enable electron-bridge:

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

Mixed Mode installs only the base Native package without enabling the Electron feature:

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

Run the following in the directory containing vcpkg.json:

vcpkg install --triplet x64-windows

Use only the following public entry points when integrating:

  • @cloudcare/electron-native-adapter: the unified bootstrap() entry point for the Main Process;
  • @cloudcare/electron-native-adapter/preload/standalone: use directly when the app has no existing Preload;
  • @cloudcare/electron-native-adapter/preload/install: when the app already has a Preload, merge it into the business Preload using a bundler.

Do not copy the Adapter source code, and do not reference internal files in the npm package that are not declared via exports.

The vcpkg commands above use x64 as an example. If you use the vcpkg tools directory manually, pass the sdkDirectory below to native.directory; the default npm download flow does not require this setting:

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",
    );

Adjust the relative path depth of the development directory to match your application structure. Do not rely on the current working directory or hardcode the absolute path of the development machine.

Initialize 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 app 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 named pipe with the same name:

const electron = require("electron");
const { bootstrap } = require("@cloudcare/electron-native-adapter");

const rumBridge = await bootstrap({
  electron,
  native: {
    mode: "external",
    pipeName: "my-app-rum",
  },
  enableAppLaunch: true,
});

In Mixed Mode:

  • Do not start guance_windows_electron_bridge.exe, otherwise a second SDK Handle is created;
  • Electron no longer passes the application ID, DataKit/Dataway, cache, or upload configuration;
  • The C++ host must ensure the SDK Handle outlives the Bridge Server;
  • When collecting Browser Logs, Native custom logging must also be enabled, with logging_enabled set to 1.

Full Mode

When the application itself is Electron, the Main Process starts and manages the Bridge EXE. Run the following initialization after app.whenReady() resolves and before loading Renderer pages:

const electron = require("electron");
const path = require("node:path");
const { bootstrap } = require("@cloudcare/electron-native-adapter");

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

When reporting through DataWay, replace datakitUrl with datawayUrl and clientToken. applicationId, service, environment, and version are required, and a DataKit or DataWay address must be provided.

The sampling rates for Native RUM, Log, Replay, and Trace all range from 0 to 1 and default to 1. loggingEnabled, replayEnabled, traceEnabled, and debug are disabled by default; the example explicitly enables logging. replayPrivacy supports allow, mask-user-input, and mask, defaulting to mask.

Other optional configuration:

Location Parameter Description
native.settings traceEnabled, traceSampleRate Configures the Native Trace switch and sampling rate
native.settings traceType Defaults to w3c_traceparent
native.settings traceAllowedUrls Native Trace URL rule string
native.settings httpTimeoutMs Upload timeout, defaults to 10000 ms, range 1..300000
native (managed) readyTimeoutMs, stopTimeoutMs Startup handshake and exit wait time, defaults to 10000 and 3000 ms
native (managed) onNativeOutput Receives (stream, text) for diagnosing Bridge stdout and stderr
native (external) timeoutMs, retryDelayMs Connection timeout and retry interval, defaults to 10000 and 100 ms
bootstrap() onError Receives asynchronous transport and window handling errors

The app must wait for rumBridge.stop() to complete before exiting, for example:

let stopping = false;
electron.app.on("before-quit", (event) => {
  event.preventDefault();
  if (stopping) return;
  stopping = true;
  rumBridge.stop().then(() => electron.app.exit(0), (error) => {
    console.error(error);
    electron.app.exit(1);
  });
});

bootstrap() returns a unified Client that provides capabilities, attachWindow(), detachWindow(), updateWindow(), transportState, and an idempotent stop(). transportState is used to check writability, backpressure, and transport failures. startFullMode() and connectMixedMode() are retained only as compatibility entry points for earlier versions; all new integrations should use bootstrap().

The Adapter enables enableAppLaunch by default, automatically generating launch_cold and launch_hot Actions based on the Electron app lifecycle, the first frame of trusted windows, and the Browser View context; set it to false when automatic launch Actions are not needed. To ensure a cold launch is associated with the first Browser View, start or connect the Bridge as early as possible, and call attachWindow() immediately after creating the window.

Integrate the Preload and Windows

Every window to be collected must load the Guance Preload and be registered as a trusted window via attachWindow(). Keep the following Electron security settings:

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

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

const standalonePreloadPath = require.resolve(
  "@cloudcare/electron-native-adapter/preload/standalone",
);

const { BrowserWindow } = require("electron");
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 app already has a Preload, include @cloudcare/electron-native-adapter/preload/install as a build dependency for bundlers such as webpack and esbuild, and call it once in the business Preload:

const {
  installElectronRumPreload,
} = require("@cloudcare/electron-native-adapter/preload/install");

installElectronRumPreload();

When sandbox: true is enabled, the final Preload output must be a self-contained bundle that can be loaded directly by webPreferences.preload. For example, you can use esbuild and keep Electron as an external runtime dependency:

esbuild src/preload.cjs --bundle --platform=node --format=cjs --external:electron --outfile=dist/preload.cjs

Pages that do not need collection should not load the Guance Preload or call attachWindow(). For multi-window applications, register each window independently before loading its page; the Adapter automatically removes the registration when the window is destroyed, and the returned removal function can also be used to stop collection early.

If all windows are trusted, set autoAttach: true in bootstrap() to automatically register existing and new windows; the default is false. Automatic registration cannot replace Preload installation.

Initialize the Renderer

Every Renderer to be monitored must initialize the Browser SDK. Bridge mode does not require applicationId; datakitOrigin is used only to pass the Browser SDK initialization validation, and data is not 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();
}

Once the Browser SDK detects FTWebViewJavascriptBridge, it switches to Bridge transport and does not start Browser HTTP Batch. We recommend controlling log sampling uniformly through the Native loggingSampleRate to avoid double sampling caused by also setting a lower Browser sessionSampleRate.

Session Replay is an experimental capability disabled by default

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

Package Assets

In Full Mode, call the public packaging helper before signing the app to copy the complete runtime outside the ASAR:

const { stageWindowsRuntime } = require(
  "@cloudcare/electron-native-adapter/packaging/windows",
);

stageWindowsRuntime({
  resourcesDirectory: "release/MyApp-win32-x64/resources",
  arch: "x64",
});

By default, the helper locates the runtime installed in the npm package and copies it to resources/native; the target directory must be empty. Packaged managed mode automatically locates this directory, so native.directory does not need to be set. Assets such as the Native EXE, DLLs, and the manifest must be kept intact and must not be placed inside app.asar.

When packaging cross-architecture, install the target runtime first, then explicitly pass the target arch. Windows supports x64, x86 / ia32, and arm64. Runtimes installed via the CLI must be specified through the helper's nativeDirectory.

If you are manually using the vcpkg tools directory, you can also continue copying through electron-builder's extraResources, specifying the resource location with the previously mentioned sdkDirectory:

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

Full Mode must ship the guance_windows_electron_bridge.exe and the adjacent guance_windows_native.dll of the same SDK version, and the app packaging tool must also carry @cloudcare/electron-native-adapter. Mixed Mode does not need to copy the vcpkg tools directory; the Native DLL is still delivered through the C++ host's existing deployment flow, and the JavaScript Adapter is still provided by the npm dependency. Do not rely on the current working directory or development machine absolute paths to locate assets.

Custom and Offline Runtime Installation

If npm installation was run with --ignore-scripts, or you need a different target architecture, run the following in the application root directory:

npx guance-electron-native --sdk-version <sdk-tag> --target <target>

Windows targets are win32-x64, win32-x86, and win32-arm64; macOS is darwin-universal. Use the full tag of the Native SDK Release for <sdk-tag>, keeping existing prefixes such as vcpkg_, nuget_, or v; the corresponding runtime assets must exist under the tag.

Offline installation requires the SDK .tar.gz and the adjacent .tar.gz.sha256 checksum file:

npx guance-electron-native --sdk-version <sdk-tag> --target <target> --runtime-archive C:/sdk/runtime.tar.gz

The CLI installs the runtime into the application root directory. During development, pass the output directory to native.directory; during packaging, pass it to the nativeDirectory of stageWindowsRuntime(). After packaging, remove the development directory configuration and use the automatically located resources/native.

npm postinstall supports the following environment variables (set in PowerShell with $env:VariableName = "value"):

Environment Variable Purpose
GUANCE_NATIVE_RUNTIME_ARCHIVE Use a local SDK archive and its adjacent checksum file instead of downloading
GUANCE_NATIVE_RUNTIME_TARGET Specify the target platform and architecture
GUANCE_NATIVE_SDK_VERSION Override the Native SDK tag pinned in the package
GUANCE_NATIVE_RUNTIME_ASSET_NAME Override the downloaded asset filename
GUANCE_NATIVE_RUNTIME_DOWNLOAD_BASE_URL Use an HTTPS mirror with the directory structure /<sdk-tag>/<filename>
GUANCE_NATIVE_SKIP_DOWNLOAD Set to 1 to skip runtime installation; for external mode

The archive must match the specified SDK version and architecture. Providing only an offline Native Runtime does not mean npm is fully offline; the npm packages and their dependency cache must also be prepared in advance. Private source checkouts skip the automatic download; when debugging locally with file: dependencies, prepare the runtime yourself.

Integration Boundaries

  • The Main Process uses only the public interfaces exported by @cloudcare/electron-native-adapter and must not register SDK-internal IPC Channels itself;
  • Do not expose the application ID, Client Token, DataKit/Dataway address, native Session, or the complete Native configuration to the Renderer;
  • The Main Process registers only trusted webContents. Remote pages also require restrictions on navigation, popups, permissions, and allowed domains;
  • Full Mode configures Native Trace through native.settings; in Mixed Mode, the host configures it. The Adapter does not inject Trace configuration into the Renderer, nor does it automatically add Trace Headers to page requests;
  • Renderer JavaScript Errors and Long Tasks are collected by Browser RUM; unresponsive, render-process-gone, and Main Process crashes are not automatically reported by the Bridge. If needed, integrate Electron's crashReporter or another Crashpad service separately.

Verify the Integration

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

For acceptance testing, refer to Electron Native Adapter Consumer Acceptance and Electron Sample in the Windows SDK repository. For local debugging, you can use npm file: dependencies; production apps should use release packages and manage the actually installed version through the app's lockfile.

Feedback

Is this page helpful?