Trackkit is a lightweight, provider-agnostic analytics SDK with a single facade for Umami, Plausible, and GA4 (Measurement Protocol).
SSR-aware • CSP-friendly • Consent-gated • No remote scripts
Every call flows through the same runtime pipeline — you never need to think about timing, readiness, or consent yourself:
- Lazy-load the provider adapter (only the one you configure is bundled).
- Queue events while the provider or consent isn't ready yet.
- Respect consent, domain rules, DNT, and localhost settings before anything is sent.
- Flush the queue through PolicyGate → Consent → Provider → Transport.
This means you can call track() at any point — during SSR, before the provider script has loaded, or before a user has responded to a consent banner — and Trackkit will do the right thing.
- Privacy-first — cookieless by default for Umami & Plausible; consent-aware for GA4.
- No remote scripts — CSP-friendly, no injected
<script>tags; safe for strict environments. - Small & fast — tree-shakeable core; only the adapter you use is bundled.
- Multi-provider — run Umami/Plausible for everyone and layer GA4 for consented users.
- SSR aware — queue on the server, hydrate and replay on the client.
- Typed DX — conditional tuple types, debug logs, queue inspection, provider state machine.
Visit Trackkit's full documentation site for:
To run the documentation site locally, run pnpm docs:dev and open http://localhost:5173.
This repo uses pnpm workspaces. All commands below are run from the repository root.
npm i trackkit # or: pnpm add trackkit / yarn add trackkitimport { createAnalytics } from 'trackkit';
const analytics = createAnalytics({
provider: {
name: 'umami', // 'umami' | 'plausible' | 'ga4' | 'noop'
site: '94db1cb1-74f4-4a40-ad6c-962362670409',
host: 'https://analytics.example.com', // required if self-hosting/custom domain
},
debug: true,
});
// send events
analytics.pageview();
analytics.track('signup_submitted', { plan: 'starter' });Trackkit supports a unified
siteidentifier for all providers; see the Configuration reference.
The example above uses the instance API.
Most apps should prefer instances:
- You can scope analytics to a particular app, tab, widget, or test.
- It’s easier to reason about SSR, multi-tenant setups, and tests.
- You avoid hidden global state.
However, if you prefer a global approach, you can use the included singleton helpers instead:
// Singleton convenience API
import { init, pageview, track } from 'trackkit';
init({ provider: { name: 'umami', site: '...' } });
pageview();
track('signup_submitted', { plan: 'starter' });Internally, both forms hit the same core sdk.
import { createAnalytics /* or init, grantConsent */ } from 'trackkit';
const analytics = createAnalytics({
provider: { name: 'ga4', site: 'G-XXXXXXXXXX' },
consent: {
initialStatus: 'pending', // 'pending' | 'granted' | 'denied'
requireExplicit: true, // default: true
allowEssentialOnDenied: false, // default: false
},
});
// later, from your consent banner:
analytics.grantConsent(); // or denyConsent();Trackkit is consent-aware: events are queued until consent and provider readiness allow them to be sent, and non-essential analytics follow your configured policy. All built-in providers allow for consent management.
For full behaviour, see the Consent & Privacy guide.
Trackkit reads build-time/public env vars (with common bundler prefixes):
| Var | Meaning |
|---|---|
TRACKKIT_PROVIDER |
default provider (umami | plausible | ga4 | noop) |
TRACKKIT_SITE |
provider site/measurement ID |
TRACKKIT_HOST |
analytics host (self-host/custom domain) |
TRACKKIT_QUEUE_SIZE |
max buffered events (default: 50) |
TRACKKIT_DEBUG |
true/false |
For runtime injection and SSR-safe config, see the Configuration reference.
Bundlers:
- Vite →
VITE_TRACKKIT_* - CRA →
REACT_APP_TRACKKIT_* - Generic/Node →
TRACKKIT_*
For Next.js, prefer runtime injection or a small custom loader that passes values into init at startup (see docs/reference/configuration.md for details).
Trackkit supports multiple providers.
See the Choosing a Provider guide for more information.
Trackkit queues events during server rendering and hydrates them on the client. Server-side calls must use the SSR API (trackkit/ssr); client code hydrates automatically.
See the Server-Side Rendering guide for full semantics.
Trackkit sends all data via fetch — no injected <script> tags. Add the providers you use to connect-src:
pnpm installpnpm test
pnpm test:coverage # with coveragepnpm typecheckpnpm lintpnpm buildpnpm deadcode # full analysis
pnpm deadcode:ci # ci-mode
pnpm size # bundle size reportspnpm docs:dev # run the docs site locally
pnpm docs:build # generate static build (docs/.vitepress/dist)
pnpm docs:preview # preview the production buildThe documentation site is deployed via Cloudflare Pages.
Publishing a release consists of:
pnpm releaseThis runs:
- clean
- build
- defaults:inject
- defaults:assert
To build docs API:
pnpm release:docsNPM publication is handled through the prepublishOnly script in the package.
See CONTRIBUTING.md for:
- repository structure
- development environment
- tests and release rules
- provider guidelines
- PR expectations
MIT © Enkosi Ventures