SDK reference
Every method on PulseClient, the config it takes, and the functions the package exports beside it.
pnpm add @thepulseapi/sdkSession
| Method | Returns | |
|---|---|---|
init(config) | TrackResponse | null | Start a session and send the automatic signals once |
getSession() | SessionResponse | Current session and inferred personas |
getSessionId() | string | The current session id |
resetSession() | void | Clear it and start fresh |
onPersona(cb) | void | Subscribe to persona updates |
Signals and ranking
| Method | Returns | |
|---|---|---|
track(signals) | TrackResponse | Send shopper signals |
search(products, options?) | SearchResponse | Rank products you pass in |
rankedCatalog(options?) | RankedCatalogResponse | Rank the catalogue already synced to PULSE |
event(type, data?) | EventResponse | Record a named event |
search and rankedCatalog are not interchangeable. search ranks what you hand it;
rankedCatalog ranks what PULSE already holds.
Exposure
| Method | ||
|---|---|---|
exposure(decisionId, items) | void | Record what was actually rendered, buffered |
flushExposures() | Promise<void> | Send buffered exposures now |
Config
apiKeyRequiredstring
Publishable key, pk_live_...
organizationIdRequiredstring
From the dashboard
endpointOptionalstring
Override only for local development
Defaults to https://api.thepulseapi.com
autoTrackOptionalboolean
Capture device, referrer and time on init()
Defaults to true
sessionTtlMsOptionalnumber
Inactivity before a new session
Defaults to 1800000
anonymousIdOptionalstring
Identity label only. Never reaches inference.
debugOptionalboolean
Verbose logging
Defaults to false
Beyond the client
PulseClient is most of the package and not all of it. These are exported too, for the cases
where you need a signal without a client, or need to look at what the SDK cached.
Signal capture
init() calls captureAutoSignals() for you when autoTrack is on, so you only need these
directly when you want a signal at a different moment, or want one the automatic set leaves out.
| Export | Returns | |
|---|---|---|
captureAutoSignals() | Signal[] | Device, referrer and time in one call. What init() sends |
captureDeviceSignal() | Signal | null | Device class from the user agent |
captureReferrerSignal() | Signal | null | Where the visit came from |
captureTimeSignal() | Signal | Time of day. Never null, there is always a clock |
captureEnhancedReferrerSignals() | Signal[] | Campaign and channel detail beyond the plain referrer |
captureDeviceInfoAsync(): Promise | DeviceInfo | Fuller device detail, including client hints |
captureGeoInfo(): Promise | GeoInfo | null | Coarse location from the IP |
geoToSignals(geo) | Signal[] | Turn a GeoInfo into signals |
captureWeatherInfo(lat, lon, apiKey?): Promise | WeatherInfo | null | Conditions at a point |
weatherToSignals(weather) | Signal[] | Turn a WeatherInfo into signals |
captureCulturalCalendar(countryCode) | Signal[] | Seasonal and cultural events active today |
parseUserAgent(ua) | DeviceInfo | Parse a user agent string you already have |
captureWeatherInfo needs your own key
It calls OpenWeatherMap and returns null without an apiKey, so nothing breaks if you leave
it out. The free tier is 1,000 calls a day, which is why the result is cached per session
rather than fetched per page.
captureAutoSignals() is exported for one specific failure. init() sends the automatic
signals exactly once and swallows its own error, so a session whose init() failed never
re-sends them and stays thin for its whole life. These signals cost no network of their own, so
calling this again on a later page load is cheaper than the alternative.
Session context
Device, location and weather are properties of the session rather than of the page: they cannot change between one page and the next. The SDK captures them once, keys the cache by session id so it cannot outlive the visitor it describes, and reuses it. You rarely need to touch this.
| Export | Returns | |
|---|---|---|
readSessionContext(sessionId) | SessionContext | null | The cache, or null if it belongs to another session |
writeSessionContext(sessionId, patch) | void | Merge fields into it |
isWeatherFresh(ctx, now?) | boolean | Whether the weather reading is still inside its TTL |
clearSessionContext() | void | Drop the cache |
WEATHER_TTL_MS | number | 10 minutes |
Weather is the only field here with a TTL. Everything else is immutable for the session, but a
30-minute session can outlast a rain shower, and a weather:rain signal driving a
recommendation after the sun came out is the engine being confidently wrong.

