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

onbored-js

v0.1.0-alpha.9

Published

SDK for OnBored

Readme

Onbored JS SDK

Stop churn in the first 2 weeks. Funnel tracking + session replay for onboarding flows.

npm version License: MIT

Account-first analytics. Buffer events pre-auth, flush on identify. Session replay with privacy controls. Built for B2B SaaS.


Install

npm i onbored-js

Quick Start

Vanilla JS

import { onbored } from 'onbored-js';

onbored.init({ projectKey: 'pk_live_...' });
onbored.identifyAccount('acct_123', { plan: 'enterprise' });
onbored.funnel('onboarding');
onbored.step('profile-setup', { slug: 'onboarding' });
onbored.complete({ slug: 'onboarding' });

React

import { OnboredProvider, useFunnel } from 'onbored-js/react';

function App() {
  return (
    <OnboredProvider config={{ projectKey: 'pk_live_...', accountId: 'acct_123' }}>
      <OnboardingFlow />
    </OnboredProvider>
  );
}

function OnboardingFlow() {
  const { step, complete } = useFunnel('onboarding');
  return (
    <button onClick={() => step('setup').then(complete)}>
      Done
    </button>
    );
}

Events appear at onbored.io instantly.


Core Concepts

Account-First Architecture Events buffer until identifyAccount() called. Required for B2B multi-tenant tracking.

Funnels Conversion journeys (e.g., onboarding, checkout). Each gets UUID flow ID.

onbored.funnel('signup', { source: 'landing' }); // Returns flow ID

Steps Milestones within funnels. Track completions or skips.

onbored.step('email-verified', { slug: 'signup', method: 'magic-link' });
onbored.skip('team-setup', { slug: 'signup', reason: 'solo' });

Sessions Auto-managed. 30min timeout. Persists in localStorage. Rotates on account switch.


API

onbored.init(config)

Initialize SDK. Call before other methods.

| Option | Type | Description | Required | |--------|------|-------------|----------| | projectKey | string | Project key | ✓ | | accountId | string | Account identifier | | | accountTraits | object | Account metadata | | | userId | string | User identifier | | | userTraits | object | User metadata | | | debug | boolean | Console logging | | | env | string | Skip API calls | | | sessionReplay | object | See Session Replay section | |

onbored.identifyAccount(accountId, traits?)

Identify account. Flushes buffered events. Rotates session on change.

onbored.identifyAccount('acct_789', { plan: 'enterprise', seats: 50 });

onbored.identify(userId, traits?)

Identify user. Optional. Merges traits.

onbored.identify('user_101', { email: '[email protected]', role: 'admin' });

onbored.funnel(slug, metadata?)

Start funnel. Returns flow ID (UUID).

onbored.funnel('signup', { source: 'google' });

onbored.step(stepName, options)

Track step completion.

onbored.step('email-verified', { slug: 'signup', method: 'link' });

onbored.skip(stepName, options)

Track step skip.

onbored.skip('team-invite', { slug: 'signup', reason: 'solo' });

onbored.complete(options)

Complete funnel. Flushes immediately.

onbored.complete({ slug: 'signup', duration: 420 });

onbored.capture(eventType, data)

Custom events.

onbored.capture('feature_used', { feature: 'export', format: 'csv' });

onbored.reset()

Logout. Clears session + stops replay.

onbored.reset();

onbored.destroy()

Cleanup. Removes listeners.

onbored.destroy();

React

<OnboredProvider>

Initializes SDK. Client-side only (use 'use client' in Next.js App Router).

import { OnboredProvider } from 'onbored-js/react';

<OnboredProvider config={{ projectKey: 'pk_live_...', accountId: 'acct_123' }}>
  <App />
</OnboredProvider>

Next.js App Router

// app/providers.tsx
'use client';
import { OnboredProvider } from 'onbored-js/react';

export function Providers({ children }) {
  return (
    <OnboredProvider config={{ projectKey: 'pk_...', accountId: 'acct_...' }}>
      {children}
    </OnboredProvider>
  );
}

// app/layout.tsx
import { Providers } from './providers';
export default function RootLayout({ children }) {
  return <html><body><Providers>{children}</Providers></body></html>;
}

useFunnel(slug)

Auto-starts funnel on mount. Returns { step, skip, complete }.

import { useFunnel } from 'onbored-js/react';

function Wizard() {
  const { step, complete } = useFunnel('onboarding');
  return <button onClick={() => step('done').then(complete)}>Finish</button>;
}

Session Replay

Record user sessions. GDPR-friendly. Gzip compression. Auto-pause on idle.

Enable

onbored.init({
  projectKey: 'pk_...',
  sessionReplay: {
    apiHost: 'https://api.onbored.com',
    flushInterval: 10000,              // Default: 10s
    maskInputs: true,                  // Default: true
    maskInputOptions: {
      password: true,                  // Always masked
      email: true,                     // Always masked
      tel: true,                       // Always masked
      text: false,                     // Configurable
    },
    blockElements: ['.cc-form'],       // CSS selectors
    privateSelectors: ['[data-ssn]'],  // Additional privacy
  },
});

Privacy Defaults

Auto-masked inputs: password, email, tel Auto-blocked elements: [data-private], [data-sensitive], .private, .sensitive, .ssn, .credit-card

Flush Triggers

  • Size: >900KB
  • Event count: >100
  • Time: Every 10s (configurable)
  • Page hidden
  • Session stop

Account Rotation

On identifyAccount() call:

  1. Stop current recording
  2. Rotate session
  3. Restart with new account context
  4. Emit replay_stopped + replay_started

Advanced

Custom Storage

onbored.init({
  projectKey: 'pk_...',
  storage: {
    sessionStorageKey: 'custom-session',
    activityStorageKey: 'custom-activity',
    flowContextStorageKey: 'custom-flow',
  },
});

Custom Headers

onbored.init({
  projectKey: 'pk_...',
  global: { headers: { Authorization: 'Bearer token' } },
});

Development Mode

No API calls. Console logging. Manual flush via window.__onboredFlush().

onbored.init({ projectKey: 'pk_...', env: 'development', debug: true });

TypeScript

Full type definitions included.

import type { OnboredClientOptions, EventPayload } from 'onbored-js';

Examples

B2B SaaS Onboarding

import { OnboredProvider, useFunnel } from 'onbored-js/react';

<OnboredProvider config={{
  projectKey: 'pk_...',
  accountId: org.id,
  accountTraits: { plan: org.plan, seats: org.seats },
  userId: user.id,
  sessionReplay: { apiHost: 'https://api.onbored.com' },
}}>
  <Wizard />
</OnboredProvider>

function Wizard() {
  const { step, skip, complete } = useFunnel('setup');
  return (
    <>
      <button onClick={() => step('profile')}>Profile</button>
      <button onClick={() => skip('team', { reason: 'solo' })}>Skip Team</button>
      <button onClick={() => complete()}>Done</button>
    </>
  );
}

Pre-Auth Flow

// Before user authenticates
onbored.init({ projectKey: 'pk_...' });
onbored.funnel('signup');                    // Buffered
onbored.step('email-entered', { slug: 'signup' }); // Buffered

// After auth
onbored.identifyAccount('acct_123');         // Flushes buffered events
onbored.step('verified', { slug: 'signup' });
onbored.complete({ slug: 'signup' });

Auto-Tracking

<div data-onbored-step="welcome" data-onbored-funnel="onboarding">
  Welcome! (tracked via IntersectionObserver at 50% visibility)
</div>

Architecture

Queue Strategy

  • In-memory queue: 5s flush or 100 events
  • Retry: Exponential backoff, max 5 attempts
  • Unload: sendBeacon() fallback
  • Complete: Immediate flush

Session Management

  • 30min timeout
  • UUID-based, localStorage
  • Auto-rotation on account switch
  • Page navigation tracked (SPA support)

Funnel Context

  • UUID flow ID per funnel
  • sessionStorage persistence
  • Auto page view tracking
  • IntersectionObserver for step views (50% threshold)

Troubleshooting

Events not appearing

  • Check env: 'production' (dev mode skips API)
  • Verify projectKey at onbored.io
  • Enable debug: true, check console
  • Network tab: Look for /ingest/events

React hook errors

  • Ensure <OnboredProvider> wraps components
  • Use 'use client' in Next.js App Router

Session not persisting

  • Check localStorage availability
  • Incognito mode may block storage

Funnel context lost

  • sessionStorage required
  • Same projectKey across pages
  • Call funnel() before navigation

Development

git clone https://github.com/MohamedH1998/onbored-js.git && cd onbored-js
pnpm install
pnpm dev        # Watch mode
pnpm test       # Unit tests
pnpm test:e2e   # E2E (Playwright)
pnpm build      # Build for production

Releases: Changesets + GitHub Actions

  1. pnpm changeset → describe change
  2. Commit changeset file
  3. Merge to main → auto-publish to npm

Pre-release stages: alpha → beta → rc → stable (currently alpha)


Links

WebsitenpmGitHubIssues

Support: [email protected]@momito

MIT © Onbored