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

@oodle-ai/rum

v0.4.0

Published

Oodle Real User Monitoring SDK

Readme

@oodle-ai/rum

Real User Monitoring SDK for Oodle. Captures browser performance data, user sessions, errors, and session replay.

Install

npm install @oodle-ai/rum

Quick start

import { OodleRum } from '@oodle-ai/rum';

OodleRum.init({
  instanceId: '<OODLE_INSTANCE_ID>',
  apiKey: '<OODLE_RUM_API_KEY>',
  endpoint: 'https://<COLLECTOR_DOMAIN>',
  service: 'my-app',
  env: 'production',
  version: '1.0.0',
  sessionReplay: true,
  sessionSampleRate: 100,
  replaySampleRate: 100,
  privacyLevel: 'mask-user-input',
});

Enabling it per environment

Gate init() alone — the rest of the API is safe to call unconditionally from shared code:

if (import.meta.env.PROD) {
  OodleRum.init({ /* ... */ });
}

// No environment check needed here or at any other call site.
OodleRum.identify({ id: user.id });
OodleRum.trackEvent('checkout_completed');

Without init(), nothing is recorded and nothing is sent: trackEvent and flush do nothing, and getSessionId() returns ''. identify, setTags, and addFeatureFlag keep working, so state set before a later init() still applies once it runs — a setTags call takes precedence over the tags passed to init() on any key both set.

User identification

OodleRum.identify({
  id: 'user-123',
  name: 'Jane Doe',
  email: '[email protected]',
});

Custom events

OodleRum.trackEvent('checkout_completed', {
  orderId: '12345',
  total: 99.99,
});

Configuration

| Option | Type | Default | Description | |--------|------|---------|-------------| | instanceId | string | required | Oodle instance ID | | apiKey | string | required | RUM API key (write-only, safe for client-side) | | endpoint | string | required | Collector URL (must be HTTPS in production) | | service | string | required | Application name | | env | string | '' | Environment (e.g. production, staging) | | version | string | '' | Application version | | sessionReplay | boolean | true | Enable session replay recording | | sessionSampleRate | number | 100 | Percentage of sessions to track (0-100) | | replaySampleRate | number | 100 | Percentage of tracked sessions to record replay (0-100) | | privacyLevel | string | 'mask-user-input' | 'mask-user-input' masks password/email inputs; 'mask' masks all text and inputs; 'allow' masks nothing | | tags | object | undefined | Custom key-value tags attached to all events | | viewUrlQueryParams | string[] | undefined | Query parameter names to keep in view_url on every event (for example ['traceId']). All other parameters are dropped. See Privacy |

What's collected

  • Web Vitals — LCP, FID, CLS, INP, TTFB, FCP
  • Page views and navigation timing
  • JavaScript errors and unhandled rejections
  • Network requests — fetch and XHR with timing
  • User actions — clicks, rage clicks, dead clicks
  • Console errors
  • Session Replay — pixel-perfect DOM recordings

Privacy

The SDK removes the query string from view_url and referrer_url, because a query string can hold tokens or personal data. Two other places keep the full URL: resource_url on network request events, and the page URL that session replay records. Keep secrets out of URLs, or turn off sessionReplay for pages that have them in the URL.

To keep a parameter that only identifies page state, such as the ID of the record a page shows, list its name in viewUrlQueryParams:

  • Every event (views, actions, errors, resources, console) carries view_url, so every event keeps the listed parameters. view_url_path and referrer_url never contain a query string.
  • The SDK keeps the value of a listed parameter as it is. Do not list a parameter that can hold personal data or a token.
  • view_url gets one value for each record ID. To count or group views by page, use view_url_path.
  • Names match exactly and are case-sensitive.
  • The kept parameters are encoded again, so view_url can differ from the address bar (for example, %3A for : and + for a space). Decode the value before you compare it with an ID.
  • Parameters after # in hash-based routes are not kept.
  • A value that is not an array of strings is ignored, with a console warning.

The privacyLevel setting controls input masking in session replay:

  • 'mask-user-input' (default) — masks password and email fields
  • 'mask' — masks all text content and all input types
  • 'allow' — masks nothing

Excluding specific elements

privacyLevel applies to the whole page. To exclude individual elements, mark them in your markup. Both an attribute and a class are accepted for each level, so you can use whichever fits your templates:

<!-- Not recorded at all. The element and its subtree are replaced by an
     empty placeholder of the same size, so layout is preserved. -->
<div data-oodle-privacy="hidden">...</div>
<div class="oodle-privacy-hidden">...</div>

<!-- Recorded, but text is replaced with dots. Structure and styling are
     kept, so the replay still shows the shape of the page. -->
<span data-oodle-privacy="mask">[email protected]</span>
<span class="oodle-privacy-mask">...</span>

Use hidden when the element itself is sensitive, and mask when only its contents are. hidden is also the way to keep a subtree that is very large or mutates constantly (a canvas, a virtualized log view) out of the recording — the cost of recording it is skipped along with the content.

Marking works in both directions relative to privacyLevel: an element marked mask is masked even under 'allow', and unmarked elements still follow whatever the global level says.

rrweb's own class names work too, since the SDK leaves them at their defaults:

  • .rr-block — same effect as .oodle-privacy-hidden
  • .rr-mask — same effect as .oodle-privacy-mask
  • .rr-ignore — records the input element, but never its typed value

Elements are matched live, so toggling a class at runtime takes effect from the next DOM mutation onward. Content recorded before the class was added is already in the replay, so apply the marker before the sensitive value is rendered rather than after.

License

Apache-2.0