npm.io
0.2.2 • Published 16h ago

abmeter

Licence
MIT
Version
0.2.2
Deps
0
Size
196 kB
Vulns
0
Weekly
0

ABMeter JavaScript SDK

ABMeter is a feature-flag and A/B-testing platform. You define parameters, experiments, and feature flags in the ABMeter Lab; this package reads the value assigned to each visitor in the browser and reports exposures and events back.

Unlike server-side SDKs, the browser never receives assignment rules, salts, or audience definitions. The SDK asks the ABMeter API for pre-evaluated assignments for the current user (POST /api/v1/user-assignments) and caches the resulting value map. Reading a value is a synchronous map lookup; an exposure is reported only when a value is actually read.

Install

npm install abmeter

Or from the CDN (exposes window.abmeter):

<script src="https://cdn.jsdelivr.net/npm/abmeter@0.2/dist/abmeter.iife.min.js"></script>

@0.2 is a range: it picks up patch releases on its own. Pin the exact version (abmeter@0.2.2) before production — a range still lets a release you did not deploy reach your site, and only an exact version is served immutable. Avoid the version-less form npm/abmeter/dist/... entirely: it follows every release, breaking ones included. unpkg serves the same file at the same paths.

Quick start

import * as abmeter from 'abmeter';

abmeter.configure({
  apiKey: 'YOUR_API_KEY',
  baseUrl: 'https://abmeter.ai',
  // Optional: identify a logged-in user. When omitted, the SDK generates a
  // stable anonymous track id (a random UUID persisted in cookie + localStorage).
  user: { userId: 'user_123', email: 'user@example.com' },
});

const buttonColor = abmeter.resolveParameter('button-color');

abmeter.trackEvent('purchase', { price: 4.99 });

apiKey must be a publishable key (pk_..., minted on the Lab API Keys page) — it is safe to embed in browser code and is limited server-side to the three endpoints this SDK uses. configure refuses any other key: secret keys (api-...) are never browser-safe.

configure hydrates synchronously from localStorage when a cached assignment map exists (no flash of defaults on repeat visits) and refreshes it in the background with ETag caching. resolveParameter returns the cached value and lazily queues an exposure — a value that is fetched but never read produces no exposure.

Identity

  • Anonymous visitors get a generated track id — a random UUID stored in a cookie and localStorage — sent as the user_id. Note that Safari caps JavaScript-set cookies at ~7 days; for long-running experiments, set the cookie server-side.
  • Logged-in users: pass user: { userId } yourself. Keep one randomization unit per experiment — do not switch a user's id across the login boundary mid-experiment.
  • email is optional and used only by email-predicate audiences.
Decide the identity before the first configure

Calling configure again with a different userId is not a supported way to upgrade an anonymous visitor to a logged-in one. Two things change that you cannot undo:

  • The visitor may flip variant. Assignments are fetched per user id, so the second configure gets a different map. Whatever the page already rendered was for the old identity.
  • Attribution splits. Exposures already recorded carry the old id, everything after carries the new one, and results match events to a visitor by the id their exposure was recorded under. The two halves never meet — no error, just a metric quietly missing conversions.

Queued telemetry itself is safe: configure drains the previous configuration in the background rather than discarding it. Use await reset() first if you need certainty that the drain completed before the page can navigate away.

This matters most in a single-page app served as static files, which cannot know the user until an auth request returns. Two options that work:

  • Stay anonymous for the life of the experiment and let the generated track id be the randomization unit — correct, and it also measures logged-out traffic.
  • Configure once auth resolves, and render defaults until then.

Event submission

Exposures and events are queued and submitted in small batches in the background. The queue drains on visibilitychange → hidden and pagehide using fetch(..., { keepalive: true }) with a sendBeacon fallback, so data survives tab closes without blocking navigation. Call abmeter.flush() on SPA route changes if you want an eager drain.

Content blockers may drop telemetry requests at the network layer; the SDK treats that as expected loss and never throws.

API

Function Description
configure(options) Initialize the SDK. Options: apiKey (required), baseUrl, user: { userId?, email? }, flushInterval (ms, default 1000), logger, errorCallback.
resolveParameter(slug) Resolved value for this user, or undefined if unknown. Queues an exposure lazily (deduplicated over a 10-minute window).
getExposure(slug) The exposure metadata for a parameter (null for feature-flag/default resolutions), without queueing anything.
trackEvent(eventSlug, customFields?) Queue an event for the configured user.
flush() Drain the queue now (returns a promise).
reset(options?) Drain fully and tear down timers/listeners. configure again to restart.

All read/track functions are error-safe: failures are logged (and passed to errorCallback when configured) and return a safe default instead of throwing.

Keywords