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

notificationkit-web

v0.1.4

Published

Web SDK for NotifyKit - push notifications, in-app messages, and user engagement

Readme

NotificationKit Web SDK

JavaScript/TypeScript SDK for NotificationKit — a self-hosted notification platform for web push, in-app messages, and user engagement.

Table of Contents


Installation

# npm
npm install notificationkit

# yarn
yarn add notificationkit

# pnpm
pnpm add notificationkit

CDN (Script Tag)

<script src="https://cdn.jsdelivr.net/npm/notificationkit/dist/notificationkit.umd.js"></script>

When loaded via CDN the SDK is available as the global NotificationKit.


Quick Start

import { NotificationKit } from 'notificationkit';

// 1. Initialize once on app load (no URL needed — it's built into the SDK)
NotificationKit.init({
  apiKey: 'YOUR_API_KEY',
});

// 2. Log in the current user
await NotificationKit.login('user-123');

// 3. Attach profile data
await NotificationKit.identify({
  email: '[email protected]',
  firstName: 'Jane',
  lastName: 'Doe',
});

// 4. Request push permission and opt in
const permission = await NotificationKit.Notifications.requestPermission();
if (permission === 'granted') {
  await NotificationKit.User.PushSubscription.optIn();
}

// 5. Track a custom event
await NotificationKit.track('purchase_completed', { plan: 'pro', amount: 49 });

Service Worker Setup

The SDK requires a service worker to receive web push notifications. Copy the bundled worker file into your public directory so it is served at the root of your site.

Copy the worker file:

# After installing the package
cp node_modules/notificationkit/dist/NotificationKitWorker.js public/NotificationKitWorker.js

By default the SDK registers the worker at /NotificationKitWorker.js. You can change this path with the serviceWorkerPath option:

NotificationKit.init({
  apiKey: 'YOUR_API_KEY',
  serviceWorkerPath: '/workers/NotificationKitWorker.js',
});

If you use a build tool (Vite, webpack, etc.) you can import the worker path directly from the package:

import workerUrl from 'notificationkit/worker';

The service worker must be served from the same origin as your page and from the scope you want to receive notifications in. Placing it at /NotificationKitWorker.js gives it full-site scope.


Web Push Notifications

Check Support

if (!NotificationKit.Notifications.isPushSupported()) {
  console.log('Push not supported in this browser');
}

Request Permission

const permission = await NotificationKit.Notifications.requestPermission();
// 'granted' | 'denied' | 'default'

Opt In / Opt Out

// Opt the current user into push
await NotificationKit.User.PushSubscription.optIn();

// Check current state
console.log(NotificationKit.User.PushSubscription.optedIn); // boolean
console.log(NotificationKit.User.PushSubscription.token);   // endpoint URL or null

// Opt out and remove the push subscription
await NotificationKit.User.PushSubscription.optOut();

Listen for Notification Clicks

NotificationKit.Notifications.addEventListener('click', (data) => {
  console.log('Notification clicked:', data);
});

Listen for Permission Changes

NotificationKit.Notifications.addEventListener('permissionChange', (permission) => {
  console.log('Permission changed to:', permission);
});

GDPR Consent

When operating under GDPR or similar regulations you can gate all network activity behind explicit user consent.

NotificationKit.init({
  apiKey: 'YOUR_API_KEY',
  requireConsent: true, // No network calls until consent is given
});

// After the user accepts your consent banner:
NotificationKit.setConsentGiven(true);

// To revoke consent:
NotificationKit.setConsentGiven(false);

// You can also change the requirement at runtime:
NotificationKit.setConsentRequired(false);

When requireConsent is true and consent has not been given, all HTTP requests are silently dropped until setConsentGiven(true) is called. Consent is persisted to localStorage so it survives page reloads.


API Reference

Core

NotificationKit.init(config)

Initialize the SDK. Must be called before any other method. Safe to call multiple times — subsequent calls are no-ops.

| Parameter | Type | Required | Default | Description | |---|---|---|---|---| | apiKey | string | Yes | — | Your NotificationKit API key | | serviceWorkerPath | string | No | '/NotificationKitWorker.js' | Path to the service worker file | | vapidPublicKey | string | No | — | VAPID public key for Web Push | | requireConsent | boolean | No | false | Block network calls until consent is given | | baseUrl | string | No | Built-in | Override the API base URL (only needed for self-hosting) |

NotificationKit.init({
  apiKey: 'nk_live_abc123',
  serviceWorkerPath: '/NotificationKitWorker.js',
  vapidPublicKey: 'BExample...',
  requireConsent: false,
});

NotificationKit.login(userId)Promise<string>

Associate the SDK with an authenticated user. Returns the internal NotificationKit user ID.

const nkId = await NotificationKit.login('user-123');

| Parameter | Type | Description | |---|---|---| | userId | string | Your application's user identifier |


NotificationKit.identify(options)Promise<void>

Update profile attributes for the current user. Requires login() to have been called first.

await NotificationKit.identify({
  email: '[email protected]',
  firstName: 'Jane',
  lastName: 'Doe',
  language: 'en',
  attributes: { plan: 'pro', companyId: 'acme' },
});

| Parameter | Type | Description | |---|---|---| | email | string? | User email address | | firstName | string? | First name | | lastName | string? | Last name | | language | string? | BCP-47 language tag (e.g. 'en', 'fr') | | attributes | Record<string, unknown>? | Arbitrary key-value pairs (reserved keys are ignored) |


NotificationKit.track(event, properties?)Promise<void>

Track a custom event for the current user. Also evaluates in-app message triggers.

await NotificationKit.track('video_played', { videoId: 'abc', duration: 120 });

| Parameter | Type | Description | |---|---|---| | event | string | Event name | | properties | Record<string, unknown>? | Optional event properties |


NotificationKit.logout()Promise<void>

Log out the current user, clear all persisted state, and broadcast the logout to all open tabs.

await NotificationKit.logout();

NotificationKit.setConsentRequired(required)

Toggle whether network calls require consent at runtime.

NotificationKit.setConsentRequired(true);

NotificationKit.setConsentGiven(given)

Grant or revoke user consent. Persisted to localStorage.

NotificationKit.setConsentGiven(true);

Read-only Getters

| Property | Type | Description | |---|---|---| | NotificationKit.userId | string \| null | Your application's user ID (set via login()) | | NotificationKit.nkUserId | string \| null | NotificationKit's internal user ID |


User Namespace

NotificationKit.User

Aliases

Aliases allow you to link multiple identifiers to the same user (e.g. a Stripe customer ID alongside your own user ID).

// Add a single alias
await NotificationKit.User.addAlias('stripe_id', 'cus_abc123');

// Add multiple aliases at once
await NotificationKit.User.addAliases({
  stripe_id: 'cus_abc123',
  intercom_id: 'user_xyz',
});

// Remove aliases
await NotificationKit.User.removeAlias('stripe_id');
await NotificationKit.User.removeAliases(['stripe_id', 'intercom_id']);

Email & SMS Subscriptions

// Email
await NotificationKit.User.addEmail('[email protected]');
await NotificationKit.User.removeEmail('[email protected]');

// SMS
await NotificationKit.User.addSms('+14155552671');
await NotificationKit.User.removeSms('+14155552671');

Language

await NotificationKit.User.setLanguage('fr');

Tags

Tags are key-value pairs used for segmentation and targeting.

// Add tags
await NotificationKit.User.addTag('plan', 'pro');
await NotificationKit.User.addTags({ plan: 'pro', region: 'us-west' });

// Remove tags
await NotificationKit.User.removeTag('plan');
await NotificationKit.User.removeTags(['plan', 'region']);

// Read cached tags (populated from login response, no network call)
const tags = NotificationKit.User.getTags();
// => { plan: 'pro', region: 'us-west' }

PushSubscription

const push = NotificationKit.User.PushSubscription;

push.optedIn  // boolean — whether the user is currently opted in
push.token    // string | null — the Web Push endpoint URL
push.id       // string | null — subscription ID

await push.optIn();   // subscribe to push
await push.optOut();  // unsubscribe from push

Change Events

NotificationKit.User.addEventListener('change', (state) => {
  console.log('User state changed:', state.nkUserId, state.externalId);
});

NotificationKit.User.removeEventListener('change', myCallback);

Notifications Namespace

NotificationKit.Notifications

| Member | Type | Description | |---|---|---| | permission | 'granted' \| 'denied' \| 'default' | Current browser notification permission | | isPushSupported() | () => boolean | Returns true if the browser supports Web Push | | requestPermission() | () => Promise<NotificationPermission> | Prompt the user for notification permission | | addEventListener('permissionChange', cb) | — | Fired when permission changes | | addEventListener('click', cb) | — | Fired when the user clicks a notification | | removeEventListener(event, cb) | — | Remove a previously registered listener |

// Check current permission without prompting
console.log(NotificationKit.Notifications.permission);

// Request permission
const result = await NotificationKit.Notifications.requestPermission();

// Listen for permission changes
NotificationKit.Notifications.addEventListener('permissionChange', (perm) => {
  if (perm === 'denied') console.warn('User denied notifications');
});

// Listen for notification clicks
NotificationKit.Notifications.addEventListener('click', (data) => {
  // data is the payload sent with the notification
  window.location.href = data.url;
});

Session Namespace

NotificationKit.Session

Outcomes measure meaningful user actions tied to a session.

| Method | Description | |---|---| | addOutcome(name) | Record an outcome (can fire multiple times) | | addUniqueOutcome(name) | Record an outcome only once per session | | addOutcomeWithValue(name, value) | Record an outcome with a numeric value |

// Track that the user converted
await NotificationKit.Session.addOutcome('conversion');

// Track a revenue outcome with a value
await NotificationKit.Session.addOutcomeWithValue('revenue', 49.99);

// Track a unique outcome (de-duplicated server-side)
await NotificationKit.Session.addUniqueOutcome('onboarding_completed');

InAppMessages Namespace

NotificationKit.InAppMessages

Pause / Resume

// Pause in-app message display (e.g. during a checkout flow)
NotificationKit.InAppMessages.paused = true;

// Resume
NotificationKit.InAppMessages.paused = false;

Triggers

Triggers allow you to show in-app messages based on user actions or state.

// Set a trigger — fires matching in-app messages immediately
NotificationKit.InAppMessages.addTrigger('onboarding_step', '2');

// Remove a trigger
NotificationKit.InAppMessages.removeTrigger('onboarding_step');

Events

// Before a message is shown
NotificationKit.InAppMessages.addEventListener('willDisplay', (message) => {
  console.log('About to display message:', message.id);
});

// When the user clicks a message action
NotificationKit.InAppMessages.addEventListener('click', (message) => {
  console.log('Message clicked:', message.id);
});

NotificationKit.InAppMessages.removeEventListener('willDisplay', myCallback);
NotificationKit.InAppMessages.removeEventListener('click', myCallback);

Debug Namespace

NotificationKit.Debug

Control the verbosity of SDK console output. The default log level is 'warn'.

| Level | Output | |---|---| | 'none' | Silent — no console output | | 'error' | Errors only | | 'warn' | Errors and warnings (default) | | 'info' | Errors, warnings, and info messages | | 'debug' | All output including verbose debug traces |

// Enable verbose logging during development
NotificationKit.Debug.setLogLevel('debug');

// Read the current level
const level = NotificationKit.Debug.getLogLevel(); // 'debug'

// Silence all SDK logs in production
NotificationKit.Debug.setLogLevel('none');

TypeScript

The SDK ships with full TypeScript definitions. No @types package is needed.

import {
  NotificationKit,
  NotificationKitError,
  type InitConfig,
  type IdentifyOptions,
  type UserState,
  type LogLevel,
} from 'notificationkit';

const config: InitConfig = {
  apiKey: 'nk_live_abc123',
  requireConsent: true,
};

NotificationKit.init(config);

NotificationKit.User.addEventListener('change', (state: UserState) => {
  console.log(state.nkUserId, state.externalId);
});

Exported types:

| Type | Description | |---|---| | InitConfig | Options accepted by NotificationKit.init() | | IdentifyOptions | Options accepted by NotificationKit.identify() | | UserState | Shape of the user change event payload | | LogLevel | 'none' \| 'error' \| 'warn' \| 'info' \| 'debug' | | NotificationKitError | Error class thrown by SDK methods |


Browser Support

The SDK targets modern evergreen browsers. Web Push requires additional platform support.

| Feature | Chrome | Firefox | Safari | Edge | |---|---|---|---|---| | Core SDK | 60+ | 60+ | 12+ | 79+ | | Web Push | 50+ | 44+ | 16.1+ (macOS/iOS) | 79+ | | Service Worker | 40+ | 44+ | 11.1+ | 17+ | | BroadcastChannel (multi-tab sync) | 54+ | 38+ | 15.4+ | 79+ |

iOS Safari supports Web Push from iOS 16.4+ when the web app is added to the home screen.


Error Handling

All async SDK methods can throw a NotificationKitError. The error includes a status property with the HTTP status code when the failure originates from a network request.

import { NotificationKit, NotificationKitError } from 'notificationkit';

try {
  await NotificationKit.login('user-123');
} catch (err) {
  if (err instanceof NotificationKitError) {
    console.error(`SDK error [${err.status}]: ${err.message}`);
  } else {
    throw err;
  }
}

Common errors:

| Message | Cause | |---|---| | NotificationKit not initialized. Call NotificationKit.init() first. | A method was called before init() | | No userId set. Call login() first. | A user-scoped method was called before login() |

Methods that communicate with the service worker (e.g. PushSubscription.optIn()) fail silently when the service worker is unavailable rather than throwing, so push functionality degrades gracefully without affecting the rest of the SDK.