subscriptions
Contextune.subscribe(filter, handler) lets you react to every event log addition in real time. It is framework-agnostic — the same API works in plain browser JS, React, Vue, or any other context.
1 / basic usage
Call subscribe() after init(). It returns an unsubscribe function — call it when you no longer need notifications.
import { Contextune } from '@contextune/sdk';
Contextune.init();
// Fire on every event
const unsubscribe = Contextune.subscribe('event', (entry, state) => {
console.log('new event:', entry.name);
console.log('log before this entry had', state.event_log.length, 'events');
});
Contextune.track('page_loaded'); // handler fires
Contextune.track('cta_clicked'); // handler fires again
// Stop listening
unsubscribe();
Contextune.track('something_else'); // handler does NOT fire2 / filter
The first argument controls which events trigger the handler. Two forms are supported:
| name | type | default | example |
|---|---|---|---|
'event'Fire the handler on every entry added to the log. | string literal | — | — |
(entry) => booleanFire the handler only when the predicate returns true. Receives the incoming EventLogEntry before it is added to the log. | function | — | — |
import { Contextune } from '@contextune/sdk';
Contextune.init();
// Fire only for specific events
const unsubscribe = Contextune.subscribe(
(entry) => entry.name === 'checkout',
(entry, state) => {
// entry.name is guaranteed to be 'checkout' here
sendContextToAgent(entry, state);
},
);
// more complex predicate
const unsubscribe2 = Contextune.subscribe(
(entry) => entry.properties?.cart_value != null && Number(entry.properties.cart_value) > 100,
(entry, state) => {
triggerHighValueFlow(entry, state);
},
);3 / handler arguments
The handler receives two arguments: the incoming event and the full snapshot at the moment the event arrived.
| name | type | default | example |
|---|---|---|---|
entryThe event that just entered the log. A shallow copy — safe to store or mutate. The event_log in state does not yet contain this entry. | EventLogEntry | — | — |
stateFull snapshot captured immediately before entry was added. event_log reflects the state before this event; marketing_params and device_info are present when enabled. | ContextuneSnapshot | — | — |
import { Contextune } from '@contextune/sdk';
import type { ContextuneSnapshot, EventLogEntry } from '@contextune/sdk';
Contextune.init();
Contextune.track('first');
Contextune.track('second');
Contextune.subscribe('event', (entry: EventLogEntry, state: ContextuneSnapshot) => {
// entry — the event that just arrived (NOT yet in state.event_log)
// state — full snapshot BEFORE this event was added
// When 'third' fires:
// entry.name === 'third'
// state.event_log has ['first', 'second']
// state.marketing_params and state.device_info are also present
console.log('arrived:', entry.name);
console.log('previous events:', state.event_log.map(e => e.name));
});
Contextune.track('third');The pre-event snapshot is useful when you need the full history context at the moment an event triggered — for example, to send both the triggering event and the preceding log to your model in a single call.
4 / react integration
Wrap subscribe() in a useEffectand return the unsubscribe function as the cleanup. This is the canonical React pattern — the subscription is tied to the component's lifecycle.
'use client';
import { useEffect } from 'react';
import { Contextune } from '@contextune/sdk';
import type { EventLogEntry, ContextuneSnapshot } from '@contextune/sdk';
export function useContextuneEvent(
eventName: string,
handler: (entry: EventLogEntry, state: ContextuneSnapshot) => void,
) {
useEffect(() => {
const unsubscribe = Contextune.subscribe(
(e) => e.name === eventName,
handler,
);
return unsubscribe; // cleanup on unmount
}, [eventName, handler]);
}
// Usage in a component:
export function CheckoutWatcher() {
useContextuneEvent('checkout', (entry, state) => {
console.log('checkout with', state.event_log.length, 'prior events');
});
return null;
}5 / multiple subscribers
Any number of subscribers can be active at the same time. Each runs independently — an error in one does not prevent the others from being called. Errors inside handlers are caught and silently dropped.
import { Contextune } from '@contextune/sdk';
Contextune.init();
// Multiple independent subscribers — all fire on each matching event.
// Each subscriber is isolated: an error in one does not affect the others.
const unsubA = Contextune.subscribe('event', (entry) => {
analyticsLayer.push(entry);
});
const unsubB = Contextune.subscribe(
(e) => e.name.startsWith('checkout'),
(entry, state) => {
agentLayer.notify(entry, state);
},
);
// Tear down individually or let destroy() clear all of them.
unsubA();
// unsubB stays active6 / plain browser JS
No framework required. subscribe() is a plain function call on the static Contextune object.
// Works outside of any framework — plain browser JS.
// Wire it up once and let it run for the lifetime of the page.
import { Contextune } from '@contextune/sdk';
Contextune.init({ source: 'ga4' });
Contextune.subscribe('event', (entry, state) => {
// Forward to your server-sent-events endpoint, WebSocket, etc.
navigator.sendBeacon('/api/events', JSON.stringify({ entry, state }));
});7 / lifecycle
- Calling
subscribe()beforeinit()returns a no-op unsubscribe function — no error, no notification ever fires for that registration. destroy()clears all active subscribers. Re-initialising after destroy starts with an empty subscriber set.- You can call the returned unsubscribe function multiple times safely — subsequent calls are no-ops.
import { Contextune } from '@contextune/sdk';
Contextune.init();
const unsub = Contextune.subscribe('event', (entry) => {
console.log(entry.name);
});
// destroy() clears ALL subscribers — no need to call unsub() first.
Contextune.destroy();
// Re-init starts with an empty subscriber set.
Contextune.init();types
type SubscriptionFilter = 'event' | ((entry: EventLogEntry) => boolean);
type SubscriptionHandler = (
entry: EventLogEntry,
state: ContextuneSnapshot,
) => void;
// Both are exported from '@contextune/sdk'
import type { SubscriptionFilter, SubscriptionHandler } from '@contextune/sdk';For the full method signature, see API reference → subscribe.