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

@ziplogger/browser

v0.5.2

Published

ZipLogger browser SDK — product-analytics events, console errors, unhandled rejections, distributed tracing and session replay from web apps, with a React error boundary. Zero dependencies.

Downloads

779

Readme

@ziplogger/browser

Browser SDK for ZipLogger — product-analytics events, uncaught errors, unhandled promise rejections and distributed tracing from web apps, with a first-class React error boundary. Zero dependencies.

npm install @ziplogger/browser

Quick start

import { ZipLoggerBrowser } from '@ziplogger/browser'

export const ziplogger = new ZipLoggerBrowser({
  endpoint: 'https://app.ziplogger.ai',
  apiKey: 'zk_...',            // use a key dedicated to browser traffic
  release: import.meta.env.VITE_APP_VERSION,
})

ziplogger.captureGlobalErrors()  // window.onerror + unhandledrejection

ziplogger.log({ severity: 'info', message: 'checkout started', fields: { cartValue: 214.9 } })
try { risky() } catch (err) { ziplogger.captureError(err, { step: 'payment' }) }

Events

Events are what people did; logs are what you read when something breaks. They are separate calls because ZipLogger answers different questions with each.

ziplogger.track('checkout_started', { cartValue: 214.9, currency: 'USD' })

// After sign-in. Links everything this browser did anonymously to the account, so the visitor
// stops being counted as two people.
ziplogger.identify('user_42')

ziplogger.reset()   // on sign-out: a fresh anonymous identity from here

An un-identified visitor still needs an id, or the server has nobody to attribute the event to. The SDK mints one on first use and keeps it in localStorage (zl_anon), with a per-tab session id in sessionStorage (zl_sess) — that stored anonymous id is exactly what identify() later links. Both fall back to memory when storage is unavailable, so private mode degrades to per-page attribution rather than an error.

Every event carries an insertId, so a retry after a timeout cannot count it twice.

Linking events to requests

With instrumentFetch() on, every same-origin request (and any origin in propagateTo) carries a W3C traceparent header, and the event you track right after it carries that request's trace id as requestId. ZipLogger then shows the logs and traces of the request the event happened in ("Requests sampled", "Errors on these requests" on the event page).

ziplogger.instrumentFetch({ propagateTo: ['https://api.example.com'] })

const res = await fetch('/api/checkout', { method: 'POST', body })
ziplogger.track('checkout_completed', { amount: 99 })   // requestId = that request's trace id

Inference uses the most recent instrumented fetch within requestCorrelationTtlMs (default 5 s, a constructor option; 0 disables it). An event with no recent request carries no requestId — one is never invented. To pin an event to a specific request yourself, pass its trace id (or the full traceparent value) explicitly; it wins over the inferred one:

ziplogger.track('checkout_completed', { amount: 99 }, { requestId: traceId })

Do not put credentials in properties. Values that look like tokens, keys or card numbers are redacted server-side, but the safe habit is not to send them.

Every event carries url, userAgent, and environment fields automatically; Error objects map to ZipLogger's stackTrace. A final fetch(…, { keepalive: true }) flush fires on pagehide so events survive navigation and tab closes.

React

import React from 'react'
import { createErrorBoundary, createUseZipLogger } from '@ziplogger/browser/react'
import { ziplogger } from './ziplogger'

const ZipLoggerErrorBoundary = createErrorBoundary(React, ziplogger)
export const useZipLogger = createUseZipLogger(React, ziplogger)

root.render(
  <ZipLoggerErrorBoundary fallback={<p>Something went wrong.</p>}>
    <App />
  </ZipLoggerErrorBoundary>,
)

// in any component
const { captureError } = useZipLogger()

Render errors ship with the component stack; the factory pattern (createErrorBoundary(React, …)) keeps this package free of a React dependency, so it works with any React ≥ 16.8 — and the core client works with Vue, Svelte, Angular, or no framework at all.

Session replay

npm install @rrweb/record        # optional peer dependency; only if you want replay
import { attachSessionReplay } from '@ziplogger/browser/replay'

const ziplogger = new ZipLoggerBrowser({
  endpoint: 'https://app.ziplogger.ai',
  apiKey: 'zk_...',
  sessionReplay: { enabled: true, sampleRate: 0.1 },   // record 10% of sessions
})
attachSessionReplay(ziplogger)

ziplogger.sessionReplay.isRecording()

Records the DOM, not video, and attaches to the same session id your events and errors carry. Passwords, payment fields and one-time codes are always masked, every other input is masked by default, and data-ziplogger-mask / data-ziplogger-ignore mark up anything else — in the browser, before it is sent. The recorder is loaded only for visitors who are sampled in: a page that does not record replays ships the same bytes it always did.

See docs/session-replay.md.

Notes

  • Browser API keys are visible to users by design (like every client-side telemetry key). Use a dedicated key so it can be revoked independently, and rely on your plan's rate limits.
  • Batching defaults are browser-tuned: 20 events/request, 3s linger, 2 retries, 1,000-event buffer.