Atribu
Tracking

Framework Guides

Set up @atribu/tracker in React, Next.js, Vue 3, Svelte, and vanilla JavaScript

Detailed setup instructions for each framework. The @atribu/tracker package works with any JavaScript framework thanks to its SSR-safe design.

React

Create a provider component that initializes the tracker once:

src/components/AtribuProvider.tsx
import { useEffect } from "react";
import { init } from "@atribu/tracker";

export function AtribuProvider({ children }: { children: React.ReactNode }) {
  useEffect(() => {
    init({
      trackingKey: "trk_live_your_key",
      // Optional: customize behavior
      sessionTimeoutMinutes: 30,
      enableWebVitals: true,
    });
  }, []);

  return <>{children}</>;
}
src/main.tsx
import { AtribuProvider } from "./components/AtribuProvider";

function App() {
  return (
    <AtribuProvider>
      <YourApp />
    </AtribuProvider>
  );
}

Tracking events in components

src/components/PricingButton.tsx
import { track } from "@atribu/tracker";

export function PricingButton() {
  return (
    <button onClick={() => track("pricing_clicked", { plan: "pro" })}>
      View Pricing
    </button>
  );
}

Identifying users after form submission

src/components/ContactForm.tsx
import { identify } from "@atribu/tracker";

export function ContactForm() {
  const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    const data = new FormData(e.currentTarget);

    identify({
      email: data.get("email") as string,
      firstName: data.get("name") as string,
    });

    // Submit form...
  };

  return (
    <form onSubmit={handleSubmit}>
      <input name="name" placeholder="Name" />
      <input name="email" type="email" placeholder="Email" />
      <button type="submit">Submit</button>
    </form>
  );
}

Next.js (App Router)

Client component required

The tracker uses browser APIs (window, localStorage). It must be initialized in a Client Component with the "use client" directive.

src/components/AtribuProvider.tsx
"use client";

import { useEffect } from "react";
import { init } from "@atribu/tracker";

export function AtribuProvider({ children }: { children: React.ReactNode }) {
  useEffect(() => {
    init({ trackingKey: "trk_live_your_key" });
  }, []);

  return <>{children}</>;
}
src/app/layout.tsx
import { AtribuProvider } from "@/components/AtribuProvider";

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        <AtribuProvider>{children}</AtribuProvider>
      </body>
    </html>
  );
}

SSR safe

If you accidentally import @atribu/tracker in a Server Component, init() returns a silent no-op client. No errors, no crashes — it simply does nothing until running in the browser.


Vue 3

src/App.vue
<script setup lang="ts">
import { onMounted } from "vue";
import { init } from "@atribu/tracker";

onMounted(() => {
  init({ trackingKey: "trk_live_your_key" });
});
</script>

<template>
  <RouterView />
</template>

Tracking events

src/components/PricingCard.vue
<script setup lang="ts">
import { track } from "@atribu/tracker";

function handleClick() {
  track("pricing_clicked", { plan: "pro" });
}
</script>

<template>
  <button @click="handleClick">View Pricing</button>
</template>

Svelte

src/App.svelte
<script>
  import { onMount } from "svelte";
  import { init } from "@atribu/tracker";

  onMount(() => {
    init({ trackingKey: "trk_live_your_key" });
  });
</script>

<slot />

Vanilla JavaScript

index.html
<script type="module">
  import { init, track, identify } from "@atribu/tracker";

  init({ trackingKey: "trk_live_your_key" });

  // Track a custom event
  document.querySelector("#cta").addEventListener("click", () => {
    track("cta_clicked");
  });

  // Identify after form submit
  document.querySelector("form").addEventListener("submit", (e) => {
    const email = e.target.querySelector('[name="email"]').value;
    identify({ email });
  });
</script>

SPA navigation

The tracker automatically detects Single Page App navigation via:

  • history.pushState and history.replaceState interception
  • popstate event listener
  • hashchange event listener

Each navigation fires a new page_view event and resets engagement tracking (scroll depth, time on page). No additional configuration needed.


SSR environments

In server-side rendering (Next.js, Nuxt, SvelteKit SSR), the tracker handles the missing window gracefully:

  1. init() detects typeof window === "undefined"
  2. Returns a no-op client where all methods (track, identify, etc.) are empty functions
  3. No errors thrown, no window is not defined crashes
  4. When the code later runs in the browser, init() activates normally

This means you can safely import and call tracker functions anywhere — server or client.

On this page