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

avada-behavior-sdk

v0.2.6

Published

Node/browser SDK for emitting **Avada product behavior events** to the ingest pipeline (`POST /ingest/events`). Events are typed against the central event registry, batched client-side, and streamed into `avada_product_raw.{appId}_sdk_events`.

Readme

avada-behavior-sdk

Node/browser SDK for emitting Avada product behavior events to the ingest pipeline (POST /ingest/events). Events are typed against the central event registry, batched client-side, and streamed into avada_product_raw.{appId}_sdk_events.

npm i avada-behavior-sdk

Published publicly on npm as avada-behavior-sdk. Inside this monorepo, use the workspace package instead.

Prerequisite (Data Platform provisions once): an ingest API key and a shop-signing HMAC secret for your appId, minted at Admin → Behavior Keys (/admin/behavior-keys). Until the app is registered there, every event is rejected.


Quick start — Cloud Functions / Koa (recommended)

The simplest path. Import the serverless preset, give it your appId, done. It reads the standard env vars, signs every event, disables the background timer (Cloud Functions freeze between requests), flushes after each emit, and never throws — analytics can't break business logic.

import { createAvadaTracker } from "avada-behavior-sdk/serverless";

export const tracker = createAvadaTracker("ageVerification");

// Emit anything the app is allowed to emit — typed against the registry.
await tracker.track("installed", shopId, { plan_at_install: "free" });
await tracker.track("settings_updated", shopId, { changed_keys: ["theme"] });
await tracker.track("verification_submitted", shopId, { campaign_id, age: 21 });

That's the whole integration. No config file, no crypto, no HTTP wiring.

Required env

createAvadaTracker(appId) reads these — no options needed in the common case:

| Env var | Required | Purpose | |---|---|---| | BEHAVIOR_SDK_API_KEY | ✅ | Bearer ingest key. | | BEHAVIOR_SDK_SIGNING_SECRET | ✅ | Shop-signing HMAC secret (signs every event). | | APP_ENV | | Must be exactly production for prod routing; anything else (or unset) routes to the staging table. | | APP_VERSION | | Stamped as app_version (default 1.0.0). |

⚠️ If APP_ENV isn't production, events still send (HTTP 200) but land in ..._sdk_events_staging and never reach production analytics — the #1 cause of "events sent but missing." See Environment routing.

If either credential is missing, tracker.enabled is false and all emits are silent no-ops (safe in dev/CI).

tracker.track(eventName, shopId, props)

One uniform call for every event. eventName and props are type-checked against the registry; the tracker fills in shop_id, shop_signature, and occurred_at for you.

await tracker.track("feature_enabled", shopId, {
  feature_name: "auto_apply_rules",
  actor_type: "merchant_user",
});

Also exported from this entry:

  • createShopSignature(appId, shopId, occurredAt, secret) — the raw signer, byte-matched to the ingest verifier (use it if you sign elsewhere).
  • toNumber(value) — coerce request values to a finite number or undefined (handy for numeric props like mrr, age that arrive as strings).

Thin sugar over track — equivalent, use them or track directly, your call:

tracker.installed(shopId, props);              // → track("installed", …)
tracker.uninstalled(shopId, props);
tracker.subscriptionStarted(shopId, props);    // → track("subscription_started", …)
tracker.planChanged(shopId, props);
tracker.subscriptionCancelled(shopId, props);
tracker.featureToggled(shopId, { featureName, enabled });  // picks feature_enabled / feature_disabled
tracker.settingsUpdated(shopId, props);        // defaults changed_keys: [] + actor_type

Optional config (createAvadaTracker(appId, options))

Pass options only when you need to deviate. Any option overrides its env default (options.x ?? env), so you can use different env var names or hardcode values.

| Option | Default | Notes | |---|---|---| | apiKey | BEHAVIOR_SDK_API_KEY | Pass to read from a different env var. | | signingSecret | BEHAVIOR_SDK_SIGNING_SECRET | | | appVersion | APP_VERSION ?? "1.0.0" | | | environment | APP_ENV === "production" ? "production" : "staging" | Must be "production" \| "staging" \| "test". | | autoFlush | true | Flush after every emit. Set false + call tracker.flush() once at request end if a handler emits many events. | | endpoint | shared production ingest | Override for local/dev stacks. | | fetchImpl | global fetch | Inject for non-fetch runtimes / tests. | | logger | console | debug/warn/error. |

// Different env var names + environment driven by the app's own config:
export const tracker = createAvadaTracker("ageVerification", {
  apiKey: process.env.MY_BEHAVIOR_KEY,
  signingSecret: process.env.MY_BEHAVIOR_SECRET,
  environment: appConfig.isProduction ? "production" : "staging",
});

tracker also exposes enabled (boolean), flush(), and close().


Advanced — batching emits with autoFlush

The SDK never sends events one-by-one over the wire: track() puts an event in an in-memory buffer, and flush() POSTs the whole buffer as a single batch. autoFlush controls when that flush happens.

autoFlush: true (default) — flush after every track(), so one HTTP POST per event.

  • ✅ Reliable and zero-thought: on Cloud Functions the instance can freeze the moment your handler returns, so sending immediately guarantees the event isn't lost.
  • ➖ One network round-trip per emit adds latency to the response.

autoFlush: falsetrack() only buffers; you call tracker.flush() once to send everything in a single POST.

export const tracker = createAvadaTracker("ageVerification", { autoFlush: false });

// In a handler that emits several events:
await tracker.track("installed", shopId, { plan_at_install: "free" });
await tracker.track("feature_enabled", shopId, { feature_name: "x" });
await tracker.track("settings_updated", shopId, { changed_keys: ["theme"] });
await tracker.flush(); // ← one POST for all three, instead of three
  • ✅ Collapses N emits in one request into a single round-trip — less latency, fewer requests.
  • ➖ You must remember to flush(). If the instance freezes before you flush, the whole buffer is lost (the background timer is disabled in serverless, so it won't drain on its own).

Rule of thumb: keep the default true when handlers emit 0–1 events (the common case). Switch to false only for a handler that emits many events in one request, and flush once at the end.


Advanced — core client (createBehaviorClient)

For long-running servers or browser code, use the lower-level client directly. It buffers and flushes automatically on a timer (flushIntervalMs), so you don't flush per-event — but you sign shop_signature yourself and manage shutdown.

import { createBehaviorClient } from "avada-behavior-sdk";

const client = createBehaviorClient({
  appId: "orderLimit",
  apiKey: process.env.AVADA_BEHAVIOR_KEY!,
  appVersion: "2.14.0",
  environment: "production",
});

// Defaults merged into every subsequent event until overridden.
client.identify({
  shop_id: "123456",
  shop_signature: serverGeneratedShopSignature, // you generate this — see shop_signature
  shop_plan_at_event: "pro",
});

client.track("feature_enabled", {
  feature_name: "auto_apply_rules",
  actor_type: "merchant_user",
  source: "admin",
});

await client.flush(); // force-send buffered events now
await client.close(); // flush + stop the timer (call on shutdown)

Events are buffered and flushed automatically (by batchSize or flushIntervalMs); you only need flush()/close() for immediate delivery or graceful shutdown.

On Cloud Functions, prefer the serverless quick start — it sets flushIntervalMs: 0 and flushes per emit so events aren't lost when the instance freezes.

Full ClientOptions reference

| Option | Required | Default | Notes | |---|---|---|---| | appId | ✅ | — | Registry app id, e.g. orderLimit. | | apiKey | ✅ | — | Behavior ingest key for this app. | | appVersion | ✅ | — | Stamped onto every event as app_version. | | environment | ✅ | — | production | staging | test. Controls routing (see below). | | endpoint | | https://analytics.avada.net/ingest/events | Override for local/dev stacks. | | batchSize | | 50 | Auto-flush once this many events are buffered. | | flushIntervalMs | | 5000 | Periodic flush timer; 0 disables it. | | maxBufferSize | | 1000 | Oldest events are dropped past this (overflow → onError). | | maxRetries | | 5 | Per-batch retry attempts before dropping. | | retryBaseDelayMs | | 100 | Base for exponential backoff. | | maxEventBytes | | 65536 | Single events larger than this are rejected. | | maxBatchBytes | | 524288 | Batch JSON byte ceiling. | | onError / onFlush | | — | Observability hooks. | | logger | | console | debug/warn/error. | | fetchImpl | | global fetch | Inject for non-fetch runtimes/tests. |


Environment routing

The SDK stamps environment into event_properties and the ingest service routes by it:

  • productionavada_product_raw.{appId}_sdk_events (feeds the canonical avada_product_behavior.events ETL).
  • anything else (staging, test, or absent) → avada_product_raw.{appId}_sdk_events_staging, which never reaches production analytics.

So non-prod traffic can be inspected in isolation — just point the staging build at the staging table.

shop_signature

Every event carrying a shop_id must be signed with the app's HMAC secret over the tuple (app_id, shop_id, occurred_at)v1=HMAC-SHA256(...). The ingest verifier rejects mismatches with 403.

  • Serverless preset: signs automatically — you never touch it.
  • Core client: you generate the signature on your backend (use the exported createShopSignature from avada-behavior-sdk/serverless) and pass it via identify({ shop_signature }) or per-event props. Never put the secret in frontend code; the SDK only transports the signature.

What the SDK does and doesn't do

  • Auto-stamps app_version, sdk_version (kept in lockstep with package.json via codegen — src/generated/version.ts), and environment onto every event.
  • Generates a per-event ULID source_doc_id used for idempotency/dedup across retries.
  • Never writes directly to avada_product_behavior.events.
  • Never sends retention_class — the ingest service derives it from config/events/registry.yaml.

Related

This is the front-of-app behavior lane. For backend-only ingestion of records that already exist in an app's own system (e.g. a resolved support conversation), use the separate source-events lane instead — see docs/data-platform/behavior-sdk/source-events-ingest-guide.md.