HitKeep NPM Package for React, Vue, Angular, and Astro
Script tags are awkward in component frameworks: they live outside the bundler, they offer no types, and every custom event becomes an unchecked window.hk?.event?.() call. @hitkeep/tracker packages the same tracker that ships as hk.js — built from the same source, with the same privacy behavior — as a fully typed ES module.
npm install @hitkeep/trackerThe package is published on npm as @hitkeep/tracker and released in lockstep with HitKeep itself.
import { init, track } from '@hitkeep/tracker';
init({ host: 'https://your-hitkeep.example' });
track('signup_clicked', { plan: 'pro' });host is the origin (or mounted path prefix) your HitKeep instance serves the tracker from — the same URL the hk.js snippet would load from, including custom tracking domains. The tracker derives /ingest, /ingest/event, and /ingest/web-vitals from it.
Pageviews are captured automatically on init, including history-based SPA navigations, so none of the frameworks below need router wiring. Events tracked before init runs are queued in memory and flushed once the tracker starts. The package is published with every HitKeep release and its version matches the product version.
Framework integration
Section titled “Framework integration”Initialize once in a client-side module. In a Vite or CRA-style app, the app entry is fine:
import { init } from '@hitkeep/tracker';
init({ host: 'https://your-hitkeep.example' });In Next.js, init must run in the browser, so use a client component mounted in the root layout:
'use client';
import { useEffect } from 'react';import { cleanup, init } from '@hitkeep/tracker';
export function Analytics() { useEffect(() => { init({ host: 'https://your-hitkeep.example' }); return cleanup; }, []);
return null;}Route changes are tracked automatically through history patching. Track custom events from any component:
import { track } from '@hitkeep/tracker';
<button onClick={() => track('cta_clicked', { location: 'hero' })}>Get started</button>Initialize in your app entry, or wrap it in a small plugin:
import { createApp } from 'vue';import { init } from '@hitkeep/tracker';import App from './App.vue';
init({ host: 'https://your-hitkeep.example' });
createApp(App).mount('#app');Vue Router navigations use the history API and are tracked automatically. Track custom events from any component:
<script setup lang="ts">import { track } from '@hitkeep/tracker';</script>
<template> <button @click="track('cta_clicked', { location: 'hero' })">Get started</button></template>Initialize through an app initializer in app.config.ts:
import { ApplicationConfig, provideAppInitializer } from '@angular/core';import { init } from '@hitkeep/tracker';
export const appConfig: ApplicationConfig = { providers: [ provideAppInitializer(() => { init({ host: 'https://your-hitkeep.example' }); }) ]};Angular Router navigations go through the history API and are tracked automatically — no Router.events subscription is needed. Track custom events from any component or service:
import { track } from '@hitkeep/tracker';
onUpgradeClick(): void { track('plan_upgraded', { plan: 'pro' });}Add a module script to your base layout. Astro bundles it like any other import:
<html lang="en"> <body> <slot /> <script> import { init } from '@hitkeep/tracker';
init({ host: 'https://your-hitkeep.example' }); </script> </body></html>For a mostly static Astro site without view transitions, the hk.js snippet works equally well — the npm package earns its place once you track typed custom events from islands:
import { track } from '@hitkeep/tracker';
track('newsletter_subscribed', { source: 'footer' });With <ClientRouter /> view transitions enabled, navigations use the history API and are tracked automatically.
Configuration
Section titled “Configuration”Every option maps to a snippet data attribute where one exists. Defaults match the snippet’s behavior.
init({ host: 'https://your-hitkeep.example', // required autoCapturePageviews: true, autoTrackSpaNavigation: true, outboundLinks: true, fileDownloads: true, formSubmissions: true, webVitals: false, useBeacon: true, respectDoNotTrack: true, captureOnLocalhost: false, bindToWindow: true});| Option | Default | Snippet equivalent | Effect |
|---|---|---|---|
host |
— | script src origin |
HitKeep origin or path prefix that receives pageviews, events, and Web Vitals |
autoCapturePageviews |
true |
always on | Send a pageview when init runs |
autoTrackSpaNavigation |
true |
data-disable-spa-tracking |
Track history-based route changes as pageviews |
outboundLinks |
true |
data-disable-outbound-tracking |
Automatic outbound_click events |
fileDownloads |
true |
data-disable-download-tracking |
Automatic file_download events |
formSubmissions |
true |
data-disable-form-tracking |
Automatic form_submit events |
webVitals |
false |
data-enable-web-vitals |
Load ${host}/hk-vitals.js and send opt-in Web Vitals samples |
useBeacon |
true |
data-disable-beacon |
Prefer navigator.sendBeacon() with keepalive fetch fallback |
respectDoNotTrack |
true |
data-collect-dnt |
Drop tracking when the browser sends DNT: 1 |
captureOnLocalhost |
false |
none | Track on localhost and 127.0.0.1, which are blocked by default |
bindToWindow |
true |
always on | Expose window.hk.event for snippet-compatible callers |
trackerSource |
@hitkeep/tracker |
data-hitkeep-source |
Attribution source reported with every request |
API reference
Section titled “API reference”All functions are exported from the package root with full TypeScript declarations.
function init(config: TrackerConfig): TrackerHandle;function track(name: string, properties?: Record<string, unknown>): void;function trackPageview(): void;function cleanup(): void;initstarts the tracker and returns a handle withtrack,trackPageview, andcleanup. It is idempotent: a second call — or a call on a page where thehk.jssnippet already bootstrapped — logs a debug notice and does not double-track.trackrecords a named event with optional properties. Calls made beforeinitare queued in memory and flushed oninit.trackPageviewsends a manual pageview, for use withautoCapturePageviews: false.cleanupremoves all listeners, restores the patched history methods, and allows re-initialization. Useful for hot module replacement and test teardown.
Visitor opt-out
Section titled “Visitor opt-out”The bundled tracker ships inside your application bundle instead of loading from your analytics host, so content blockers do not filter it. Offer visitors an explicit opt-out:
function blockTrackingForMe(): void;function enableTrackingForMe(): void;function isTrackingEnabled(): boolean;The opt-out persists in localStorage under hk_ignore and is honored by both this package and the hk.js snippet.
Typed e-commerce events
Section titled “Typed e-commerce events”Typed wrappers emit the event names and property shapes from Ecommerce Analytics, so checkout instrumentation is checked by the compiler:
import { trackPurchase } from '@hitkeep/tracker';
trackPurchase({ transaction_id: 'tx-1042', value: 49.9, currency: 'EUR', items: [{ item_id: 'sku-1', item_name: 'Starter Plan', quantity: 1, price: 49.9 }]});function trackViewItem(properties: ItemEventProperties): void; // view_itemfunction trackAddToCart(properties: ItemEventProperties): void; // add_to_cartfunction trackBeginCheckout(properties: ItemEventProperties): void; // begin_checkoutfunction trackPurchase(properties: PurchaseProperties): void; // purchaseDifferences from the hk.js snippet
Section titled “Differences from the hk.js snippet”The runtime behavior — delivery, retries, duplicate suppression, session storage, privacy boundaries — is identical to Tracker Architecture because it is the same code. The differences are in how the tracker reaches the page:
- Explicit
hostrequired. The snippet derives endpoints from its own script URL; a bundled module has no script URL. - Localhost stays blocked by default. Set
captureOnLocalhost: truein development builds when you want local hits recorded. - Content blockers do not filter it, so ship the visitor opt-out above where your privacy posture calls for one.
- Attribution is reported as
@hitkeep/trackerwith the package version, visible in ingest payloads astsrcandtv. - Updates arrive through npm, not automatically with your HitKeep instance. Keep major versions aligned with your self-hosted instance version.
Related
Section titled “Related”- Tracker Architecture
- Automatic Events
- Custom Events
- Custom Tracking Domains
- Server-Side Tracking
- Ecommerce Analytics
- Web Vitals Analytics
Prefer not to run the instance behind the tracker yourself? Start with HitKeep Cloud →