@atribu/tracker
v0.1.3
Published
Official Atribu tracking SDK — marketing attribution that shows which ads drive revenue
Maintainers
Readme
The official browser tracking SDK for Atribu — page views, sessions, engagement, outbound links, file downloads, form submissions, booking detection, and a Meta Pixel bridge, all auto-captured.
Building a server-side integration instead? See
@atribu/nodefor sending WhatsApp / Instagram messages, OAuth flow helpers, and signed webhook verification.
Installation
npm install @atribu/trackerQuick Start
import { init } from "@atribu/tracker";
init({
trackingKey: "trk_live_...", // from Tracking Settings → Ingest Keys
});That's it. Page views, sessions, engagement, outbound links, file downloads, form submissions, and booking detection are all auto-captured.
What's Auto-Captured
| Signal | What & When |
|---|---|
| Page views | init, SPA navigation (pushState/replaceState/popstate/hashchange), bfcache restoration |
| Sessions | 30 min inactivity timeout (configurable 1–120), persisted across page loads |
| Engagement | Scroll depth (px + %), time on page — sent on page exit |
| Outbound links | External link clicks via sendBeacon |
| File downloads | pdf · xlsx · docx · csv · zip · mp4 · and 30+ more extensions |
| Form submissions | Auto-detected on standard <form> submits AND GHL-style <div> form fetches |
| Booking detection | Calendly · Cal.com · GoHighLevel · custom postMessage patterns |
| Meta Pixel bridge | Intercepts fbq() calls for server-side CAPI dedup |
| Bot filtering | Blocks traditional bots; tags AI agents (ChatGPT, Claude, Perplexity, Gemini) as visitor_type: "ai_agent" |
| Declarative events | data-atribu-event HTML attributes — no-code event tracking |
Configuration
init({
trackingKey: "trk_live_...", // required
apiHost: "https://tracking.example.com", // custom tracking domain
trackingEndpoint: "...", // full override of collect URL
interceptMetaFbq: true, // mirror Meta Pixel events (default true)
metaBridgePageview: false, // mirror Meta PageView too (default false)
customProperties: { tier: "pro" }, // static props on every event
transformRequest: (event) => event, // event middleware (return null to suppress)
ignoredPages: ["/admin/*"], // URL patterns with `*` wildcards
sessionTimeoutMinutes: 30, // 1–120 min
sessionMode: "inactivity_only", // or "inactivity_or_source_change"
});| Option | Type | Default | Description |
|---|---|---|---|
| trackingKey | string | required | Ingest Key from Tracking Settings → Ingest Keys |
| apiHost | string | window.location.origin | Origin for the collect endpoint |
| trackingEndpoint | string | ${apiHost}/api/tracking/collect | Full override for collect URL |
| interceptMetaFbq | boolean | true | Mirror fbq() calls to Atribu |
| metaBridgePageview | boolean | false | Also mirror Meta PageView events |
| customProperties | object \| function | — | Extra properties merged into every event |
| transformRequest | function | — | Return null/false to suppress, or modified event |
| ignoredPages | string[] | — | URL patterns with * wildcards |
| sessionTimeoutMinutes | number | 30 | Session inactivity timeout (1–120) |
| sessionMode | 'inactivity_only' \| 'inactivity_or_source_change' | 'inactivity_only' | Whether to also reset a session when a new source fingerprint appears mid-session |
Custom Events
import { track } from "@atribu/tracker";
track("signup", { plan: "pro", source: "pricing-page" });Revenue Tracking
import { trackRevenue } from "@atribu/tracker";
trackRevenue("purchase", 99.99, "USD", { plan: "enterprise" });User Identification
Link a visitor to a known user for cross-device attribution. Two complementary APIs:
import { identify, setUserId } from "@atribu/tracker";
// Identify with PII for server-side identity resolution (joins this visitor
// to your customer_profile via the identity graph):
identify({
email: "[email protected]",
firstName: "Jane",
lastName: "Doe",
phone: "+1234567890",
});
// Attach a stable user_id to every future event (e.g. on login):
setUserId("user_abc123");
// Clear it on logout:
setUserId(null);setUserId is the simpler one — it just stamps your application's user ID on every event from this point forward. identify does the heavier work of resolving the visitor to a customer profile via the identity graph (anonymous_id ↔ email ↔ phone).
Consent Management
import { setConsent } from "@atribu/tracker";
setConsent({ analytics: true, marketing: false });Consent state is persisted to localStorage and attached to every event.
Lifecycle Controls
import { flush, reset } from "@atribu/tracker";
flush(); // force-send queued events (e.g. before navigating away)
reset(); // clear visitor ID, session, all stored state (e.g. on logout)Singleton Access
Initialize once, retrieve from anywhere:
import { init, getTracker } from "@atribu/tracker";
// In your app's entry point:
init({ trackingKey: "trk_live_..." });
// In any other module:
const atribu = getTracker();
atribu.track("button_click", { label: "hero-cta" });Framework Examples
React
import { useEffect } from "react";
import { init } from "@atribu/tracker";
function App() {
useEffect(() => {
init({ trackingKey: "trk_live_..." });
}, []);
return <>{/* your app */}</>;
}Next.js (App Router)
// app/providers.tsx
"use client";
import { useEffect } from "react";
import { init } from "@atribu/tracker";
export function AtribuProvider({ children }: { children: React.ReactNode }) {
useEffect(() => {
init({ trackingKey: "trk_live_..." });
}, []);
return <>{children}</>;
}// app/layout.tsx
import { AtribuProvider } from "./providers";
export default function RootLayout({ children }) {
return (
<html><body><AtribuProvider>{children}</AtribuProvider></body></html>
);
}Vue 3
import { onMounted } from "vue";
import { init } from "@atribu/tracker";
onMounted(() => init({ trackingKey: "trk_live_..." }));Svelte
import { onMount } from "svelte";
import { init } from "@atribu/tracker";
onMount(() => init({ trackingKey: "trk_live_..." }));Vanilla JS
<script type="module">
import { init, track } from "@atribu/tracker";
init({ trackingKey: "trk_live_..." });
document.querySelector("#signup-btn").addEventListener("click", () => {
track("signup", { source: "landing" });
});
</script>Declarative Events
Track events without writing JavaScript using HTML data attributes:
<button
data-atribu-event="signup"
data-atribu-prop-plan="pro"
data-atribu-revenue="99.99"
data-atribu-currency="USD"
>
Sign Up
</button>The tracker auto-captures clicks on elements with data-atribu-event and extracts:
- Event name from
data-atribu-event - Custom properties from
data-atribu-prop-*attributes - Revenue from
data-atribu-revenue+data-atribu-currency
Meta Pixel Bridge
When interceptMetaFbq is true (the default), the tracker intercepts fbq() calls from the Meta Pixel and mirrors them to Atribu for server-side deduplication and attribution. The event_id passed through is the same one Meta CAPI sees, so Pixel↔CAPI dedup works automatically.
Privacy
- First-party only. All data goes to your configured endpoint. No third-party tracking, no cross-site identifiers.
- No cookies set for tracking. Visitor + session IDs live in
localStorage. The tracker reads_fbp/_fbccookies (set by Meta Pixel) only when present, for CAPI match quality. - Consent-aware.
setConsent()state is persisted and attached to every event. Events fired before consent are queued and replayed once consent is granted. - Bot filtering on-device. Traditional bots are blocked at the client level. AI agents (ChatGPT, Claude, Perplexity, Gemini) are tracked but tagged
visitor_type: "ai_agent"so you can filter them in reporting.
Developer Exclusion
Exclude yourself from tracking during development:
localStorage.atribu_ignore = "true";Remove it to re-enable tracking:
delete localStorage.atribu_ignore;TypeScript
Full TypeScript support with all types exported:
import type {
AtribuConfig,
AtribuClient,
TrackOptions,
IdentifyInput,
ConsentPayload,
TrackingEvent,
CustomPropertiesContext,
} from "@atribu/tracker";How It Works
This package bundles the full Atribu tracker runtime (the same code served by atribu-tracker.js). When you call init():
- Window configuration variables are set from your config.
- The tracker runtime initializes (bot detection, outbox, event listeners).
session_startandpage_vieware auto-fired.- SPA navigation, engagement, and all auto-capture modules activate.
In SSR environments (Node.js, Next.js server components), init() returns a silent no-op client — safe to import + call anywhere.
Runtime Support
| Runtime | Supported | |---|---| | Modern browsers (Chrome, Safari, Firefox, Edge) | ✅ | | Mobile webviews (iOS, Android) | ✅ | | SSR (Node 18+, Next.js server) | ✅ — no-op fallback | | Bun (browser bundle) | ✅ | | Deno | ❌ (no DOM) |
Links
License
MIT
