@betterumami/core
v0.2.0
Published
Framework-agnostic tracker core for BetterUmami. Drop-in replacement for the script-tag tracker.
Readme
@betterumami/core
Framework-agnostic BetterUmami tracker. Drop-in replacement for the script-tag tracker — same POST /api/send payload, headers, and cache-token handling.
Install
npm install @betterumami/coreUsage
import { init, track, trackEvent, trackPageview, identify, getSession } from '@betterumami/core';
init({
websiteId: 'your-website-id',
hostUrl: 'https://analytics.example.com', // optional, defaults to window.location.origin
});
trackEvent('signup-button', { plan: 'pro' }); // custom event
trackPageview(); // manual pageview
identify('user-123', { plan: 'pro' }); // visitor identityAutomatic pageviews fire on load and on SPA route changes (History API pushState/replaceState hooks + popstate). Elements with data-umami-event="name" are tracked on click.
How to tell the SDK actually loaded
After init() runs you can confirm it two ways:
In the DOM. A no-op marker is injected into
<head>:<script type="text/betterumami" data-betterumami-marker data-website-id="abc-123" data-version="0.1.2"></script>The
typeis non-JS so the browser stores it as text but never executes it. Open DevTools → Elements →<head>and look for the marker.In DevTools. A
window.betterumaminamespace is installed:window.betterumami.track('devtools-test'); window.betterumami.getSession(); window.betterumami.version; // '0.1.2'
Debugging failures
Network or server errors no longer fail silently. Failed sends log a warning so you can spot them in the console:
[BetterUmami] failed to send event TypeError: Failed to fetch
[BetterUmami] failed to send event 500 Internal Server Error (https://api.example.com/api/send)If you want to inspect payloads without sending anything, set dryRun: true. Every event is logged to console.log instead of POSTed — useful for local development.
Config
| Option | Type | Default | Description |
|---|---|---|---|
| websiteId | string | — | Required. The website ID from your BetterUmami dashboard. |
| hostUrl | string | window.location.origin | Origin of the BetterUmami instance. |
| endpoint | string | /api/send | Collection path. Combined with hostUrl at init. |
| autoTrack | boolean | true | Enable automatic tracking (clicks, pageviews) on init. |
| autoPageview | boolean | true | Send a pageview on load and on SPA route changes. Set to false if your framework already reports its own route changes. |
| trackPopstate | boolean | true | Also listen to popstate (back/forward). |
| domains | string \| string[] | — | Only track on these hostnames. Comma-separated or array. |
| excludeSearch | boolean | false | Strip the query string from tracked URLs. |
| excludeHash | boolean | false | Strip the hash from tracked URLs. |
| doNotTrack | boolean | false | Respect the browser's Do Not Track setting. |
| tag | string | — | Tag attached to every event. |
| credentials | RequestCredentials | 'omit' | fetch credentials mode. |
| beforeSend | (type, payload) => payload \| null | — | Inspect / modify / drop every payload. Return null to drop. |
| nonce | string | — | CSP nonce to apply to the in-page marker <script>. |
| dryRun | boolean | false | Log payloads to console.log instead of POSTing. Nothing leaves the browser. |
SPA route tracking
@betterumami/core patches history.pushState and history.replaceState, and listens for popstate. No router integration is required for any framework. Disable with autoPageview: false if you report route changes yourself (e.g. with appWithTranslation in Next.js).
Programmatic API
| Function | Purpose |
|---|---|
| init(config) | Initialize the SDK. Idempotent — re-calling is a no-op. |
| track(name?, data?) | Send a pageview, named event, or arbitrary payload. |
| trackEvent(name, data?) | Convenience wrapper for track(name, data). |
| trackPageview(url?) | Force a pageview (optionally overriding the URL). |
| identify(id, data?) | Attach a stable visitor ID and/or session data. |
| getSession() | Returns { cache, website } for inspection. |
| destroy() | Remove listeners, marker, and window.betterumami. Mainly for tests / HMR. |
Why is there a window.betterumami global?
For parity with upstream Umami (window.umami) and to make the SDK discoverable. Other libraries can detect that the SDK is loaded by checking window.betterumami; users can run window.betterumami.track('foo') from the console without importing anything.
TypeScript
The package ships .d.ts files. All public APIs (init, track, trackEvent, trackPageview, identify, getSession, BetterUmamiConfig, EventData) are typed.
