Skip to content

Add getBrowserAgentLoader() API and hasToRemoveLoaderScript option to getBrowserTimingHeader()#4061

Open
Andreyco wants to merge 1 commit into
newrelic:mainfrom
Andreyco:feat/getBrowserAgentLoader
Open

Add getBrowserAgentLoader() API and hasToRemoveLoaderScript option to getBrowserTimingHeader()#4061
Andreyco wants to merge 1 commit into
newrelic:mainfrom
Andreyco:feat/getBrowserAgentLoader

Conversation

@Andreyco

Copy link
Copy Markdown

Background

The existing getBrowserTimingHeader() returns a single <script> block combining two conceptually distinct things:

  • the NREUM config blob — transaction-specific metadata that is unique per request and must not be cached.
  • the agent loader script — a static JS payload (js_agent_loader) that is identical across all requests for a given agent version and is safe to cache aggressively.

Bundling them together forces both to be delivered through the same path, which is either uncacheable (correct for config, wasteful for the loader) or cached (correct for the loader, incorrect for config).

What this changes

New method: api.getBrowserAgentLoader(options)

Returns only the static loader script, optionally wrapped in a <script> tag (with nonce support). Because the loader never changes between requests, it can be served through a CDN or long-lived cache, or inlined once into a layout template.

New option: getBrowserTimingHeader({ hasToRemoveLoaderScript: true })

Returns only the per-request NREUM config block — no loader body. This is the piece that must be injected dynamically on each response (e.g. via a reverse proxy inserting it into , or a server-side template). Change is opt in and non breaking.

Internal refactor: _wrapScriptTag(content, options)

The <script> wrapping logic (plain / nonce / unwrapped) was duplicated between _generateRUMHeader and the new method. Extracted into a shared private helper.

Why this matters

This split enables deployment patterns that weren't previously possible with a single APM-connected Node.js agent:

  • cached loader delivery — serve getBrowserAgentLoader() from a caching reverse proxy or CDN; invalidate only on agent upgrades.
  • lightweight per-request injection — inject only the small config blob (hasToRemoveLoaderScript: true) via a proxy or template on each request, keeping the response path thin.
  • Separation of concerns

The existing getBrowserTimingHeader() behaviour is unchanged — callers that don't opt in to either new option get the same combined output as before.

@CLAassistant

CLAassistant commented Jun 19, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@Andreyco Andreyco force-pushed the feat/getBrowserAgentLoader branch from 79b161a to 97b20f7 Compare June 19, 2026 13:35
Splits the browser monitoring output into two independently deliverable
pieces: the static loader script (getBrowserAgentLoader) and the
per-request config blob (getBrowserTimingHeader with hasToRemoveLoaderScript: true).

This enables deployments where the loader is served through a caching
proxy or CDN while only the lightweight config blob is injected per
request — without losing APM-driven transaction correlation.

Extracts shared <script> tag wrapping logic into _wrapScriptTag so both
methods handle nonce and hasToRemoveScriptWrapper consistently.
@Andreyco Andreyco force-pushed the feat/getBrowserAgentLoader branch from 97b20f7 to 34e9680 Compare June 19, 2026 13:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Needs PR Review

Development

Successfully merging this pull request may close these issues.

3 participants