Skip to content

[RUM-14998] IPC Renderer process support#38

Merged
cdn34dd merged 5 commits into
mainfrom
carlosnogueira/RUM-14998/ipc-renderer-support
Mar 26, 2026
Merged

[RUM-14998] IPC Renderer process support#38
cdn34dd merged 5 commits into
mainfrom
carlosnogueira/RUM-14998/ipc-renderer-support

Conversation

@cdn34dd

@cdn34dd cdn34dd commented Mar 11, 2026

Copy link
Copy Markdown
Collaborator

Motivation

Adds support for capturing RUM events from renderer processes by bridging the browser SDK to the main process event pipeline.

Changes

  • Added a preload script (src/preload/bridge.ts) that exposes a DatadogEventBridge to renderer processes, allowing the browser RUM SDK (@datadog/browser-rum) to send events through IPC instead of posting directly to the intake
  • Added BridgeHandler in the main process to receive renderer events via IPC and route them through the existing EventManager pipeline
  • The preload script is bundled as dist/preload-auto.cjs and automatically registered via session.registerPreloadScript() during init()
  • Updated the playground app to integrate @datadog/browser-rum in the renderer, with UI controls for fetch demos and error generation

Checklist

  • Tested locally (playground)
  • Added unit tests for this change.
  • Added e2e/integration tests for this change.
  • Updated related documentation.

@datadog-prod-us1-6

This comment has been minimized.

@cdn34dd cdn34dd force-pushed the carlosnogueira/RUM-14998/ipc-renderer-support branch 2 times, most recently from ad16b19 to b0594e7 Compare March 16, 2026 11:07
@cdn34dd cdn34dd marked this pull request as ready for review March 16, 2026 11:11
@cdn34dd cdn34dd requested a review from a team as a code owner March 16, 2026 11:11

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b0594e75f3

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/index.ts Outdated
Comment thread src/index.ts Outdated
Comment thread src/ipc/BridgeHandler.ts Outdated
Comment thread src/ipc/BridgeHandler.ts Outdated
Comment thread src/ipc/BridgeHandler.ts Outdated
Comment thread src/ipc/BridgeHandler.ts Outdated
Comment thread src/ipc/BridgeHandler.ts Outdated
Comment thread src/ipc/BridgeHandler.ts Outdated
Comment thread src/preload/bridge.ts
Comment thread playground/src/renderer.ts Outdated
Comment thread src/preload/bridge.ts Outdated
@cdn34dd cdn34dd force-pushed the carlosnogueira/RUM-14998/ipc-renderer-support branch 3 times, most recently from 059773f to 267768a Compare March 25, 2026 13:07
@cdn34dd cdn34dd requested a review from bcaudan March 25, 2026 13:11
Comment thread README.md Outdated

### Renderer Process Support

The SDK automatically registers a preload script that exposes a `DatadogEventBridge` to every renderer process. When `@datadog/browser-rum` is initialized in a renderer, it detects the bridge and routes events through IPC to the main process instead of posting directly to the intake.

@bcaudan bcaudan Mar 25, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💬 suggestion: adding a note on the need to have browser SDK‏

Suggested change
The SDK automatically registers a preload script that exposes a `DatadogEventBridge` to every renderer process. When `@datadog/browser-rum` is initialized in a renderer, it detects the bridge and routes events through IPC to the main process instead of posting directly to the intake.
In order to monitor the renderer process, the [Browser SDK](https://docs.datadoghq.com/real_user_monitoring/application_monitoring/browser/setup/) must be setup in pages loaded by the renderer.
The Electron SDK automatically registers a preload script that exposes a `DatadogEventBridge` to every renderer process. When present, the Browser SDK detects the bridge and routes events through IPC to the Electron SDK instead of sending them directly to Datadog servers.

Comment thread README.md Outdated

Both `contextIsolation: true` (default) and `contextIsolation: false` are supported.

> **Note:** Only the automatic preload mode is currently supported. Manual bridge setup is not yet available.

@bcaudan bcaudan Mar 25, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🥜 nitpick: ‏Unless there is a specific reason to mention it, let's not mention manual bridge setup

Comment thread README.md Outdated

The SDK automatically registers a preload script that exposes a `DatadogEventBridge` to every renderer process. When `@datadog/browser-rum` is initialized in a renderer, it detects the bridge and routes events through IPC to the main process instead of posting directly to the intake.

Both `contextIsolation: true` (default) and `contextIsolation: false` are supported.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❓ question: Does it really works with contextIsolation: false?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it does, I tested on the playground app to make sure.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, let's add a test for it then and maybe remove this mention.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright

Comment thread src/index.ts Outdated
Comment on lines +38 to +41
new BridgeHandler(eventManager, {
defaultPrivacyLevel: config.defaultPrivacyLevel,
allowedWebViewHosts: config.allowedWebViewHosts,
});

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🥜 nitpick: ‏we could use config directly as a dependency, it would avoid the noise here and the need to update this file if BridgeHandler need an extra config parameter

Comment thread src/index.ts Outdated
Comment on lines +43 to +48
const currentDir = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));
const preloadPath = path.join(currentDir, 'preload-auto.cjs');
session.defaultSession.registerPreloadScript({
type: 'frame',
filePath: preloadPath,
});

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💬 suggestion: ‏what about extracting that to a different file?
It would keep the init function at a higher level of abstraction.

Comment thread e2e/lib/appPage.ts Outdated
Comment on lines +53 to +60
if (startTime !== undefined) {
await this.page.evaluate(
(ts) => (globalThis as unknown as ElectronAppWindow).electronAPI.generateManualError(ts),
startTime
);
} else {
await this.page.locator('#generate-manual-error').click();
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❓ question: ‏What is the need there?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main reason is test, the 'click' option is what most e2e test use, the startTime override is required for test that assert timing.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it related to this PR though?
FMU, it was working by calling directly the electronAPI all the time and the button was not really needed, so not sure why introducing the button.

Comment thread e2e/lib/appPage.ts Outdated
Comment on lines +76 to +82
async openFileWindow() {
await this.page.evaluate(() => (globalThis as unknown as ElectronAppWindow).electronAPI.openFileWindow());
}

async openHttpWindow() {
await this.page.evaluate(() => (globalThis as unknown as ElectronAppWindow).electronAPI.openHttpWindow());
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💬 suggestion: ‏It could be less confusing to have all this setup mentioning renderer test, something like:

Suggested change
async openFileWindow() {
await this.page.evaluate(() => (globalThis as unknown as ElectronAppWindow).electronAPI.openFileWindow());
}
async openHttpWindow() {
await this.page.evaluate(() => (globalThis as unknown as ElectronAppWindow).electronAPI.openHttpWindow());
}
async openRendererTestWindowOverFile() {
await this.page.evaluate(() => (globalThis as unknown as ElectronAppWindow).electronAPI.openRendererTestWindowOverFile());
}
async openRendererTestWindowOverHttp() {
await this.page.evaluate(() => (globalThis as unknown as ElectronAppWindow).electronAPI.openRendererTestWindowOverHttp());
}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What exactly is confusing about them, I think the suggested names aren't any better.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When discovering how things are working for the e2e tests, it is not obvious why we have different browser windows and which files / APIs are related to those.
Having something in the name that mention renderer would make that clearer IMO.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I'll change to have renderer in the name, but to something a little less verbose.

Comment on lines +61 to +66
this.eventManager.notify({
kind: EventKind.RAW,
source: EventSource.RENDERER,
format: EventFormat.RUM,
data: bridgeEvent.event,
} as RawRumEvent);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❗ warning: we should exclude those events from the main view counters

Image

Comment thread src/assembly/Assembly.ts Outdated
Comment on lines +66 to +75
const { session, application } = (hookResult ?? {}) as MainProcessAttributes;

return {
kind: EventKind.SERVER,
track: EventTrack.RUM,
data: combine(event.data, {
session: { id: session?.id },
application: { id: application?.id },
}) as RumEvent,
};

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💬 suggestion: ‏I was a bit confused by the MainProcessAttributes type with the optional properties.
What about removing the type and make things clearer in the implementation:

Suggested change
const { session, application } = (hookResult ?? {}) as MainProcessAttributes;
return {
kind: EventKind.SERVER,
track: EventTrack.RUM,
data: combine(event.data, {
session: { id: session?.id },
application: { id: application?.id },
}) as RumEvent,
};
const { session, application } = hookResult ?? {};
const mainProcessAttributes = {
session: { id: session?.id },
application: { id: application?.id },
};
return {
kind: EventKind.SERVER,
track: EventTrack.RUM,
// override some renderer event attributes by main process attributes
data: combine(event.data, mainProcessAttributes) as RumEvent,
};

Comment thread e2e/scenarios/renderer-bridge.scenario.ts
@cdn34dd cdn34dd force-pushed the carlosnogueira/RUM-14998/ipc-renderer-support branch from 267768a to 8dccb25 Compare March 26, 2026 09:33
@cdn34dd cdn34dd force-pushed the carlosnogueira/RUM-14998/ipc-renderer-support branch from 8dccb25 to ae817d6 Compare March 26, 2026 09:39
@cdn34dd cdn34dd requested a review from bcaudan March 26, 2026 12:39

@bcaudan bcaudan left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

@cdn34dd cdn34dd merged commit 653ba08 into main Mar 26, 2026
12 checks passed
@cdn34dd cdn34dd deleted the carlosnogueira/RUM-14998/ipc-renderer-support branch March 26, 2026 13:02
@bcaudan bcaudan mentioned this pull request Mar 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants