blob: d883d7631e142715e2bcc289c7edc339bc8b39d2 [file] [view]
---
title: The UserALE.js API
component: useralejs
permalink: /docs/useralejs/API/
priority: 2
---
[Apache Flagon UserALE.js](https://github.com/apache/flagon/tree/master/products/userale/packages/flagon-userale) provides a comprehensive JavaScript and TypeScript API for runtime configuration, custom log enrichment/filtering, header injection, and pluggable wire exporters.
---
## Core Lifecycle & Configuration API
### `options(newConfig?: Partial<Settings.Config>): Settings.Config`
Reads or shallow-merges runtime configuration options. Calling `options()` with no arguments returns the current configuration object.
```typescript
import * as userale from 'flagon-userale';
userale.options({
url: 'https://collector.example.com/v1/logs',
userId: 'user-42',
toolName: 'checkout-ui',
toolVersion: '2.5.0',
exporterFormat: 'otlp-json',
});
```
### `start(): void` & `stop(): void`
Starts or halts event capturing and log transmission. Particularly useful when `autostart: false` (`data-autostart="false"`) is configured until user consent or authentication completes.
```typescript
userale.options({ autostart: false });
// Later, after user consent:
userale.start();
```
### `version: string`
Exports the current `flagon-userale` package version string.
---
## Custom Logging & Filtering Callbacks
### `addCallbacks(callbacks: Record<string, CallableFunction>): boolean`
Registers one or more named callback functions executed sequentially on every packaged log (`(log, event) => log | false`). Returning `false` (or any falsy value) drops the log from the queue; returning a modified log object replaces it.
```typescript
userale.addCallbacks({
dropIntervalLogs(log) {
if (log.logType === 'interval') {
return false;
}
return log;
},
attachExperimentTag(log, event) {
return {
...log,
experimentVariant: 'checkout-v2',
};
},
});
```
### `removeCallbacks(targetKeys: string[]): void`
Removes registered callbacks by name:
```typescript
userale.removeCallbacks(['dropIntervalLogs']);
```
### `log(customLog: Logging.CustomLog): boolean`
Appends a custom log object directly onto the UserALE queue:
```typescript
userale.log({
target: 'checkout-funnel',
type: 'step_complete',
logType: 'custom',
userAction: false,
details: { step: 2, cartTotal: 149.0 },
});
```
### `packageLog(e: Event, detailFcn?: Logging.DynamicDetailFunction): boolean` & `packageCustomLog(customLogs: Logging.CustomLog, detailFcn: Logging.DynamicDetailFunction, userAction: boolean): boolean`
Packages a standard DOM `Event` or custom metadata object with full UserALE page/session/browser context and enqueues it.
### `details(config: Configuration, type: Events.AllowedEvents): ((e: Event) => Record<string, unknown>) | null`
Returns the default detail-extractor function for a given DOM event type (`click`, `keydown`, `input`, `change`, `wheel`, etc.). Note that `<input type="password">` values are automatically masked (`"********"`).
### `getSelector(ele: EventTarget): string` & `buildPath(e: Event): string[]`
Utility helpers that compute a CSS-like element selector (`tag#id.class`) and full DOM ancestry path array from a DOM `Event`.
### `getTargetRect(el: EventTarget | null): TargetRect | null` & `detectBrowser(): { browser: string; version: string }`
- `getTargetRect` extracts a rounded bounding box (`{ x, y, width, height, top, right, bottom, left }`) for a DOM element (attached automatically as `targetRect` on `click`, `dblclick`, `change`, and `submit` events).
- `detectBrowser` detects the browser name and version using `navigator.userAgentData` (User-Agent Client Hints) with a regex fallback and zero external dependencies.
---
## Authentication & Custom HTTP Headers
All HTTP-based exporters (`HttpJsonExporter`, `ProtoJsonExporter`, `OtlpJsonExporter`) construct headers through `buildHeaders(config)`, applying them to both interval `fetch()` requests and `pagehide` (`fetch(..., { keepalive: true })`) flushes.
### `registerAuthCallback(callback: () => string): boolean` & `resetAuthCallback(): void`
Registers (or resets) a dynamic provider returning the `Authorization` header value on each batch export:
```typescript
userale.registerAuthCallback(() => `Bearer ${getCurrentJwtToken()}`);
```
### `registerHeadersCallback(callback: () => Record<string, string>): boolean` & `resetHeadersCallback(): void`
Registers (or resets) a dynamic provider returning arbitrary HTTP headers on each batch export:
```typescript
userale.registerHeadersCallback(() => ({
'x-tenant-id': 'acme-corp',
'x-request-source': 'userale-web',
}));
```
Static headers can also be configured via `userale.options({ authHeader: 'Bearer ...', apiKey: '...', headers: { ... } })`.
---
## Pluggable Wire Exporters (`LogExporter`)
UserALE decouples in-memory event packaging from wire serialization and transport via the `LogExporter` interface:
```typescript
export interface LogExporter {
export(logs: Array<Logging.Log>, options?: ExportOptions): Promise<ExportResult>;
flush?(): Promise<void>;
shutdown?(): Promise<void>;
}
```
### Built-In Exporters & Helpers
| Exported Symbol | Description |
|---|---|
| `registerExporter(exporter: LogExporter)` | Registers a custom `LogExporter` instance and switches the active sender to use it immediately. |
| `createExporter(config)` | Factory returning the active `LogExporter` for a `Configuration` instance. |
| `HttpJsonExporter` | Default exporter sending flat UserALE JSON arrays over `fetch` (with 48 KiB chunked `keepalive: true` on `pagehide`). |
| `WebSocketExporter` | Streams log batches over a persistent `WebSocket` (`ws://` / `wss://`). |
| `ProtoJsonExporter` / `toProtoLogBatch(logs)` / `toProtoUserALELog(log)` | Serializes logs into canonical Protobuf v1 JSON (`apache.flagon.userale.v1.LogBatch`) matching `proto/apache/flagon/userale/v1/log.proto`. |
| `OtlpJsonExporter` / `toOtlpExportLogsServiceRequest(logs, config)` | Serializes logs into OpenTelemetry `ExportLogsServiceRequest` JSON with `Resource` hoisting, `BigInt` nanosecond timestamps, `eventName`, structured `kvlistValue` body, and W3C `traceId`/`spanId` correlation. |
| `OtelSdkExporter` | Bridges UserALE logs directly into an existing OpenTelemetry JS `@opentelemetry/api-logs` `Logger` via `logger.emit(...)`. |
| `resolveOtlpLogsEndpoint(endpoint)` | Normalizes an OTLP base URL by appending `/v1/logs` when the URL path is empty or `/`. |
| `toUnixNanoString(clientTimeMs, microTime)` | Converts millisecond + sub-millisecond timestamps to a 64-bit nanosecond string using `BigInt`. |
### Example: Correlating UserALE Events with W3C Distributed Traces
```typescript
import * as userale from 'flagon-userale';
userale.options({
exporterType: 'otlp',
otlpEndpoint: 'http://localhost:4318/v1/logs',
toolName: 'storefront-web',
traceContext: () => ({
traceId: currentActiveSpan.traceId, // 32-hex W3C trace-id
spanId: currentActiveSpan.spanId, // 16-hex W3C span-id
}),
});
```
---
## Two-Layer Session Replay & Behavioral DOM Telemetry (`#104`)
UserALE provides a two-layer session replay architecture that keeps the core bundle dependency-free while supporting both structural DOM telemetry and `rrweb`-compatible visual playback:
| Exported Symbol | Description |
|---|---|
| `startSessionReplay(options?: SessionReplayOptions, config?: Configuration): () => void` | Starts Layer 1 (`MutationObserver` + `RageClickDetector`) and optional Layer 2 (`rrweb` ring-buffer recorder). Returns a stop/cleanup function. |
| `flushSessionReplay(trigger?: string): Promise<ReplayEnvelope \| null>` | Immediately flushes the rolling `rrweb` ring buffer as a `logType: 'replay', type: 'session_replay'` envelope tagged with `sessionId` and active OpenTelemetry `traceId` / `spanId`. |
| `stopSessionReplay(): void` | Stops active `MutationObserver` and `rrweb` recording and clears the ring buffer. |
| `getActiveReplayRingBuffer(): ReplayRingBuffer \| null` | Returns the active `ReplayRingBuffer` instance when session replay is running. |
| `ReplayRingBuffer` | Rolling in-memory ring buffer (`maxDurationMs`, `maxFrames`) that preserves `rrweb` `Meta` (`type: 4`) and latest `FullSnapshot` (`type: 2`) anchor frames. |
| `RageClickDetector` | Sliding-window detector that triggers when `threshold` (default `3`) clicks occur on the same target selector within `windowMs` (`1000ms`) and `maxRadiusPx` (`30px`). |
```typescript
import * as userale from 'flagon-userale';
import * as rrweb from 'rrweb';
userale.startSessionReplay({
recorder: rrweb.record,
maxDurationMs: 30_000,
observeMutations: true,
detectRageClicks: true,
flushOnError: true,
});
```
---
## Contributing
Contributions are welcome! See our [Contributing Guide]({{ '/docs/contributing' | prepend: site.baseurl }}) or open an issue on [GitHub](https://github.com/apache/flagon/issues).