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

@anyreplay/browser

v0.3.0

Published

Session replay recorder for the browser: DOM-based recording with configurable masking (passwords and payment fields always masked), custom events, and chunked delivery to AnyReplay.

Readme

@anyreplay/browser

Session replay recorder for the browser, made by AnyReplay: watch any user's session, translated into your own language.

  • DOM-based recording (built on rrweb), not video — about 35 KB gzipped
  • Form fields are masked by default; one line records them, and passwords and payment fields never are
  • Tag moments with track() and see them on the player's timeline
  • Sessions survive reloads and route changes; chunked, retried, and flushed with sendBeacon on page close
  • Deterministic sampling per visitor, retries that wait out an outage instead of giving up, and an optional consent gate

Install

npm install @anyreplay/browser
import { createRecorder } from '@anyreplay/browser';

const recorder = createRecorder({
  projectKey: 'ar_pk_live_…',      // from your AnyReplay project
  // ingestUrl: 'https://in.anyreplay.com',  // default; set for self-hosted
  // sampleRate: 1,                // 0..1, decided per visitor
  // maskAllInputs: false,         // on by default; false records what people type into fields
  // maskAllTyping: true,          // the stricter switch: fields and rich-text editors
  // maxSessionsPerMonth: 5000,    // optional cap for this project
  // appId: 'com.example.shop',    // only inside an app shell; see below
});

recorder.track('checkout_clicked', { plan: 'growth' });
recorder.identify({ userId: 'u_42', email: '[email protected]' });

Inside an app

A page running inside a Capacitor, Cordova, Electron or Tauri app has no real web origin — its web view reports capacitor://localhost, https://localhost or file:// — so a project that lists allowed domains refuses it. Add the app's bundle id or package name under Allowed apps in the project's settings, and pass the same value as appId. Leave appId out on a website: from a real web origin it is ignored, so it cannot open a web project's domain list. It is a filter, not a secret. The @anyreplay/capacitor, @anyreplay/cordova, @anyreplay/electron and @anyreplay/tauri packages (a preview) wrap this SDK and read the app id for you.

Every session also reports platform: 'web' and this package's name and version, so the dashboard can say what recorded it.

Prefer a script tag? Create a project in the dashboard and copy the snippet from its setup page; it loads the same code from cdn.anyreplay.com.

API

| Call | What it does | |---|---| | createRecorder(options) | Starts recording (or waits for consent) and returns a handle | | handle.track(name, properties?) | Tags this moment; name is 1–64 chars of [A-Za-z0-9_.:-], properties a JSON object ≤ 4 KB | | handle.trackError(error) | Records an error you caught yourself, redacted, and marks the session as having one | | handle.identify({ userId?, email? }) | Attaches your user id to the session; held until the session's first chunk is accepted, then sent once | | handle.consent(true) | Starts recording when requireConsent: true; consent(false) removes what was stored and stops (before recording started, a later consent(true) still starts it) | | handle.status() | idle, awaiting-consent, recording, sampled-out or stopped | | handle.flush() | Sends what is buffered now; resolves when delivered | | handle.stop() | Stops for this page | | handle.sessionId() | The current session id, for your own logs |

Privacy

By default a recording does not contain what visitors type into forms: every form field value becomes asterisks of the same length, so the replay shows the field being filled in without showing what went into it. To see what people typed — a form nobody could finish is easier to understand when you can read it — opt out:

  • maskAllInputs: false — form field values are recorded (the fields below stay masked).
  • maskAllInputs left out — the project's masking switch in the dashboard decides. The page records masked until ingest answers the first chunk with that choice, and stays masked if no answer comes.
  • maskAllTyping: true — the stricter switch: form fields plus the text of every contenteditable editor, whatever maskAllInputs says.
  • class="ar-mask" — one element, or one field, masked while the rest records.
  • class="ar-block" — the element's contents are not recorded at all.

Some fields are masked in every mode and no option records them: passwords and one-time codes; card numbers, security codes, expiry dates and cardholder names (from autocomplete="cc-…" or from a name, label or placeholder that reads like one); IBANs, routing numbers and sort codes; any value of 13–19 digits that passes the card-number check — and, because a number is typed one key at a time, any value that could still become one: digits only, starting 2–6, grouped like a card, more than six digits long. A card number written inside longer text ("my card is 4242 4242 …" in a note) has its digits starred and the rest of the text kept. At most the first six digits of a card number are ever recorded. Masking always happens in the page, before anything is sent.

type="email" and type="tel" are not on that list. An address and a phone number are ordinary contact details, so they follow maskAllInputs like any other field: masked by default, recorded with maskAllInputs: false unless maskAllTyping or class="ar-mask" covers them.

License

MIT © Baem Tech. Source: github.com/baemtech/anyreplay-sdk.