JavaScript SDK
The PennyLens SDK exposes a small global API for tracking events, identifying users, and controlling capture at runtime. Once the snippet from Installation loads, the SDK is available as window.PennyLens.
Loading and readiness
The script tag loads asynchronously and calls init() automatically from its data-project attribute. Calls made before that init completes are dropped, not queued — so if you need to fire an event immediately on page load from your own inline script, initialize manually via the npm package instead of relying on the auto-init timing.
PennyLens.track("hero_cta_clicked");
Methods
init(config)
Initializes the tracker. Called automatically by the script-tag snippet; call it manually when using the npm package.
import { PennyLens } from "@pennylens/tracker";
PennyLens.init({
projectId: "YOUR_API_KEY", // your API key from Settings, not the project id
sessionRecording: true,
debug: false,
});
track(event, properties?)
Records a custom event. Property values must be JSON-serializable.
PennyLens.track("checkout_started", {
cart_value: 89.99,
item_count: 3,
currency: "USD",
});
| Argument | Type | Notes |
| --- | --- | --- |
| event | string | Event name. Lowercase with underscores by convention. |
| properties | object | Optional. Nested objects and arrays are flattened to one level. |
identify(userId, traits?)
Accepted by the SDK today, but currently a client-side-only, in-memory call — the ID and traits aren't yet transmitted to PennyLens or attached to events. See User identification for exactly what this does today and the track()-based patterns that work now.
PennyLens.identify("user-7281", {
email: "alex@example.com",
plan: "pro",
});
consent()
For sites using consentRequired: true (see Configuration below): grants consent, persists it to localStorage, and starts tracking if the SDK hasn't initialized yet.
PennyLens.consent();
Configuration
When initializing via npm, pass options to init():
import { PennyLens } from "@pennylens/tracker";
PennyLens.init({
projectId: "YOUR_API_KEY", // your API key from Settings, not the project id
sessionRecording: true,
consentRequired: false,
debug: false,
});
| Option | Type | Default | Notes |
| --- | --- | --- | --- |
| projectId | string | — | Required. Your API key — Settings → API key. Named projectId for historical reasons; the project id is a different value and is rejected at ingest. |
| endpoint | string | — | Optional. Custom ingestion endpoint URL. |
| sessionRecording | boolean | false | Set true to load the rrweb recorder bundle (~25 KB, loaded async, separate from the core snippet). |
| recorderUrl | string | https://cdn.pennylens.com/recorder.js | Optional. Point at a self-hosted recorder bundle. |
| consentRequired | boolean | false | When true, no events are sent until PennyLens.consent() is called. |
| debug | boolean | false | Logs SDK activity to the browser console. |
| flushInterval | number | 5000 | Milliseconds between batched sends. |
| flushSize | number | 20 | Event count that triggers an early flush. |
Script-tag installs read data-project (and optionally data-endpoint) from the <script> tag itself — there's no data-* equivalent for every option above; use the npm package if you need finer control.
Input masking in session recordings is always on and is not configurable — see Session recordings for the per-element opt-outs that are available (data-pl-ignore, data-pl-mask).
TypeScript
The npm package ships types out of the box:
import type { TrackerConfig, TrackEvent, IdentifyPayload } from "@pennylens/tracker";
Next steps
- User identification — what
identify()does today, and what's on the roadmap - Session recordings — recording controls and retention
- Event Tracking — auto-tracked and custom events