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

@tracewayapp/frontend

v1.0.7

Published

Traceway SDK for browser environments

Downloads

782

Readme

Traceway Browser SDK

Error tracking and session replay for browser apps. Capture exceptions with full stack traces, plus the last ~10 seconds of console logs, network calls, navigation transitions, custom breadcrumbs, and an rrweb DOM replay — automatically.

Traceway is a completely open-source error tracking platform. You can self-host it or use Traceway Cloud.

This is the framework-agnostic browser SDK. Use it directly in vanilla JS / TS, or pick a thin framework wrapper that initializes it for you: @tracewayapp/react, @tracewayapp/vue, @tracewayapp/svelte, @tracewayapp/jquery.

Features

  • Automatic capture of window.onerror and unhandledrejection
  • Full browser stack traces normalized to Traceway's wire format
  • rrweb session replay — exception-bound clip by default; opt into always-on session recording for full-session replay (see below)
  • Logs — every console.{debug,log,info,warn,error} line, kept in a rolling buffer
  • Actions — every fetch / XMLHttpRequest call, History API navigation, and custom breadcrumb
  • Auto-collected attributesurl, path, referrer, userAgent, language, platform, viewport, screen, timezone stamped on every session and exception
  • Global attribute scopesetAttribute("userId", "42") and friends to attach app-level identifiers (tenant, user id, feature flag) to every subsequent session and exception
  • Distributed tracing — propagates a traceway-trace-id header across fetch / XHR / Axios
  • Source-map resolution on the backend (see @tracewayapp/sourcemap-upload)
  • Gzip-compressed transport via native CompressionStream (the page-unload flush sends raw JSON so it dispatches synchronously)
  • Self-request filter — the SDK does not log its own /api/report calls into the action buffer
  • Debounced, retrying batch uploads
  • Simple one-line setup

Installation

npm install @tracewayapp/frontend

Or via CDN (no bundler):

<script src="https://cdn.jsdelivr.net/npm/@tracewayapp/frontend@1/dist/traceway.iife.global.js"></script>
<script>
  Traceway.init("your-token@https://traceway.example.com/api/report");
</script>

Quick Start

import { init, captureException, captureMessage, recordAction, flush } from "@tracewayapp/frontend";

// Initialize once at app startup
init("your-token@https://traceway.example.com/api/report", {
  version: "1.0.0",
});

// Capture errors
try {
  riskyOperation();
} catch (error) {
  captureException(error);
}

// Capture custom messages
captureMessage("User completed checkout");

// Record a custom breadcrumb that rides along with the next exception
recordAction("checkout", "payment_submitted", { amount: 42 });

// Force-send all pending exceptions (e.g. before page unload)
await flush();

init() automatically installs window.onerror and unhandledrejection handlers, patches console.*, instruments fetch / XMLHttpRequest, instruments the History API, and starts an rrweb session recorder. Each captured exception is paired with the rolling timeline that preceded it.

Manual Capture

import {
  captureException,
  captureExceptionWithAttributes,
  captureMessage,
  flush,
} from "@tracewayapp/frontend";

// Capture a caught error
try {
  await riskyOperation();
} catch (e) {
  captureException(e as Error);
}

// Capture with attributes (key-value tags)
captureExceptionWithAttributes(error, { tenant: "acme", region: "us-east" });

// Capture a message
captureMessage("User completed checkout");

// Force send pending events
await flush();

Options

| Option | Default | Description | |--------|---------|-------------| | version | "" | App version string, attached to every report | | debug | false | Print debug info to the console | | debounceMs | 1500 | Milliseconds before flushing batched events | | retryDelayMs | 10000 | Retry delay on failed uploads | | ignoreErrors | sensible defaults | Array of string \| RegExp patterns; matching exceptions are dropped | | beforeCapture | none | (exception) => boolean — return false to drop | | captureLogs | true | Mirror console.* into the rolling log buffer | | captureNetwork | true | Record fetch / XHR as network actions | | captureNavigation | true | Record History API push / replace / pop as navigation actions | | sessionRecording | true | Enable the rrweb session recorder | | sessionRecordingSegmentDuration | 30000 | Segment length for the recorder (ms). 30 s by default; the always-on path uploads each segment as it rotates | | recordAllSessions | false | When true, upload every segment continuously and create a parent session row, regardless of whether an exception fires. Sessions end on 15 min inactivity, 60 min max duration, or pagehide | | eventsWindowMs | 10000 (30000 with recordAllSessions) | Rolling window kept in the log/action buffers | | eventsMaxCount | 200 (600 with recordAllSessions) | Hard cap applied independently to logs and actions |

The DEFAULT_IGNORE_PATTERNS export contains the built-in ignoreErrors list — you can extend it rather than replace it.

Logs & Actions

Every captured exception ships with the last ~10 seconds of session context, attached to the same sessionRecordings[] entry on the wire:

  • events — rrweb DOM events for visual replay
  • logs — recent console output
  • actions — recent network requests, route changes, custom breadcrumbs
  • startedAt / endedAt — wall-clock anchors so the backend can align logs/actions onto the replay timeline (offsetIntoVideoMs = event.timestamp − recording.startedAt)

Logs

Captured automatically by patching console.{debug, log, info, warn, error}. The original console output is preserved — the SDK only piggybacks on the call.

Disable with captureLogs: false.

Actions

Three sources feed the action buffer:

  • Networkfetch and XMLHttpRequest are instrumented to record method, URL, status code, duration, and request/response sizes. Disable with captureNetwork: false.
  • Navigationhistory.pushState, history.replaceState, popstate, and hashchange are recorded (push / replace / pop). Static <a>-driven full-page loads aren't captured — the document unloads first. Disable with captureNavigation: false.
  • Custom — call recordAction(category, name, data?) to drop in a breadcrumb (recordAction("user", "tapped_pay")). Always recorded; there's no per-category opt-out.

Session Recordings

An rrweb-based recorder runs in the background and segments events into chunks. On exception, all buffered segments are flattened into the recording payload. Disable with sessionRecording: false — logs and actions are still attached when recording is off.

Tune the segment length with sessionRecordingSegmentDuration (ms).

Buffer sizing

Logs and actions live in independent rolling buffers. Each is capped by:

  • eventsWindowMs — drop entries older than this many ms (default 10_000, or 30_000 when recordAllSessions: true so every 30 s segment carries its full activity)
  • eventsMaxCount — keep at most this many entries (default 200, or 600 with recordAllSessions)

Always-on Session Recording

By default the SDK only ships a session-replay clip when an exception fires (the last ~30 s of rrweb events plus logs/actions). Set recordAllSessions: true to record every session continuously:

init("your-token@https://traceway.example.com/api/report", {
  recordAllSessions: true,
});

What changes:

  • A persistent sessionId is generated at SDK init (or after bfcache restore) and attached to every exception captured during that session.
  • Each ~30 s rrweb segment is uploaded as a separate session_recordings row pointing at a parent sessions row in the dashboard.
  • Sessions end on 15 min inactivity (no DOM events), 60 min max duration, or pagehide (close tab / navigate away). The closing payload uses fetch keepalive so it survives unload.
  • The exception-bound 10 s clip still ships alongside, so the issue page keeps its inline replay; the new Sessions page in the dashboard plays the full timeline.
  • Logs and actions are flushed onto each segment as it rotates (drained from the rolling buffer to avoid double-counting).

With recordAllSessions: false, only exception-bound clips ship — the default and lowest-cost mode.

Custom Attributes (global scope)

Attach app-level identifiers (userId, tenant, feature flags, etc.) once and have them ride along every subsequent session and exception:

import {
  setAttribute,
  setAttributes,
  removeAttribute,
  clearAttributes,
} from "@tracewayapp/frontend";

setAttribute("userId", "u_42");
setAttributes({ tenant: "acme", plan: "pro" });

// ...later, on logout / tenant switch:
clearAttributes();

Layering order on each event: auto-collected defaults < global scope < per-call attributes. Per-call exception attributes from captureExceptionWithAttributes(err, { … }) still win over global keys on collision.

If recordAllSessions: true is on and the global scope changes mid-session, the SDK pushes a refresh upsert so the in-flight session row picks up the new attributes immediately rather than waiting for close.

The auto-collected defaults are: url, path, referrer, userAgent, language, platform, viewport, screen, timezone. The backend additionally stamps client.ip from the request.

Distributed Tracing

When the SDK is initialized inside an app served alongside a Traceway-instrumented backend, every outgoing fetch / XHR automatically gets a traceway-trace-id header. Use getActiveDistributedTraceId() to read the in-flight id, or createAxiosInterceptor() to add the header to a shared Axios instance:

import axios from "axios";
import { createAxiosInterceptor } from "@tracewayapp/frontend";

const api = axios.create({ baseURL: "/api" });
api.interceptors.request.use(createAxiosInterceptor());

Source Maps

When you build for production, the browser stack traces are minified. Upload your source maps after each build so the dashboard can resolve them back to the original file:line:col:

npx @tracewayapp/sourcemap-upload \
  --url https://traceway.example.com \
  --token YOUR_SOURCE_MAP_TOKEN \
  --version 1.0.0 \
  --directory dist/assets

The --version flag must match the version you pass to init(). See @tracewayapp/sourcemap-upload for the full CLI reference.

API

| Function | Description | |----------|-------------| | init(connectionString, options?) | Initialize the SDK and install all global instrumentation | | captureException(error, options?) | Capture an error with browser stack trace; optional distributedTraceId | | captureExceptionWithAttributes(error, attrs?, options?) | Capture with key-value attributes (per-call; merged on top of global scope) | | captureMessage(msg) | Capture an informational message | | recordAction(category, name, data?) | Record a custom breadcrumb | | setAttribute(key, value) | Attach a key/value to every subsequent session and exception | | setAttributes(map) | Bulk version of setAttribute | | removeAttribute(key) | Drop a single key from the global scope | | clearAttributes() | Drop everything in the global scope | | flush(timeoutMs?) | Force-send all pending exceptions; stops the session recorder | | getActiveDistributedTraceId() | Return the in-flight distributed trace id, if any | | createAxiosInterceptor() | Axios request interceptor that injects the distributed-trace header |

Platform Support

| Environment | Error Tracking | Session Replay | |---|---|---| | Chrome 80+ | Yes | Yes | | Firefox 113+ | Yes | Yes | | Safari 16.4+ | Yes | Yes | | Edge 80+ | Yes | Yes | | Older browsers | No | No |

The CompressionStream API used for gzip-compressed uploads is supported in Chrome 80+, Firefox 113+, Safari 16.4+ — the SDK requires it for the regular sync path. The page-unload flush always sends raw JSON (so the request can dispatch synchronously inside the pagehide handler), and the backend accepts both.

For React Native and Expo apps, use @tracewayapp/react-native instead — it intentionally omits rrweb (no DOM) but preserves the logs, actions, and exception capture pipeline.

Links

License

MIT