npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@logbrew/browser

v0.1.3

Published

Browser error, page-view, action, network, and fetch transport helpers for the public LogBrew JavaScript SDK.

Downloads

470

Readme

@logbrew/browser

Browser helpers for the public LogBrew JavaScript SDK.

This package captures page views, synchronous browser errors, unhandled Promise rejections, product actions, app-owned network milestones, and opt-in browser timing spans while keeping validation, buffering, retry, flush, and shutdown behavior in @logbrew/sdk.

Install

npm install @logbrew/sdk @logbrew/browser
pnpm add @logbrew/sdk @logbrew/browser

Browser Setup

import { installLogBrewBrowser } from "@logbrew/browser";

const logbrew = installLogBrewBrowser({
  clientKey: "LOGBREW_BROWSER_KEY"
});

logbrew.client.log("evt_log_001", new Date().toISOString(), {
  message: "browser app started",
  level: "info",
  logger: "browser"
});

installLogBrewBrowser() attaches error and unhandledrejection listeners with addEventListener(), captures an initial page-view span, creates one W3C trace context for the browser session, and returns a handle with client, traceContext, flush(), shutdown(), previewJson(), and uninstall(). The page-view span carries the versioned page_view analytics classification and a path-only surface; this classifies the span already being captured and does not add a second event. Page views plus explicit browser actions and network milestones also add privacy-bounded breadcrumbs to later issues. Its built-in fetch transport owns one coalesced lifecycle delivery for pagehide and hidden visibility, using only an authenticated, bounded keepalive request. Duplicate signals do not start another exit request, and uninstall() removes both listeners idempotently.

Route changes in single-page apps are explicit. Use installLogBrewBrowserNavigationInstrumentation() when your app wants LogBrew to observe history.pushState, history.replaceState, and popstate, create a fresh route trace context, and capture a page-view span for each path change. It is not installed by default.

onFlush(response, context, details) and onCaptureError(error, context, details) receive details.reason as capture, online, pagehide, or visibility_hidden, so apps can distinguish normal capture flushes from lifecycle and connectivity delivery without parsing browser events globally.

For browser apps, prefer a browser-scoped public key through clientKey. apiKey is still accepted for compatibility with lower-level SDK examples.

By default, browser metadata keeps the current path without query string or hash. It does not include document title or user agent unless includeDocumentTitle or includeUserAgent is enabled. Pass a low-cardinality metadata.routeTemplate when a concrete path contains identifiers and should group under a stable analytics surface. Pass sanitizeMetadata(metadata, kind) to remove or rewrite metadata before events are queued.

Set flushOnOnline: false, flushOnPageHide: false, or flushOnVisibilityHidden: false if your app wants to own lifecycle or connectivity delivery itself.

Lifecycle delivery never uses sendBeacon, a custom transport, or a fetch transport configured with keepalive: false. Unsupported or oversized work remains in the existing queue; it is not silently dropped. After importing createFetchTransport, an app can deliver work that exceeds a deliberately lowered keepalive limit with logbrew.client.flush(createFetchTransport({ keepalive: false })). Authentication, rate-limit, and nonretryable responses pause additional lifecycle sends until an explicit successful flush(). The client key stays in the Authorization header and is never added to the endpoint, query string, request body, persistence metadata, or delivery health.

Default Runtime Context

installLogBrewBrowser() and createLogBrewBrowserClient() add a small typed runtime context to every release, environment, issue, log, span, action, and metric. When the browser exposes low-entropy User-Agent Client Hints, the context contains the browser brand and significant version, platform name, and mobile or desktop device family. Browsers without those hints send only runtime.name: "browser".

This default reads only navigator.userAgentData.brands, platform, and mobile. It never reads the legacy user-agent string, calls getHighEntropyValues(), or collects a device model, architecture, OS version, screen, language, memory, CPU, document value, host, network identifier, or user identity. Caller-provided shared context remains authoritative and can add explicit service, deployment, application, trace, session, opaque subject, or safe tag context:

const logbrew = installLogBrewBrowser({
  clientKey: "LOGBREW_BROWSER_KEY",
  context: {
    schemaVersion: 1,
    resource: {
      service: { name: "checkout-web" },
      deployment: { environment: "production", release: "[email protected]" }
    }
  }
});

Set captureRuntimeContext: false to disable only the automatic browser defaults. Explicit context remains intact. When an app passes an already created client to installLogBrewBrowser(), that client keeps the context chosen when it was created.

Browser Error Source-Map Hints

If your frontend build injects JavaScript source-map Debug IDs, pass the app-owned map into browser setup so captured error and unhandledrejection issues carry release-artifact metadata alongside release, environment, service, and trace correlation:

const logbrew = installLogBrewBrowser({
  clientKey: "LOGBREW_BROWSER_KEY",
  release: "[email protected]",
  environment: "production",
  service: "checkout-web",
  runtime: "browser",
  debugIdMap: {
    "/assets/app.js": "11111111-2222-4333-8444-555555555555"
  }
});

Browser issues record a typed exception, an explicit unhandled capture mechanism, prior bounded breadcrumbs, the error type/message, path-only frames, line, column, low-cardinality grouping key, bounded cause-chain type/source summaries, optional Debug ID, release, environment, service, runtime, and active trace/span IDs. Raw stack text and nested cause messages stay out by default; set includeErrorStack: true only if your app has a clear redaction policy. Debug ID code files, grouping keys, and automatic breadcrumbs use sanitized event fields, so full URLs, hosts, query strings, hash fragments, headers, payloads, cookies, screenshots, replay data, baggage, and tracestate are not captured.

Browser Error Suppression

Use errorSuppressionRules for known noisy browser issues that should not be queued or flushed, such as third-party widget errors your team has already triaged. Rules match only local event fields and report a safe summary through onIssueSuppressed:

const logbrew = installLogBrewBrowser({
  clientKey: "LOGBREW_BROWSER_KEY",
  errorSuppressionRules: [{
    errorName: "ResizeObserverError",
    frameFile: /\/assets\/vendor-widget\.js$/u,
    reason: "third_party_resize_observer"
  }],
  onIssueSuppressed(summary) {
    console.debug("LogBrew issue suppressed", summary.reason);
  }
});

Rules can match source, errorName, path, frameFile, groupingKey, fingerprint, or message with strings, regular expressions, or arrays of either. When a rule matches, the returned value is { suppressed: true, reason }; LogBrew does not enqueue the issue and does not flush the transport. Suppression summaries include only source, error type, current path, path-only frame file, grouping key, optional fingerprint, and reason. They do not include the raw message, stack text, full URL, host, query string, hash, headers, payloads, cookies, replay data, baggage, or tracestate.

For app-owned logic, pass shouldCaptureError(event, summary) and return false to suppress. The callback receives the full local issue event plus the safe summary, so keep the callback inside your own app boundary and do not forward raw events to logs or diagnostics.

Structured Actions

Use captureBrowserAction() for the product steps your app already understands, such as clicks, form submits, route changes, retry decisions, or funnel steps. Use captureBrowserNetwork() for important API milestones that should be correlated with the same session or trace. These action events give LogBrew and AI agents a session timeline that can be analyzed across many users without requiring a person to watch individual recordings.

import {
  captureBrowserAction,
  captureBrowserNetwork,
  installLogBrewBrowser
} from "@logbrew/browser";

const logbrew = installLogBrewBrowser({
  clientKey: "LOGBREW_BROWSER_KEY"
});

await captureBrowserAction({
  name: "checkout.clicked",
  status: "success",
  metadata: {
    funnel: "checkout",
    routeTemplate: "/checkout",
    sessionId: "sess_123",
    step: 2
  }
}, logbrew);

await captureBrowserNetwork({
  method: "POST",
  routeTemplate: "/api/checkout",
  statusCode: 503,
  durationMs: 842,
  sessionId: "sess_123",
  traceId: "4bf92f3577b34da6a3ce929d0e0e4736",
  metadata: {
    funnel: "checkout",
    retryAttempt: 1
  }
}, logbrew);

Action and network metadata is sanitized to primitive values. Browser product actions carry the versioned interaction analytics classification; network milestones do not. Keep metadata low-cardinality and avoid raw selectors, full URLs, query strings, headers, request or response bodies, user-entered text, screenshots, or replay payloads unless your application owns a clear opt-in and redaction policy. captureBrowserNetwork() records route templates, methods, status codes, durations, trace IDs, session IDs, and your own primitive metadata; it does not patch fetch or inspect network payloads automatically. See the repository product analytics capture contract for the reserved fields and compatibility rules.

Resource Timing Spans

Use captureBrowserResourceTiming() when your app wants browser PerformanceResourceTiming entries to appear as trace spans under the current page or route trace. Pass resourcePathTemplate for high-cardinality routes so resource spans group by a stable path instead of a specific ID.

import {
  captureBrowserResourceTiming,
  installLogBrewBrowser
} from "@logbrew/browser";

const logbrew = installLogBrewBrowser({
  clientKey: "LOGBREW_BROWSER_KEY"
});

for (const entry of performance.getEntriesByType("resource")) {
  if (entry.name.includes("/api/checkout/")) {
    await captureBrowserResourceTiming(entry, logbrew, {
      resourcePathTemplate: "/api/checkout/:id"
    });
  }
}

For app-owned automatic capture, opt in with installLogBrewBrowserResourceTimingInstrumentation() after setup. It uses PerformanceObserver for resource entries, can be removed with uninstall(), and is not enabled by default.

import {
  installLogBrewBrowser,
  installLogBrewBrowserResourceTimingInstrumentation
} from "@logbrew/browser";

const logbrew = installLogBrewBrowser({
  clientKey: "LOGBREW_BROWSER_KEY"
});

const resources = installLogBrewBrowserResourceTimingInstrumentation(logbrew, {
  resourcePathTemplate({ path }) {
    return path.replace(/\/\d+$/u, "/:id");
  }
});

// Later, if your app owns teardown.
resources.uninstall();

Resource timing spans keep the active trace ID, create a child span ID, record duration, status code when the browser exposes it, initiator type, size fields, and bounded phase timings such as lookup, connect, TLS, request, and response time. They store only path/template metadata; full URLs, hosts, query strings, hash fragments, headers, request or response bodies, cookies, baggage, and tracestate are not captured.

Document Load Timing Spans

Use captureBrowserNavigationTiming() when your app wants a browser PerformanceNavigationTiming entry to explain the initial document load under the current page or route trace. This gives one browser.document <path> child span with first-byte, name lookup, connect, TLS, request, response, DOM, and load-event timings without adopting hidden global tracing.

import {
  captureBrowserNavigationTiming,
  installLogBrewBrowser
} from "@logbrew/browser";

const logbrew = installLogBrewBrowser({
  clientKey: "LOGBREW_BROWSER_KEY"
});

const [entry] = performance.getEntriesByType("navigation");

if (entry) {
  await captureBrowserNavigationTiming(entry, logbrew, {
    navigationPathTemplate: "/checkout"
  });
}

For app-owned one-shot capture after the browser load event, opt in with installLogBrewBrowserNavigationTimingInstrumentation(). It reads the current navigation entry once, waits until load has completed when needed, can be removed with uninstall(), and is not enabled by default.

import {
  installLogBrewBrowser,
  installLogBrewBrowserNavigationTimingInstrumentation
} from "@logbrew/browser";

const logbrew = installLogBrewBrowser({
  clientKey: "LOGBREW_BROWSER_KEY"
});

const documentLoad = installLogBrewBrowserNavigationTimingInstrumentation(logbrew, {
  navigationPathTemplate({ path }) {
    return path.replace(/\/\d+$/u, "/:id");
  }
});

// Later, if your app owns teardown.
documentLoad.uninstall();

Document load timing spans keep the active trace ID, create a child span ID, record status, transfer sizes, first byte, DOM milestones, load-event timing, and bounded phase durations. They store only path/template metadata; full URLs, hosts, query strings, hash fragments, server timing records, headers, request or response bodies, cookies, baggage, and tracestate are not captured.

Web Vitals Spans

Use captureBrowserWebVital() when your app already receives Web Vital metrics, such as from the optional web-vitals package. LogBrew turns each metric into a browser.web_vital <name> <path> child span under the active page or route trace, so LCP, CLS, INP, FCP, and TTFB can be read next to page-load, route, fetch, XHR, resource, action, log, and error events.

import {
  captureBrowserWebVital,
  installLogBrewBrowser
} from "@logbrew/browser";
import { onLCP } from "web-vitals";

const logbrew = installLogBrewBrowser({
  clientKey: "LOGBREW_BROWSER_KEY"
});

onLCP((metric) => {
  void captureBrowserWebVital(metric, logbrew, {
    webVitalPathTemplate: "/checkout"
  });
});

If your app wants LogBrew to register multiple app-owned Web Vital callbacks at once, pass the imported callbacks through installLogBrewBrowserWebVitalsInstrumentation().

import {
  installLogBrewBrowser,
  installLogBrewBrowserWebVitalsInstrumentation
} from "@logbrew/browser";
import * as webVitals from "web-vitals";

const logbrew = installLogBrewBrowser({
  clientKey: "LOGBREW_BROWSER_KEY"
});

const webVitalSpans = installLogBrewBrowserWebVitalsInstrumentation(logbrew, {
  metricNames: ["LCP", "CLS", "INP", "FCP", "TTFB"],
  webVitalPathTemplate: "/checkout",
  webVitals
});

// Later, if your app owns teardown.
webVitalSpans.uninstall();

Web Vital spans keep the active trace ID, create a child span ID, record metric name, value, unit, rating, navigation type, delta, and safe timing subparts such as time to first byte or resource load duration when the metric provides them. They do not include DOM selectors, interaction targets, raw attribution entries, full URLs, hosts, query strings, hash fragments, headers, request or response bodies, cookies, user text, baggage, or tracestate.

Interaction, Long-Task, and Long-Animation-Frame Timing Spans

Use captureBrowserInteractionTiming() when your app already receives PerformanceEventTiming, first-input, longtask, or long-animation-frame entries and wants click/input/main-thread latency next to the active route trace. Pass interactionPathTemplate so high-cardinality paths group under a stable route name.

import {
  captureBrowserInteractionTiming,
  captureBrowserInteractionToNextPaint,
  installLogBrewBrowser
} from "@logbrew/browser";

const logbrew = installLogBrewBrowser({
  clientKey: "LOGBREW_BROWSER_KEY"
});

for (const entry of performance.getEntriesByType("event")) {
  await captureBrowserInteractionTiming(entry, logbrew, {
    interactionPathTemplate: "/checkout"
  });
}

If your app already buffers PerformanceEventTiming entries for a view, use captureBrowserInteractionToNextPaint() to emit one INP-style ranked summary span. Pass interactionCount from performance.interactionCount when available; LogBrew keeps only the slowest bounded candidates and records the p98-style rank, not every click target.

await captureBrowserInteractionToNextPaint(performance.getEntriesByType("event"), logbrew, {
  interactionCount: performance.interactionCount,
  interactionPathTemplate: "/checkout"
});

For app-owned automatic capture, opt in with installLogBrewBrowserInteractionTimingInstrumentation(). It uses PerformanceObserver for event and longtask entries, can be removed with uninstall(), and is not enabled by default.

import {
  installLogBrewBrowser,
  installLogBrewBrowserInteractionTimingInstrumentation
} from "@logbrew/browser";

const logbrew = installLogBrewBrowser({
  clientKey: "LOGBREW_BROWSER_KEY"
});

const interactions = installLogBrewBrowserInteractionTimingInstrumentation(logbrew, {
  interactionDurationThresholdMs: 40,
  interactionPathTemplate({ path }) {
    return path.replace(/\/\d+$/u, "/:id");
  }
});

// Later, if your app owns teardown.
interactions.uninstall();

When the browser reports PerformanceObserver.supportedEntryTypes with long-animation-frame, the default observer captures event plus long-animation-frame; older browsers keep the event plus longtask fallback. You can pass entryTypes explicitly if your app owns a different policy.

Interaction timing spans keep the active trace ID, create a child span ID, and record entry type, interaction type, interaction ID, input delay, processing duration, presentation delay, start time, task name, long-animation-frame blocking/render/style timing, aggregate script duration/count, INP-style candidate rank, view interaction count, and route template when available. They do not include DOM targets, selectors, element text, script URLs, script function names, script invokers, attribution script URLs, full URLs, hosts, query strings, hash fragments, headers, request or response bodies, cookies, user text, baggage, or tracestate.

Fetch Spans

Use createLogBrewBrowserFetch() when browser API calls should become trace spans and optionally propagate W3C traceparent to your own backend. This wraps an app-owned fetch function and is separate from the lower-level createTraceparentFetch() header helper.

import {
  createLogBrewBrowserFetch,
  installLogBrewBrowser
} from "@logbrew/browser";

const logbrew = installLogBrewBrowser({
  clientKey: "LOGBREW_BROWSER_KEY"
});

const logbrewFetch = createLogBrewBrowserFetch(logbrew, {
  resourcePathTemplate({ path }) {
    return path.replace(/\/\d+$/u, "/:id");
  },
  tracePropagationTargets: [/^\/api\//]
});

await logbrewFetch("/api/orders/123", {
  method: "POST",
  body: JSON.stringify({ cartId: "cart_123" })
});

createLogBrewBrowserFetch() creates a child span under the active page or route trace, injects exactly one normalized traceparent only when tracePropagationTargets matches, measures duration, records method, path/template, status code, response content length when exposed, and error type for network failures, then rethrows the original fetch error. It never captures request or response bodies, arbitrary headers, full URLs, hosts, query strings, hash fragments, cookies, error messages, baggage, or tracestate.

If your app intentionally wants a global browser fetch patch, opt in with installLogBrewBrowserFetchInstrumentation() and keep the returned teardown handle.

const fetchInstrumentation = installLogBrewBrowserFetchInstrumentation(logbrew, {
  resourcePathTemplate: "/api/orders/:id",
  tracePropagationTargets: [/^\/api\/orders\//]
});

// Later, if your app owns teardown.
fetchInstrumentation.uninstall();

Fetch instrumentation is not installed by default. If your XHR calls already go through an app-owned wrapper, use captureBrowserXhrSpan() or captureBrowserResourceTiming() instead of prototype instrumentation.

XHR Spans

Use installLogBrewBrowserXhrInstrumentation() only when your app intentionally wants LogBrew to observe browser XMLHttpRequest calls. It patches XMLHttpRequest.prototype.open/send after explicit install and returns a teardown handle.

import {
  installLogBrewBrowser,
  installLogBrewBrowserXhrInstrumentation
} from "@logbrew/browser";

const logbrew = installLogBrewBrowser({
  clientKey: "LOGBREW_BROWSER_KEY"
});

const xhrInstrumentation = installLogBrewBrowserXhrInstrumentation(logbrew, {
  resourcePathTemplate({ path }) {
    return path.replace(/\/\d+$/u, "/:id");
  },
  tracePropagationTargets: [/^\/api\//]
});

// Later, if your app owns teardown.
xhrInstrumentation.uninstall();

XHR instrumentation creates a child span under the active page or route trace, injects exactly one normalized traceparent only when tracePropagationTargets matches, measures duration, records method, path/template, status code, response content length when exposed, and event type for network failures such as error, abort, or timeout. It never captures request or response bodies, arbitrary headers, full URLs, hosts, query strings, hash fragments, cookies, error messages, baggage, or tracestate.

If your app already has its own XHR wrapper, use captureBrowserXhrSpan() or createBrowserXhrSpanEvent() with your sanitized request summary instead of installing prototype instrumentation.

Fetch Transport

import { createFetchTransport, installLogBrewBrowser } from "@logbrew/browser";

installLogBrewBrowser({
  clientKey: "LOGBREW_BROWSER_KEY",
  transport: createFetchTransport({
    endpoint: "https://api.logbrew.co/v1/events",
    maxKeepaliveBodyBytes: 64 * 1024
  })
});

createFetchTransport() uses browser fetch with keepalive: true by default so explicit page-lifecycle flushes can finish during navigation. To keep that behavior predictable, LogBrew refuses keepalive payloads above maxKeepaliveBodyBytes before calling fetch; the queued events remain available for a later non-keepalive flush. Set keepalive: false for app-owned large-batch delivery. LogBrew does not use sendBeacon by default because beacon cannot send the same Authorization header as fetch; use the explicit beacon transport only when your intake endpoint accepts the Authorization-headerless browser beacon envelope.

Optional Beacon Transport

Use createBeaconTransport() for app-owned page-exit delivery only when the target endpoint accepts a JSON body shaped as { ingest_key, envelope }.

import { createBeaconTransport, installLogBrewBrowser } from "@logbrew/browser";

installLogBrewBrowser({
  clientKey: "LOGBREW_BROWSER_KEY",
  transport: createBeaconTransport({
    endpoint: "https://example.com/logbrew/browser-beacon",
    maxBeaconBodyBytes: 60 * 1024
  })
});

The beacon transport sends a Blob with Content-Type: application/json when the browser supports it, falls back to fetch when sendBeacon is unavailable, refused, or the body exceeds maxBeaconBodyBytes, and never places the browser key in the URL or request headers. The fallback fetch uses the same body-authenticated envelope and disables keepalive for oversized bodies to avoid browser keepalive failures. Persisted delivery still stores only the original sanitized telemetry envelope, not the browser key.

When an intake returns HTTP 429, the browser transport reads the standard Retry-After header and passes it to the core SDK as retryAfterMs. The flush then raises SdkError code rate_limited, preserves queued events, and avoids immediate retry; use that signal for app-owned retry timing or user-facing recovery.

Browser clients inherit the core SDK's count-and-byte-bounded in-memory queue and race-safe request splitting. The browser factory uses a 64 KiB request default so normal batches fit the existing keepalive transport limit; set both maxBatchBytes and maxKeepaliveBodyBytes deliberately if the app changes that ceiling. Pass maxQueueSize, maxQueueBytes, maxBatchEvents, maxBatchBytes, and onEventDropped to installLogBrewBrowser() or createLogBrewBrowserClient() when the app wants explicit high-volume tuning and drop reporting. LogBrew also flushes queued in-memory events on the browser online event by default, which helps after temporary connectivity loss.

Optional Persisted Delivery

Use persistOffline: true when a browser app should keep failed batches in Web Storage across a reload, navigation, or temporary offline session.

import { installLogBrewBrowser } from "@logbrew/browser";

const logbrew = installLogBrewBrowser({
  clientKey: "LOGBREW_BROWSER_KEY",
  persistOffline: {
    maxStoredBatches: 10,
    maxStoredBytes: 256 * 1024,
    storage: window.localStorage
  }
});

Persisted delivery stores only the already-sanitized JSON batch body. It does not store the browser key, request headers, cookies, raw payloads, full URLs, query strings, or hash fragments. Stored batches are bounded by maxStoredBatches and maxStoredBytes, deduplicated by exact batch body, replayed on install and on online, and cleared after a successful replay. If the same page session still has the failed events in memory, LogBrew treats that in-memory queue as the source of truth and avoids replaying its own persisted copy separately.

When the browser provides the Web Locks API, automatic storage, delivery, acknowledgement, and replay are serialized per storage key so multiple tabs do not deliver the same persisted batch concurrently. Browsers without Web Locks, or runtimes that reject lock acquisition, retain the same persistence behavior without cross-tab coordination. Custom runtimes can provide a compatible lockManager; lock names contain neither the browser key nor telemetry data.

Use createPersistentBrowserTransport({ transport, storage }) when your app wants to wrap a custom browser transport directly. Persistence is explicit recovery for the documented header-based fetch delivery path; it is not a hidden background worker or sendBeacon fallback.

Use RecordingTransport.alwaysAccept() from @logbrew/sdk when you want to inspect queued browser events before network delivery.

Trace Propagation

Use createTraceparentFetch() when the browser app should connect frontend work to backend traces. Propagation is target-scoped by default: no traceparent header is attached unless the request URL matches tracePropagationTargets.

import {
  createBrowserTraceContext,
  createTraceparentFetch
} from "@logbrew/browser";

const traceContext = createBrowserTraceContext();

const tracedFetch = createTraceparentFetch({
  traceContext,
  tracePropagationTargets: [
    "https://api.example.com/",
    /^\/api\//
  ]
});

await tracedFetch("/api/checkout", {
  method: "POST",
  body: JSON.stringify({ cartId: "cart_123" })
});

installLogBrewBrowser() creates a shared traceContext automatically and uses it for the initial page-view span, browser action metadata, browser error metadata, unhandled rejection metadata, and app-owned network milestone metadata. Pass traceContext: logbrew.traceContext to createTraceparentFetch() when the browser request should use the same trace as the page and product actions.

If your app renews the active trace on SPA navigation, pass a provider so each request gets the current route trace:

const tracedFetch = createTraceparentFetch({
  traceContext: () => logbrew.traceContext,
  tracePropagationTargets: [/^\/api\//]
});

tracePropagationTargets accepts strings, regular expressions, or (url) => boolean functions. String URL targets apply only to the same origin plus a path prefix, so https://api.example.com/v1 covers /v1/orders on that origin but not https://wrong.example.com or /v10. Keep targets narrow so browser requests do not send tracing headers to unrelated origins. If the API is on another origin, configure that backend's CORS policy to allow the traceparent request header.

LogBrew does not patch global fetch or XHR by default, capture request/response bodies, copy arbitrary headers, store query strings or hash fragments by default, or emit W3C baggage/tracestate from the browser helper. Use explicit app-owned fetch/XHR spans or network milestones for the routes that matter.

SPA Navigation Tracing

Use the navigation helper after installLogBrewBrowser() when a browser app wants route-level page-view spans and route-scoped trace correlation without adopting a framework integration.

import {
  captureBrowserAction,
  createTraceparentFetch,
  installLogBrewBrowser,
  installLogBrewBrowserNavigationInstrumentation
} from "@logbrew/browser";

const logbrew = installLogBrewBrowser({
  clientKey: "LOGBREW_BROWSER_KEY"
});

const navigation = installLogBrewBrowserNavigationInstrumentation(logbrew);

const tracedFetch = createTraceparentFetch({
  traceContext: () => logbrew.traceContext,
  tracePropagationTargets: [/^\/api\//]
});

await captureBrowserAction({
  name: "settings.opened",
  metadata: {
    routeTemplate: "/settings"
  }
}, logbrew);

await tracedFetch("/api/settings");

navigation.uninstall();

The helper captures only path changes by default. Query strings, hash fragments, history state objects, request bodies, response bodies, headers, browser storage values, screenshots, and replay data are not copied into telemetry. uninstall() removes the popstate listener and puts the original history.pushState and history.replaceState functions back when they are still the LogBrew wrappers.

Example Source

The package includes example source for browser setup, page-view capture, error listeners, visibility flushing, and target-scoped trace propagation. Use the snippets above as the starting point for wiring LogBrew into your browser application.