SDK reference

Everything the browser SDK exposes, and the wire format underneath it.

Pulse.init(config)

Configures the SDK, sends one pageview, and starts listening for route changes. Call it once per page load.

import { Pulse } from "@akdevv/pulse/sdk";

Pulse.init({
  siteId: "pk-8f2c41a9d7e04b6fa1c35d8e92b74a06",
  apiHost: "https://pulse-analytics-main.up.railway.app",
  debug: false,
});
OptionTypeRequiredDescription
siteIdstringyesYour tracking ID, in the form pk- followed by 32 characters.
apiHoststringnoAPI origin, no path. Omit it and events post to /api/v1/track on the current origin.
debugbooleannoLogs every event and its parameters to the console. Off by default.

Returns nothing, and never throws. A failed request is swallowed on purpose, because analytics has no business breaking the page it measures.

Pulse.trackPageview(options?)

Sends a pageview by hand. Route changes are already covered, so reach for this when you want a pageview that does not match the URL, such as a modal you treat as its own screen.

Pulse.trackPageview();
Pulse.trackPageview({ url: "/checkout/payment", title: "Payment" });
OptionTypeDefault
urlstringwindow.location.href
titlestringdocument.title
referrerstringdocument.referrer

Pulse.trackEvent(name, properties?)

Records a named event. See Custom events for naming and what not to put in properties.

Pulse.trackEvent("signup_completed", { plan: "pro" });
ArgumentTypeRequired
namestring, up to 255 charactersyes
propertiesRecord<string, string | number | boolean>no

Available as window.Pulse.trackEvent on the script tag install too, with the same signature.

Click attributes

init() attaches one delegated click listener to the document, so these work on elements added to the page at any point. Both installs support them.

AttributeRequiredDescription
data-pulse-eventyesEvent name. The click is sent as a CUSTOM event under this name.
data-pulse-propsnoProperties as a JSON object. Invalid JSON warns in the console and the event sends without them.
<button data-pulse-event="plan_picked" data-pulse-props='{"plan":"pro"}'>
  Choose Pro
</button>

The listener matches with closest(), so a click on an icon inside the button still resolves to the button carrying the attribute.

usePulse(config)

React hook, same config as init. Runs once on mount, guards against React's double invocation in development, and ignores every render after the first.

import { usePulse } from "@akdevv/pulse/react";

usePulse({ siteId: "pk-...", apiHost: "https://pulse-analytics-main.up.railway.app" });

Config is read on first mount only. Changing siteId later has no effect until a full reload.

getVisitorId() and getSessionId()

import { getVisitorId, getSessionId } from "@akdevv/pulse/sdk";

Both return the UUID the SDK is attaching to events, generating one if it does not exist yet. Useful for correlating a support ticket with a session, and for nothing else. Neither is derived from the person.

IDStorageLifetime
pulse_cidlocalStorageUntil the visitor clears site data
pulse_sidsessionStorageUntil the tab closes

Private browsing can make both storage APIs throw. When that happens the SDK falls back to a fresh UUID per event rather than failing, so those hits count as new visitors.

Script tag attributes

pulse.js reads its own tag through document.currentScript.

AttributeRequiredDescription
data-tidyesTracking ID. Without it the script warns and stops.
data-hostnoAPI origin, no path. Defaults to http://localhost:8000, which is only ever right in development.
data-debugno"true" logs every event to the console. Off by default; warnings always show.

The script tracks pageviews, handles data-pulse-event clicks, and exposes window.Pulse with trackEvent(name, properties?) and trackPageview(). Custom events do not require the npm package.

Tracking endpoint

Both the script and the package end up here. It is documented so you can send events from a server, a mobile app, or curl.

POST /api/v1/track?v=1&tid=pk-...&t=PAGEVIEW&dl=https://example.com/

Everything travels in the query string. The request body is ignored.

ParameterMeaningRequired
vProtocol version, currently 1no, defaults to 1
tidTracking IDyes
tPAGEVIEW, CLICK, or CUSTOMyes
dlPage URL, absoluteyes
dtPage title, up to 500 charactersno
drReferrer URLno
enEvent name, up to 255 charactersfor CUSTOM
epEvent properties, JSON encodedno
cidVisitor ID, UUIDno
sidSession ID, UUIDno
srScreen size, 1920x1080no
vpViewport size, 1280x800no
ulBrowser language, en-USno
tsClient timestamp in millisecondsno
zCache buster, any valueno

The server derives the rest: browser, OS, and device from the user agent, country from the IP address, and the received timestamp. Send ts and the client's clock is used for the event time, which is worth remembering when a machine's clock is wrong.

Responses

/track returns 204 No Content to every request it receives. Accepted, rejected, rate limited, malformed, unknown site, all 204, all with an empty body.

That is a deliberate trade. A tracking endpoint that returns errors leaks whether a tracking ID exists, and it puts noise in the console of a site that is not yours to break. The cost is that you cannot use the status code for debugging. Use the dashboard, or turn on debug and read what the SDK is sending.

Limits

Rate limits are enforced per minute, in Redis, on two independent counters. Cross either one and events are dropped silently until the minute rolls over.

LimitValue
Events per minute, free site1,000
Events per minute, pro site10,000
Events per minute, enterprise site100,000
Events per minute, single IP address500

The IP limit applies across all sites, so one visitor cannot spend a site's whole budget. On a self-hosted instance all of these are yours to change, in backend/src/config/ratelimit.ts.

Payload limits: event names up to 255 characters, page titles up to 500, request bodies capped at 8 KB. Malformed URLs in dl are rejected outright, since a pageview with no valid URL is not a pageview.