Pulse
Growth analytics for app developers — ask about revenue, MRR, ad spend, subscriptions, funnels, LTV and CAC from your AI agent. Read-only access to your own RevenueCat, App Store, Google Play, Meta Ads and Google Ads.
Documentation
Pulse SDK
Open-source analytics SDKs for web, React Native, iOS, and Android. Add analytics to your app with a reliable, offline-first event queue and clean identity — and nothing else.
- Tiny. The web SDK is ≤ 10 KB gzipped with zero dependencies.
- Reliable. A persistent, ordered queue survives offline periods and process death. Delivery is idempotent: retries never duplicate events.
- Honest about privacy. No auto-capture, no fingerprinting, no IDFA/GAID, no ad SDKs. The SDK sends only the events you send it.
- One protocol, four platforms. Every SDK implements the same wire protocol and passes the same conformance fixtures in CI. The Pulse ingestion server replays those same fixtures — the contract is verified from both ends.
This repository holds the TypeScript packages. The Swift and Kotlin SDKs live
in pulse-sdk-native.
For AI agents
Install: npm i @pulse-circle/web, then Pulse.init('pk_...') and
Pulse.track('event', {...}). The package is self-contained (zero deps, default
endpoint baked in) and ships llms.txt inside it. Installing needs only npm; event
delivery happens in the end-user's browser at runtime.
Packages
| Package | What it's for | Install |
|---|---|---|
@pulse-circle/web | Browser / any web app | npm i @pulse-circle/web |
@pulse-circle/react-native | React Native & Expo | npm i @pulse-circle/react-native |
@pulse-circle/core | Platform-agnostic engine (used by the above) | npm i @pulse-circle/core |
@pulse-circle/mcp | Local (stdio) MCP server — offline setup/connect guides for AI agents | claude mcp add pulse -- npx -y @pulse-circle/mcp |
Quickstart (web)
npm install @pulse-circle/web
import { Pulse } from '@pulse-circle/web';
Pulse.init('pk_your_api_key');
// Track product events — the SDK batches, persists, and retries for you.
Pulse.track('subscription_started', { plan: 'pro' });
// Tie events to a user after login.
Pulse.identify('user_42');
// On logout, start a fresh anonymous identity.
Pulse.reset();
That's the whole API. See each package's README for the platform-specific install (script tag, Expo, etc.) and the full reference.
The API, everywhere
The five methods are identical across all four platforms, in each language's idiomatic syntax:
init(apiKey, options?) // configure once
track(event, properties?) // queue an event
identify(userId) // associate the current identity with a user id
reset() // logout: new anonymous identity
flush() // force-send the queue (tests, critical moments)
There are deliberately no screen/page auto-tracking and no revenue methods: revenue comes from server-side connectors, so there is exactly one source of truth per number.
The reliability contract
- Every event gets an
idempotency_keyand atimestampat the moment you calltrack— never at send time. Retries resend both byte-identical, and the server's primary key includes both, so a flaky network can never create a duplicate. - The queue is persistent (localStorage on web, files on mobile) and ordered. It survives reloads, crashes, and offline periods up to a per-platform cap, then evicts oldest-first with a debug warning rather than growing without bound.
- Retries use exponential backoff with jitter. A batch the server keeps rejecting (a "poison" batch) is moved aside after 10 attempts so it can never block everything behind it.
The normative details are in protocol/PROTOCOL.md.
Development
npm install
npm test # conformance fixtures + unit tests (vitest)
npm run lint
npm run typecheck
npm run build # tsup builds for every package
npm run size -w @pulse-circle/web # enforce the 10 KB budget
Conformance fixtures
protocol/fixtures is the source of truth for
cross-platform behaviour. Each JSON file is a scenario ("these API calls
produce these HTTP requests"); every SDK runs them through a shared
fixture runner, and the server replays them against
real ingestion. Change behaviour by changing a fixture, and every platform's
CI tells you who's out of contract.
Releasing
Versions are independent per package. Bump the version in the package's
package.json, then push a tag:
core-v0.1.0 | web-v0.1.0 | react-native-v0.1.0
The publish workflow verifies the tag
matches package.json, runs the full test + build + size gate, and publishes
to npm with provenance.
License
MIT © Pulse Circle Studio