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

@pulsealarm/pulse-event-sdk

v0.1.9

Published

Non-blocking event/error SDK for browser and Node.js

Readme

Pulse Event SDK (JavaScript)

Framework-agnostic, non-blocking event and error tracking SDK for:

  • Browser apps
  • Node.js services
  • React / Vue
  • Express / Fastify
  • Next.js / Nuxt

Features

  • Non-blocking event delivery (queue + background flush)
  • Token-based authentication (/event/:token)
  • Server-to-server secret key support (X-Pulse-Secret-Key header)
  • Manual custom event tracking
  • Built-in page view tracking (pageView)
  • Manual exception capture (captureException, captureError)
  • Global runtime error handlers (browser + Node.js)
  • Automatic session_id generation
  • Batched sending with configurable batch size
  • Queue overflow protection with callback
  • Retry with configurable max retries
  • Lightweight adapters for modern frameworks
  • TypeScript support
  • Fully tested

Installation

npm install @pulsealarm/pulse-event-sdk

Browser (No Bundler / CDN)

If you are not using a bundler (Vite, webpack, etc.), load the SDK directly from a CDN with a plain <script> tag. No build step or import required.

<!-- jsDelivr (recommended) -->
<script src="https://cdn.jsdelivr.net/npm/@pulsealarm/pulse-event-sdk/dist/pulse.min.js"></script>

<!-- or unpkg -->
<script src="https://unpkg.com/@pulsealarm/pulse-event-sdk/dist/pulse.min.js"></script>

<script>
  const pulse = new Pulse.PulseClient({
    token: "your_webhook_token_here",
    autoPageView: true,
    defaults: {
      environment: "production",
      platform: "web"
    }
  });

  pulse.installGlobalHandlers();

  // Manual page view
  pulse.pageView();

  // Custom event
  pulse.track({
    title: "Payment failed",
    level: "error",
    type: "exception",
    customer_id: "cust_456"
  });
</script>

The SDK is exposed as window.Pulse. All exports are accessible under the Pulse namespace:

| Export | Usage | |--------|-------| | Pulse.PulseClient | new Pulse.PulseClient({ token }) | | Pulse.createPulseClient | Pulse.createPulseClient({ token }) |

Tip: For bundler-based projects (Vite, webpack, Next.js, etc.), use npm install above — tree-shaking and TypeScript types are included automatically.

Quick Start

Browser

import { createPulseClient } from "@pulsealarm/pulse-event-sdk";

const pulse = createPulseClient({
  token: "your_webhook_token_here",
  autoPageView: true,
  defaults: {
    environment: "production",
    app_version: "2.3.1",
    platform: "web"
  }
});

pulse.installGlobalHandlers();

pulse.track({
  title: "Payment failed for order #1234",
  description: "Stripe returned card_declined error during checkout",
  level: "error",
  type: "exception",
  data: {
    stack_trace: "Error: card_declined\n  at processPayment (checkout.js:42)",
    any_key: "any_value"
  },
  session_id: "sess_abc123",
  customer_id: "cust_456",
  ip_address: "203.0.113.10",
  tags: ["payment", "critical-path"],
  revenue: { currency: "USD", price: 49.99 }
});

Node.js

import { createPulseClient } from "@pulsealarm/pulse-event-sdk";

const pulse = createPulseClient({
  token: "your_webhook_token_here",
  secretKey: "sk_your_secret_key",   // required for server-to-server
  defaults: {
    platform: "server",
    environment: "production"
  }
});

pulse.installGlobalHandlers();
pulse.event("worker.started");

process.on("SIGTERM", () => {
  pulse.close();
  process.exit(0);
});

Authentication

Browser (Client-side)

Only token is needed. Domain validation is handled on the server.

const pulse = createPulseClient({
  token: "your_webhook_token_here"
});

Server-to-Server

Requires secretKey in addition to token. The SDK sends it as X-Pulse-Secret-Key header.

const pulse = createPulseClient({
  token: "your_webhook_token_here",
  secretKey: "sk_your_secret_key"
});

Endpoints

The SDK automatically builds endpoint URLs from the token:

| Type | URL Pattern | |------|------------| | Event | https://pulsealarm.dev/event/:token | | Page View | https://pulsealarm.dev/page-view/:token |

Custom base URL:

const pulse = createPulseClient({
  token: "your_token",
  baseUrl: "https://your-self-hosted-domain.com"
});
// → https://your-self-hosted-domain.com/event/your_token
// → https://your-self-hosted-domain.com/page-view/your_token

You can also pass a fully custom endpoint:

const pulse = createPulseClient({
  endpoint: "https://custom-domain.com/my-ingest"
});

Runtime Token Updates

// Update token (and optionally secretKey) at runtime
pulse.setToken("new_token", "new_secret_key");

// Update just the endpoint URL
pulse.setEndpoint("https://custom-domain.com/event/new_token");

Session Tracking

  • If session_id is not provided, SDK auto-generates sess_*.
  • In browsers, session ID is persisted in both cookie (pulse_sdk_session_id) and sessionStorage.
  • Priority: explicit session_id > cookie > sessionStorage > generated value.
console.log(pulse.getSessionId()); // "sess_a1b2c3d4..."

Custom Event Tracking

// Simple event
pulse.event("checkout.step.completed", {
  level: "info",
  tags: ["checkout"]
});

// Full track with all fields
pulse.track({
  title: "Order placed",
  level: "info",
  type: "event",
  customer_id: "cust_456",
  revenue: { currency: "USD", price: 99.99 },
  tags: ["orders"]
});

In browser runtime, track() auto-fills these fields when missing:

  • request_url
  • duration
  • data.referrer
  • data.user_agent

If you provide them explicitly, your values override SDK defaults.

Exception Capture

try {
  doPayment();
} catch (error) {
  pulse.captureException(error, {
    tags: ["payment"],
    customer_id: "cust_456",
    data: { order_id: "ord_123" }
  });
}

captureException automatically extracts:

  • title from error message
  • stack_trace into data.stack_trace
  • platform as "web" (browser) or "server" (Node.js)
  • type as "exception", level as "error"

Page View Tracking

pageView() sends data to the dedicated /page-view/:token endpoint.

Auto-filled fields (when available in browser):

  • url — current page URL
  • duration — page load time (Navigation Timing API)
  • session_id — from SDK session
  • referrer — document referrer
  • user_agent — navigator user agent
  • timestamp — ISO-8601
// Automatic (uses browser APIs)
pulse.pageView();

// With overrides
pulse.pageView({
  url: "https://myapp.com/checkout",
  duration: 1200,
  customer_id: "cust_456",
  ip_address: "203.0.113.10"
});

Auto page view on load:

const pulse = createPulseClient({
  token: "your_token",
  autoPageView: true
});

Global Error Handlers

pulse.installGlobalHandlers();
  • Browser: error and unhandledrejection events
  • Node.js: uncaughtException and unhandledRejection events

Selective:

pulse.installGlobalHandlers({
  browser: true,
  node: false,
  uncaughtException: true,
  unhandledRejection: true
});

Queue & Stats

const stats = pulse.getStats();
// { sent: 42, failed: 1, dropped: 0, queued: 3 }

Queue overflow callback:

const pulse = createPulseClient({
  token: "your_token",
  maxQueueSize: 500,
  onQueueOverflow: (totalDropped) => {
    console.warn(`${totalDropped} events dropped due to queue overflow`);
  }
});

Configuration Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | token | string | — | Webhook token (used in URL: /event/:token) | | secretKey | string | null | Server secret key (sent as X-Pulse-Secret-Key header) | | endpoint | string | — | Custom endpoint URL (overrides token) | | baseUrl | string | https://pulsealarm.dev | Base URL for endpoint building | | defaults | object | {} | Default fields merged into every event | | flushIntervalMs | number | 1000 | Background flush interval | | maxQueueSize | number | 500 | Max queue size before dropping oldest | | maxRetries | number | 2 | Retry count for failed sends | | batchSize | number | 10 | Events sent per flush cycle | | timeoutMs | number | 10000 | HTTP request timeout | | autoPageView | boolean | false | Auto-send page view on load | | enableBrowserContext | boolean | false | Add browser context to events | | onError | function | — | Error callback (error, context) => {} | | onQueueOverflow | function | — | Queue overflow callback (totalDropped) => {} | | debug | boolean | false | Enable debug logging |

React Integration

import { usePulse, PulseErrorBoundary, withPulseErrorBoundary } from "@pulsealarm/pulse-event-sdk/react";

// Hook
const pulse = usePulse({ token: "your_token" });

// Error Boundary
<PulseErrorBoundary pulse={pulse} fallback={<div>Something went wrong</div>}>
  <App />
</PulseErrorBoundary>

// HOC
const SafeCheckout = withPulseErrorBoundary(Checkout, { pulse });

Vue Integration

import { createPulseVuePlugin } from "@pulsealarm/pulse-event-sdk/vue";

app.use(
  createPulseVuePlugin({
    token: "your_token",
    defaults: { platform: "web", environment: "production" }
  })
);

The plugin also configures app.config.errorHandler automatically.

Express Integration

import { createPulseClient } from "@pulsealarm/pulse-event-sdk";
import {
  createExpressPulseRequestMiddleware,
  createExpressPulseErrorMiddleware
} from "@pulsealarm/pulse-event-sdk/express";

const pulse = createPulseClient({
  token: "your_token",
  secretKey: "sk_your_secret_key"
});

app.use(createExpressPulseRequestMiddleware(pulse));
// ... your routes
app.use(createExpressPulseErrorMiddleware(pulse));

Fastify Integration

import { createFastifyPulsePlugin } from "@pulsealarm/pulse-event-sdk/fastify";

await fastify.register(createFastifyPulsePlugin(pulse));

Next.js Integration

Pages Router API handler:

import { withPulseApiHandler } from "@pulsealarm/pulse-event-sdk/next";

export default withPulseApiHandler(async function handler(req, res) {
  // your handler
}, pulse);

App Router route handler:

import { withPulseRouteHandler } from "@pulsealarm/pulse-event-sdk/next";

export const POST = withPulseRouteHandler(async function POST(request) {
  // your handler
}, pulse);

Nuxt Integration

import { createNuxtPulsePlugin } from "@pulsealarm/pulse-event-sdk/nuxt";

export default defineNuxtPlugin((nuxtApp) => {
  createNuxtPulsePlugin(pulse)(nuxtApp);
});

Event Payload Schema

| Field | Type | Required | Description | |-------|------|----------|-------------| | title | string | Yes | Event title | | description | string | No | Detailed description | | level | string | No | Dynamic value from API (must be non-empty) | | type | string | No | Dynamic value from API (must be non-empty) | | timestamp | string | No | ISO-8601 timestamp | | data | object | No | Custom key-value data | | session_id | string | No | Session identifier | | customer_id | string | No | Customer identifier | | ip_address | string | No | Client IP address | | request_url | string | No | Request URL | | duration | number | No | Duration in milliseconds | | country_code | string | No | ISO-2 country code (e.g. TR) | | tags | string[] | No | Tags for categorization | | revenue | object | No | { currency: "USD", price: 49.99 } | | group | boolean | No | Enable deduplication grouping | | resolved | boolean | No | Mark as resolved | | environment | string | No | production, staging, development, test | | app_version | string | No | Application version | | platform | string | No | web, ios, android, server, desktop |

Page View Payload Schema

| Field | Type | Required | Description | |-------|------|----------|-------------| | url | string | Yes | Page URL | | duration | number | No | Load time in milliseconds | | session_id | string | No | Session identifier | | customer_id | string | No | Customer identifier | | timestamp | string | No | ISO-8601 timestamp | | ip_address | string | No | Client IP address | | referrer | string | No | Referring URL | | user_agent | string | No | Browser user agent |

Testing

npm test

CLI Quick Test

TOKEN="your_webhook_token_here"
BASE_URL="https://pulsealarm.dev"

curl -X POST "${BASE_URL}/event/${TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{"title":"CLI test event","level":"info"}'

With secret key (server-to-server):

curl -X POST "${BASE_URL}/event/${TOKEN}" \
  -H "Content-Type: application/json" \
  -H "X-Pulse-Secret-Key: sk_your_secret_key" \
  -d '{"title":"Server test event","level":"info"}'

Notes

  • track() is non-blocking: events go to queue, then flush in background.
  • Events are sent in batches (default: 10 per flush cycle).
  • Browser attempts best-effort flush via sendBeacon on page exit/hidden state.
  • In Node.js, call pulse.close() before shutdown for clean flush.
  • Failed sends are retried up to maxRetries times before being dropped.