The Beacon SDK (@beacon/sdk) is a lightweight TypeScript client for tracking events, identifying users, and receiving feature flag updates.
npm install @beacon/sdk
# or
pnpm add @beacon/sdkimport { init, track, identify, page, flag } from "@beacon/sdk";
// Initialize the SDK
init({
url: "https://beacon.example.com",
apiKey: "bk_your_api_key",
});
// Track a page view
page();
// Track custom events
track("button_clicked", { button_id: "signup" });
// Identify users after login
identify("user_123", { plan: "pro", email: "user@example.com" });
// Check feature flags
if (flag("new_checkout_flow")) {
// Show new checkout
}Initialize the SDK. Must be called before any other SDK methods.
interface BeaconConfig {
/** Beacon server URL */
url: string;
/** Project API key */
apiKey: string;
/** Callback for connection state changes */
onConnectionChange?: (state: ConnectionState) => void;
/** Callback for errors */
onError?: (error: string) => void;
}
type ConnectionState =
| "connecting"
| "connected"
| "disconnected"
| "reconnecting";Example:
init({
url: "https://beacon.example.com",
apiKey: "bk_abc123",
onConnectionChange: (state) => {
console.log("Connection state:", state);
},
onError: (error) => {
console.error("Beacon error:", error);
},
});Track a custom event with optional properties.
type EventProps = Record<string, string | number | boolean | null>;Examples:
// Simple event
track("signup_started");
// Event with properties
track("purchase_completed", {
product_id: "sku-456",
quantity: 2,
price: 49.99,
is_gift: false,
});Associate the current session with a user identity.
identify("user_12345", {
email: "jane@example.com",
name: "Jane Doe",
plan: "enterprise",
company: "Acme Corp",
});Track a page view with automatic URL capture.
Automatically captures:
url- Full URL (window.location.href)path- Path only (window.location.pathname)ref- Referrer (document.referrer)
// Basic page view
page();
// With additional context
page({ section: "blog", author: "jane" });Get the current WebSocket connection state.
if (getConnectionState() === "connected") {
console.log("Ready to send events");
}Check if a feature flag is enabled. Exported as flag from @beacon/sdk.
import { flag } from "@beacon/sdk";
if (flag("new_feature")) {
// Show new feature
}
// With fallback (default: false)
if (flag("experimental_feature", false)) {
// Show experimental feature
}Note: For advanced flag usage (subscribe, getAll), use the React hooks or import directly from the flags module.
The SDK provides React-specific hooks for declarative usage:
import {
BeaconProvider,
useFlag,
useFlags,
usePageView,
useTrack,
track,
identify,
page
} from "@beacon/sdk/react";
// Wrap your app with BeaconProvider
function App() {
return (
<BeaconProvider config={{ url: "https://beacon.example.com", apiKey: "bk_..." }}>
<MyComponent />
</BeaconProvider>
);
}
function MyComponent() {
// Check a single flag
const isNewFeatureEnabled = useFlag("new_feature");
// Get all flags
const allFlags = useFlags();
// Track page view on mount
usePageView();
// Get the track function
const trackEvent = useTrack();
if (!isNewFeatureEnabled) return null;
return (
<div onClick={() => trackEvent("clicked", { button: "cta" })}>
New Feature!
</div>
);
}| Export | Type | Description |
|---|---|---|
BeaconProvider |
Component | Initializes SDK, wrap app with this |
useFlag(key, fallback?) |
Hook | Subscribe to a single flag |
useFlags() |
Hook | Subscribe to all flags |
usePageView(deps?) |
Hook | Track page view on mount |
useTrack() |
Hook | Returns the track function |
track, identify, page |
Function | Re-exported from core SDK |
The SDK dispatches custom events on window for integration flexibility:
| Event | Detail | Description |
|---|---|---|
beacon:flags |
Record<string, boolean> |
Fired when flags are updated |
beacon:connection |
ConnectionState |
Fired when connection state changes |
beacon:error |
string |
Fired when an error occurs |
window.addEventListener("beacon:flags", (e) => {
console.log("Flags updated:", e.detail);
});The SDK uses a Web Worker for off-main-thread event processing:
Main Thread Web Worker Server
│ │ │
│───── init ────────────▶│ │
│ │───── WebSocket ───▶│
│ │◀──── connected ────│
│◀───── ready ───────────│ │
│ │ │
│───── track ───────────▶│───── event ───────▶│
│ │ │
│ │◀──── flags ────────│
│◀───── flags ───────────│ │
Events are queued until:
- The worker signals "ready"
- The WebSocket connection is established
Queued events are sent in order once the connection is ready.
The SDK automatically reconnects with exponential backoff:
- Initial delay: 1 second
- Maximum delay: 30 seconds
- Backoff multiplier: 2x
The SDK uses localStorage to persist identity across page loads:
- Anonymous ID (
beacon_anon_id): Generated once and persisted forever. Identifies the browser/device. - Session ID (
beacon_session): Persisted with a 30-minute inactivity timeout. Stored as{id, timestamp}.
Sessions automatically rotate after 30 minutes of inactivity. Each session gets a new UUID while the anonymous ID persists. Activity (track, identify, page) extends the session timeout.
Page load at 10:00 → session_id: "abc..." (new or restored from localStorage)
track() at 10:15 → session_id: "abc..." (same session, timeout extended)
Page refresh 10:20 → session_id: "abc..." (restored from localStorage)
Idle until 11:00 → session_id: "xyz..." (new session, 30+ min inactivity)
The SDK safely handles server-side rendering. All methods check for window before executing browser APIs.
// Safe to call during SSR - will be a no-op
init({ url: "...", apiKey: "..." });
track("page_view");- API Reference - Server endpoints and architecture
- WebSocket Protocol - Wire protocol specification
- Identity Tracking - User identification and attribution