Skip to content

macOS Electron Monitoring

This page covers the macOS native host, runtime, Replay, and packaging and signing notes. For first-time integration, choose an approach from Electron App Integration. If the app is primarily Electron, first complete the managed Quick Start.

The macOS SDK integrates with Electron through the Guance Electron Native Adapter. Browser RUM and Browser Logs in the Renderer are responsible for collecting page views, user actions, requests, errors, Long Tasks, and page logs. The Electron Main Process passes the data to the macOS Native SDK, which centrally manages the native RUM app, sessions, sampling, and upload. When Session Replay is needed, configure the Native SDK and page recording together as described below.

Choose one mode based on your app structure. A single Electron process can use only one mode:

Integration Mode Use Cases SDK Owner
Full Mode (managed) The app is primarily Electron The Electron Main Process initializes and shuts down the Native SDK through Node Addon
Mixed Mode (external) The native macOS app has already integrated the Native SDK and launches Electron The native macOS host app; Electron only connects to the existing SDK

Both modes share the same Preload, window registration, and Renderer initialization. The Renderer does not configure the real RUM Application ID, upload URL, or Client Token. After choosing a mode, configure Preload and initialize the page SDK. If you only need to monitor Electron pages as standalone web applications, see Electron Integration for Web RUM.

The data flow is as follows:

Full Mode (managed)
Electron Renderer
  Browser SDK -> Secure Preload -> Electron Main Process
                                      |
                                      v
                      Node Addon (contains Native SDK)
                                      |
                                      v
                                     Upload

Mixed Mode (external)
Electron Renderer
  Browser SDK -> Secure Preload -> Electron Main Process
                                      |
                                      | Authenticated Unix Domain Socket
                                      v
                         macOS Native host app
                         Native SDK -> Upload

Electron Integration

Install Dependencies

Electron Native Adapter version

  • Installing the Adapter and the Native runtime requires Node.js 18 or later, and access to the npm Registry and the Native SDK's GitHub Releases. For offline environments, prepare the npm packages, dependencies, and Native runtime archive in advance.
  • Full Mode uses the precompiled Universal runtime, so the Native SDK is not compiled during installation. You do not need to install Git, Swift, or Xcode Command Line Tools for this. App packaging, signing, and notarization still require the corresponding macOS toolchain.
  • Mixed Mode requires the Native SDK to be integrated in the native macOS host app first. The configureElectronProcess integration described below is available starting with Native SDK 1.6.8-alpha.7. See Native Host Integration.

Guance Electron Native Adapter supports Electron 22.x (no lower than 22.3.27) and 43.x.

For Full Mode, install the dependencies and integrate Main, Preload, and Renderer according to the Common Quick Start. Installation automatically downloads the matching macOS runtime; no local compilation is required.

When using only Mixed Mode, the native host app provides the Native SDK. Skip the unnecessary runtime download when installing the Adapter:

GUANCE_NATIVE_SKIP_DOWNLOAD=1 npm install @cloudcare/electron-native-adapter@alpha

For page dependencies and initialization, see Common Renderer Integration. For optional log collection, first complete Native Logger Configuration below.

Specifying or Installing the Full Mode Native Runtime Offline

When using the runtime automatically installed by npm, you do not need to set native.directory during development. The Adapter finds the runtime in its own installation directory. The npm package and the Native SDK have independent version numbers. The matching Native SDK version is pinned by the npm package, and the two version numbers are not required to match.

To specify a different Native SDK version, run the following command from the root directory of the Electron app project and replace <SDK_VERSION> with the Native SDK Release tag that contains the Electron runtime assets:

npx guance-electron-native --sdk-version '<SDK_VERSION>'

This command downloads the precompiled Universal runtime, which includes both arm64 and x86_64. No single-architecture source build option is provided. The installer verifies the archive, SDK version, architecture, and file hashes.

For offline installation, prepare guance-electron-runtime-<SDK_VERSION>-darwin-universal.tar.gz and its .sha256 file from the same Release, and place both in the same directory:

npx guance-electron-native --sdk-version '<SDK_VERSION>' \
  --runtime-archive '/absolute/path/guance-electron-runtime-<SDK_VERSION>-darwin-universal.tar.gz'

Before running the offline command, the Adapter and its npm dependencies must already be installed; otherwise npx itself may still access npm. You can also pass a local runtime archive during npm installation:

GUANCE_NATIVE_RUNTIME_ARCHIVE='/absolute/path/runtime.tar.gz' \
  npm install @cloudcare/electron-native-adapter@alpha

A local archive takes precedence over network downloads, and its version must match the Native SDK version selected for this installation. During npm installation, you can override the bundled version with GUANCE_NATIVE_SDK_VERSION. For explicit CLI installation, use --sdk-version. After changing the version, run the app to confirm that data is reported correctly.

The runtime installed by npm is located at node_modules/@cloudcare/electron-native-adapter/.cloudcare/native/darwin/runtime. Explicit CLI installation outputs to .cloudcare/native/darwin/runtime in the app project. In that case, set native.directory to the absolute path of that directory. It is recommended to add .cloudcare/ under the project to Git ignore rules.

When packaging, copy the complete runtime directory into the app resource directory. See Packaging Resources for configuration.

Initialize the Native Bridge

Full Mode

In macOS managed mode, the Electron Main Process initializes the Native SDK through Node Addon. See the managed Quick Start for a complete example, and Main Configuration for fields and sampling units.

The app version actually reported on macOS is determined by the app packaging information. When calling the Native SDK's sampling API directly, use 0..100. Do not confuse this with the 0..1 unit used by old Adapter fields.

Mixed Mode

Mixed Mode uses native.mode: 'external'. You must first configure the SDK in the native macOS host app, and then have the native host app launch Electron. App information, upload URL, and collection options are all set in the native host app.

Native Host Integration

In the native host app project, add the Native SDK through Swift Package Manager and replace <SDK_VERSION> with the SDK version you are using:

.package(
    url: "https://github.com/GuanceCloud/datakit-ios.git",
    exact: "<SDK_VERSION>"
)

Add the following products to the macOS host app target:

  • GuanceSDK: the Native SDK;
  • GuanceElectronWebView: used to integrate Electron page data;
  • GuanceSessionReplay: add only when Session Replay is needed.

The native host app initializes the SDK and RUM first. If you have already integrated the SDK into your app, keep the existing initialization code and enable enableTraceWebView. Do not initialize again:

#import <GuanceSDK/GuanceSDK.h>
#import <GuanceElectronWebView/GuanceElectronWebView.h>

FTSDKConfig *sdkConfig =
    [[FTSDKConfig alloc] initWithDatakitUrl:@"http://127.0.0.1:9529"];
[FTSDKAgent startWithConfigOptions:sdkConfig];

FTRumConfig *rumConfig =
    [[FTRumConfig alloc] initWithAppid:@"<RUM Application ID>"];
rumConfig.enableTraceWebView = YES;
rumConfig.enableTraceUserView = YES;
[[FTSDKAgent sharedInstance] startRumWithConfigOptions:rumConfig];

If you need Session Replay, initialize it with the Native SDK's Session Replay API before launching the Electron child process. If page logs are needed, also complete Native Logger Configuration at this stage:

#import <GuanceSessionReplay/GuanceSessionReplay.h>

FTSessionReplayConfig *replayConfig = [[FTSessionReplayConfig alloc] init];
replayConfig.sampleRate = 100;
replayConfig.textAndInputPrivacy = FTTextAndInputPrivacyLevelMaskSensitiveInputs;
[[FTRumSessionReplay sharedInstance]
    startWithSessionReplayConfig:replayConfig];
Configure and Launch the Electron Child Process

Create an FTElectronBridgeServer and an NSTask, and call configureElectronProcess:error: before launching the child process. This method automatically starts the Bridge and merges the connection parameters into the environment variables of the specified child process. You do not need to call startWithError: separately or set Bridge environment variables manually.

Declare strong reference properties in AppDelegate or in the object responsible for the child process lifecycle:

@property (nonatomic, strong) FTElectronBridgeServer *electronBridgeServer;
@property (nonatomic, strong) NSTask *electronProcess;

After completing the Native SDK configuration above, run the following launch code:

self.electronBridgeServer = [[FTElectronBridgeServer alloc] init];
self.electronProcess = [[NSTask alloc] init];
self.electronProcess.executableURL =
    [NSURL fileURLWithPath:@"<absolute path to the Electron executable>"];
// Set launch arguments according to the app structure, for example the Electron project path in development mode.
// self.electronProcess.arguments = @[@"<absolute path to the Electron project>"];

NSError *error = nil;
if (![self.electronBridgeServer
        configureElectronProcess:self.electronProcess error:&error]) {
    [self.electronBridgeServer stop];
    // Handle the error in the app; do not continue launching a child process that was not configured successfully.
    return;
}

// configureElectronProcess only configures the process; it does not launch Electron automatically.
if (![self.electronProcess launchAndReturnError:&error]) {
    [self.electronBridgeServer stop];
    // Handle the launch failure in the app.
    return;
}

The equivalent Swift call is try bridgeServer.configureElectronProcess(process), followed by try process.run().

If you need to pass business environment variables, set electronProcess.environment before calling configureElectronProcess. The SDK preserves existing non-Bridge variables. If it is not set, the process inherits NSProcessInfo.processInfo.environment. This method only modifies the launch environment of the specified child process, not the native host app's environment. You can call it repeatedly before launching, but it replaces existing Bridge variables with the current Bridge values.

The following connection parameters are generated or provided by the Native Bridge. The Adapter reads them from process.env in the Electron Main Process by default. You do not need to assign them manually or write them to .env.local, and you should not expose these parameters to the Renderer:

Environment Variable Purpose
GUANCE_ELECTRON_SOCKET_PATH Local Unix Domain Socket path of the current Bridge
GUANCE_ELECTRON_AUTH_TOKEN IPC authentication Token generated by the current Bridge; not a DataWay upload Token
GUANCE_ELECTRON_PROTOCOL_VERSION IPC protocol version supported by the Native Bridge, used to check protocol compatibility with the Adapter; not an SDK or npm version number

When using an older SDK or a custom launcher that does not support configureElectronProcess, you can still call startWithError: first, and then pass the return value of environmentByAddingToEnvironment: as the Electron launch environment. Starting the Bridge alone does not automatically modify another process's environment variables.

Configure the Electron Main Process

Before Electron creates or navigates its first window, use bootstrap() to connect to the native host app. You do not need to pass native.settings or read the connection parameters manually:

const electron = require('electron')
const { app, BrowserWindow } = electron
const {
  bootstrap,
} = require('@cloudcare/electron-native-adapter')

let client

app.whenReady().then(async () => {
  client = await bootstrap({
    electron,
    native: {
      mode: 'external',
    },
    autoAttach: true,
  })

  const window = new BrowserWindow({ /* Configure the secure Preload */ })
  await window.loadURL('https://example.com')
})

App Exit

On normal exit, wait for client.stop(). See Common Lifecycle for details. In Mixed Mode, this only disconnects Electron. The native host app is still responsible for stopping the Bridge and the Native SDK.

Integrate Preload and Windows

Load the bridge according to the Common Preload Configuration, use secure window options, and package the application Preload correctly.

Specify Collection Windows

Choose autoAttach or manual registration according to Common Window Management. Integrate each window to be collected before its page is loaded.

Initialize the Renderer

Both modes share the Renderer initialization in the Quick Start. Keep the placeholder parameters. The actual app, upload URL, and credentials are configured by the Main Process or the native host.

Collect User Actions

To collect user actions such as page clicks, set trackUserInteractions: true according to the Renderer initialization example in this section. In Mixed Mode, automatic action collection for native controls is enabled through the native host app's RUM Configuration.

Collect Page Logs

To collect page logs, first enable log collection according to the integration mode:

  • Full Mode: Set loggingEnabled: true in native.settings in the Electron Main Process, and set the sampling rate with loggingSampleRate.
  • Mixed Mode: Initialize Logger in the native macOS host app and enable enableWebViewLog.

In Mixed Mode, configure Logger before the native host app launches Electron. If you already have Logger initialization code, merge the following options into the existing configuration:

FTLoggerConfig *loggerConfig = [[FTLoggerConfig alloc] init];
loggerConfig.enableWebViewLog = YES;
loggerConfig.enableLinkRumData = YES;
loggerConfig.sampleRate = 100;
[[FTSDKAgent sharedInstance] startLoggerWithConfigOptions:loggerConfig];

The Main Process can use client.capabilities.log to confirm whether the native side supports receiving page logs. Initialize Browser Logs only on pages where this capability is enabled. If you pass this state to pages through the application Preload, expose only the required boolean and do not pass the complete native configuration.

enableWebViewLog is used to receive page logs. If you need to associate logs with native RUM sessions, also set enableLinkRumData: YES and enable enableTraceWebView for RUM as shown in the Mixed Mode example.

After completing the native configuration, initialize Browser Logs according to the Common Page Logs Configuration to avoid double sampling.

Enable Session Replay

First enable replay collection according to the integration mode:

  • Full Mode: Set replayEnabled: true in native.settings, and set replaySampleRate and replayPrivacy as needed.
  • Mixed Mode: Configure the Session Replay sampling rate and privacy protection method in the native host app according to the Mixed Mode example.

Replay is disabled by default. After completing the native configuration, start recording only when the Bridge returns records, according to Common Replay Capability Detection. This capability does not guarantee that the current session will be selected by sampling.

After integration, you can view page views, user actions, and the corresponding replay in Guance. In Mixed Mode, you can view the visit data of the native app and Electron pages in the same session; the replays for the native UI and Electron pages are displayed separately.

In Mixed Mode, page snapshots are managed by the Browser SDK, and the Native Bridge does not trigger full page snapshots in reverse. Do not use client.updateWindow(..., { visible: false }) as a way to pause recording in Mixed Mode. Full Mode still retains the snapshot synchronization mechanism between the native side and pages.

Packaging Resources

Full Mode

In managed mode, you must install the Native runtime first and then copy the complete directory outside the ASAR. The macOS Universal artifact includes both arm64 and x86_64. When using the runtime installed by npm, use the following extraResources configuration with electron-builder to copy the runtime, and add the .node file to the macOS binary signing configuration:

{
  "extraResources": [
    {
      "from": "node_modules/@cloudcare/electron-native-adapter/.cloudcare/native/darwin/runtime",
      "to": "native"
    }
  ],
  "mac": {
    "binaries": [
      "Contents/Resources/native/guance_electron.node"
    ]
  }
}

If you used explicit CLI installation, change the from above to .cloudcare/native/darwin/runtime in the app project. Do not copy only the .node file. The resource bundle in the runtime directory must also be delivered. After packaging, the Adapter uses the native directory under process.resourcesPath by default. If native.directory is explicitly configured, point it to that directory after packaging as well; do not continue using a development machine path.

Follow the app's existing macOS signing and notarization workflow and sign guance_electron.node together with the app. Before release, run the packaged app and verify that the SDK loads and reports data normally.

Mixed Mode

In Mixed Mode, package and sign the Native SDK, GuanceElectronWebView, and the Session Replay component as needed according to the native host app's existing workflow. Electron can be packaged in the usual way.

Integration Boundaries

  • Page RUM events and logs are forwarded to the Native SDK through Preload and the Main Process. Do not register or forward SDK-internal IPC channels yourself.
  • The Adapter only accepts main-frame events from registered windows. Child frames are not treated as independent trusted entries.
  • traceEnabled configures Native SDK tracing. It does not automatically configure tracing for the Renderer's fetch/XHR. If page requests need trace correlation, additionally set allowedTracingUrls and the backend-matching traceType in Browser RUM. See the Electron example in the repository.
  • The current macOS Adapter does not provide the automatic launch_cold and launch_hot Action reporting available in the Windows integration. Do not rely on enableAppLaunch to generate these events on macOS.
  • Renderer JavaScript errors and Long Tasks are collected by Browser RUM. Electron's unresponsive and render-process-gone events are not automatically converted into RUM errors by the Bridge. Crash monitoring in the native host app cannot replace crash collection for Electron child processes; you must integrate it separately according to your app's needs.
  • Restrict navigation, popups, permissions, and allowed domains for remote pages. The upload URL and credentials are configured in the Electron Main Process or the native host app, and must not be written into page code.

Verifying the Integration

  1. Launch the app and confirm there are no SDK initialization errors in the Main Process or the page console. In the Renderer DevTools Network tab, confirm that there are no direct RUM or Log upload requests.
  2. Visit a page, click controls, send a request, and trigger an error and a Long Task. Confirm in Guance that the corresponding data is visible and that the app ID uses the Native configuration. After enabling page logs, send a log to verify.
  3. With replay disabled, confirm that getCapabilities() does not include records. After enabling replay and being selected by sampling, view the recording and confirm that text and input content match the selected privacy settings.
  4. Create a second window and confirm it is collected. When using specified-window collection, confirm that windows that are not integrated produce no data.
  5. In Mixed Mode, view the visit records of the native app and Electron pages in the same session.
  6. Exit the Full Mode app and confirm that client.stop() completes. Exit the Mixed Mode Electron child process and confirm that the native SDK continues collecting and uploading. Run the packaged app and verify data and replay again.

For complete examples, see Electron Full Mode Example and Native Host Mixed Mode Example in the macOS SDK repository.

FAQ

Symptom Troubleshooting
Native runtime download fails during npm installation Check whether the SDK Release contains the runtime for the specified version and its .sha256 file, and whether the network is reachable. In offline environments, use a local archive. Set GUANCE_NATIVE_SKIP_DOWNLOAD=1 only for Mixed Mode
Error that the Native runtime file is missing or cannot be loaded Check native.directory, the target architecture, and whether the runtime directory is complete. After packaging, also check the file location and signature
No monitoring data on the page Check whether Preload is working, whether the window is integrated, and whether Browser RUM is initialized after the Adapter is ready
No replay on the page Check whether replay is enabled on the native side, whether getCapabilities() includes records, whether the sampling rate is hit, and whether the page calls startSessionReplayRecording()
Mixed Mode connection fails Check whether configureElectronProcess was successfully called before launching the corresponding NSTask, whether its environment variables were overwritten afterward, and whether the Bridge is held strongly
IPC protocol not supported Check whether the Adapter and the Native SDK support the same IPC protocol. Do not bypass the check by manually modifying GUANCE_ELECTRON_PROTOCOL_VERSION

Feedback

Is this page helpful?