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

zelto-sdk

v0.3.0

Published

zelto-sdk – Isomorphic TypeScript/JavaScript SDK for Zelto ai-platform analytics (events, identify, auto-capture)

Readme

zelto-sdk

Isomorphic TypeScript/JavaScript SDK for the Zelto ai-platform analytics backend. Use the same zelto.init, zelto.track, and zelto.identify API in browser and Node.

Install

npm install zelto-sdk
# or
pnpm add zelto-sdk
# or
yarn add zelto-sdk

Quick start

import { zelto } from 'zelto-sdk';

zelto.init({ apiKey: 'your_api_key' });

zelto.track('button_clicked', { button_id: 'signup', page: 'home' });

// Optional: identify user (e.g. after login)
zelto.identify('anonymous-uuid-from-cookie', 'user_123', { email: '[email protected]' });

Implementing in a new project

1. Call init once at startup

Initialize the SDK once before any track or identify calls. Do not call init on every request or on every component render.

Browser (SPA / static site) Call init in your app entry (e.g. main.tsx, App.tsx, or the script that runs first).

// src/main.tsx (React) or equivalent
import { zelto } from 'zelto-sdk';

zelto.init({
  apiKey: import.meta.env.VITE_ZELTO_API_KEY, // or process.env.NEXT_PUBLIC_ZELTO_API_KEY, etc.
  capturePageViews: true,   // optional: send page_view on first load
  captureClicks: true,      // optional: auto-track link/button clicks
});

Node (server / API) Call init when your process starts (e.g. top-level in your server file or after config is loaded).

// server/index.ts
import { zelto } from 'zelto-sdk';

zelto.init({
  apiKey: process.env.ZELTO_API_KEY!,
  baseUrl: process.env.ZELTO_BASE_URL, // optional; defaults to production
  userAgent: 'MyApp/1.0',
});

Using environment variables

  • Browser: Use your bundler’s env (e.g. VITE_*, NEXT_PUBLIC_*) so the API key is inlined at build time. Never commit secrets; use a build-time or runtime config from your backend if you need to hide the key.
  • Node: Use process.env.ZELTO_API_KEY (or similar) and set it in your environment or .env file.

2. Track custom events with track

Use track for any custom event (e.g. form submit, feature use, signup).

import { zelto } from 'zelto-sdk';

zelto.track('signup_completed', { plan: 'pro', source: 'pricing_page' });
zelto.track('article_viewed', { article_id: '123', title: 'Getting started' });
  • Property types: Only string, number, and boolean are supported. Values are stringified before send.
  • Context: In the browser, page_url, page_path, referrer, and user_agent are added automatically. In Node, only user_agent is added if you pass it in init.

3. Identify users (optional)

Call identify when you know who the user is (e.g. after login). Pass the same distinctId you used for anonymous events (e.g. from a cookie or from the SDK’s stored ID) and your internal userId.

Browser: The SDK stores a stable distinct_id in localStorage under zelto_track_distinct_id. To link anonymous activity to a known user:

  1. After login, read the current distinct ID (e.g. from your own cookie that you set from the same value, or by calling init and then using your stored anonymous ID).
  2. Call identify(anonymousDistinctId, loggedInUserId, { email, name, ... }).
// After successful login
import { zelto } from 'zelto-sdk';

const anonymousId = getStoredAnonymousId(); // e.g. from cookie or your own storage
zelto.identify(anonymousId, user.id, { email: user.email, name: user.name });

Node: There is no persistent distinct ID; each process gets an in-memory UUID. For server-side events, pass a stable identifier (e.g. session ID or user ID) as distinctId and optionally userId.

4. Flush before exit (recommended)

Events are batched and sent on a timer or when the queue reaches batchSize. To avoid losing events on page close or process exit, call flush() and await it.

Browser (page unload):

import { zelto } from 'zelto-sdk';

window.addEventListener('beforeunload', () => {
  zelto.flush(); // fire-and-forget; best-effort
});
// Or use sendBeacon in the future if the SDK supports it

Node (graceful shutdown):

import { zelto } from 'zelto-sdk';

process.on('beforeExit', async () => {
  await zelto.flush();
});

5. SPA / client-side routing

The SDK does not listen to history or hash changes. For single-page apps, send a page_view on each route change yourself:

// Example: React Router
import { zelto } from 'zelto-sdk';

// In your router or layout
useEffect(() => {
  zelto.track('page_view', {
    page_path: location.pathname,
    page_url: location.href,
    referrer: document.referrer || undefined,
  });
}, [location.pathname]);

You can still use capturePageViews: true for the initial load; then use zelto.track('page_view', ...) only for subsequent route changes.

6. Framework-specific tips

  • Next.js (App Router): Call init in a root layout or a client component that mounts once. Use NEXT_PUBLIC_ZELTO_API_KEY for client-side init. For server components or API routes, call init at server startup and use track in server code with appropriate distinct/user IDs.
  • Vite / CRA: Call init in main.tsx; use import.meta.env.VITE_ZELTO_API_KEY or process.env.REACT_APP_ZELTO_API_KEY.
  • Node/Express: Call init once when the app starts. Use track in route handlers or middleware; pass a request-scoped distinct ID (e.g. from session or cookie) if you need to attribute server events to a user.

API reference

init(options)

Initialize the SDK once before using track or identify. Throws if apiKey is missing.

| Option | Type | Default | Description | |--------|------|---------|-------------| | apiKey | string | required | API key; org is derived server-side. | | baseUrl | string | https://app.zelto.ai/api/v1 | Base URL for events and identify. | | capturePageViews | boolean | false | (Browser) Send a page_view event on initial load. | | captureClicks | boolean \| { selector?: string } | false | (Browser) Capture clicks on links/buttons via delegation. | | batchSize | number | 10 | Flush when queue reaches this size (max 1000). | | flushIntervalMs | number | 5000 | Flush at most every N ms. | | userAgent | string | — | (Node) Optional user-agent string for events. |

  • SPA page views: For single-page apps, call track('page_view', { page_path: '...' }) in your router on route change; the SDK does not listen to history by default.
  • Custom click selector: Use captureClicks: { selector: '.my-cta, [data-track]' } to limit which elements are tracked. Default selector: a, button, [role="button"], input[type="submit"], input[type="button"].

track(eventName, properties?)

Enqueue a custom event. Events are batched and sent to POST {baseUrl}/analytics/events.

  • eventName: string (e.g. 'button_clicked', 'signup_completed').
  • properties: optional object. Only string, number, and boolean values are supported; they are stringified before send.

Context added automatically when available: page_url, page_path, referrer, user_agent, plus distinct_id and optional user_id from the current identity.

flush(): Promise<void>

Send all pending events in the queue. Resolves when the queue is empty. Use before page unload or process exit for graceful shutdown (e.g. window.addEventListener('beforeunload', () => flush()) or process.on('beforeExit', async () => { await flush(); })).

identify(distinctId, userId?, properties?)

Send user identity to POST {baseUrl}/analytics/users/identify and set in-memory identity for subsequent events. Fire-and-forget; does not block.

  • distinctId: stable anonymous device/session ID (e.g. from cookie or SDK’s stored ID).
  • userId: optional logged-in user ID from your system.
  • properties: optional traits (e.g. email, name). Can be any JSON-serializable values for identify; event properties remain string/number/boolean.

Browser: A stable distinct_id is generated and stored in localStorage under zelto_track_distinct_id (with in-memory fallback when storage is unavailable). Subsequent events use this ID until you call identify with a different one.

Node: A UUID is generated per process and kept in memory only.


Auto-capture (browser)

When capturePageViews: true, the SDK sends a single page_view event on initial load with page_url, page_path, and referrer.

When captureClicks: true (or captureClicks: { selector: '...' }), the SDK uses event delegation to send element_clicked events for matching elements. Each event includes:

  • element – tag name (e.g. a, button)
  • id – element id if set
  • text – trimmed text content (truncated to 200 chars)
  • href – for <a>, the href value

Use a custom selector to restrict which elements are tracked.


Reliability and retries

  • Events are sent in batches. On network or server errors, the SDK retries 429 and 5xx with exponential backoff (up to 3 attempts by default). 4xx (other than 429) are not retried.
  • Failed batches are re-queued and sent on the next flush (by timer or flush()). Call flush() on page unload or process exit to reduce the chance of losing events.

Builds

  • ESM: import { zelto } from 'zelto-sdk' then zelto.init(), zelto.track(), etc.
  • CJS: const { zelto } = require('zelto-sdk') then zelto.init(), zelto.track(), etc.
  • TypeScript declarations are included.

License

MIT