# `LiveLayerTracker`

The visitor tracking class. Resolves a stable identity (FingerprintJS + localStorage fallback), then optionally auto-tracks page views, clicks, scroll depth. Conversations carry the same visitor ID, so your CRM sees one continuous timeline.

```ts
import { LiveLayerTracker } from "@livelayer/sdk";

const tracker = new LiveLayerTracker({
  agentId: "agt_abc123",
  apiBase: "https://livelayer.app",
  autoTrack: true,
  autoTrackClicks: true,
});

const visitor = await tracker.init();
// → { id: "vis_abc123", isReturning: true, sessionCount: 4 }
```

For the script-tag version (drop-in HTML), see [Visitor tracking](/docs/develop/script-tag/visitor-tracking).

## Constructor

```ts title="TrackerConfig"
interface TrackerConfig {
  agentId: string;
  apiBase?: string;
  autoTrack?: boolean;
  autoTrackClicks?: boolean;
}
```

<!-- omitted: ParamsTable -->

## Methods

```ts
async init(): Promise<VisitorInfo | null>
identify(attributes: Partial<VisitorAttrs>): void
track(eventName: string, data?: Record<string, unknown>): void
destroy(): void
```

<ParamsTable params={[
  { name: "init",     type: "() => Promise<VisitorInfo | null>", required: false, description: "Bootstrap the tracker. Resolves visitor identity, sets up auto-tracking. Returns visitor info or null if blocked entirely." },
  { name: "identify", type: "(attrs) => void", required: false, description: "Attach attributes to the current visitor (email, name, plan, custom fields). Subsequent events carry these." },
  { name: "track",    type: "(name, data?) => void", required: false, description: "Track a custom event with optional payload." },
  { name: "destroy",  type: "() => void", required: false, description: "Clean up: flush pending events, remove auto-track listeners. Call on logout or unmount." },
]} />

## Visitor info shape

```ts
interface VisitorInfo {
  id: string;              // "vis_abc123"
  isReturning: boolean;    // True on subsequent sessions
  sessionCount: number;    // Total resolved sessions for this visitor
}
```

## Common patterns

### React app — boot once, reuse

```tsx title="tracker-context.tsx"
"use client";
import { LiveLayerTracker, type VisitorInfo } from "@livelayer/sdk";
import { createContext, useContext, useEffect, useState, type ReactNode } from "react";

const Ctx = createContext<{ tracker: LiveLayerTracker | null; visitor: VisitorInfo | null }>({
  tracker: null,
  visitor: null,
});

export function TrackerProvider({ children, agentId }: { children: ReactNode; agentId: string }) {
  const [tracker, setTracker] = useState<LiveLayerTracker | null>(null);
  const [visitor, setVisitor] = useState<VisitorInfo | null>(null);

  useEffect(() => {
    const t = new LiveLayerTracker({ agentId });
    t.init().then((v) => {
      setTracker(t);
      setVisitor(v);
    });
    return () => t.destroy();
  }, [agentId]);

  return <Ctx.Provider value={{ tracker, visitor }}>{children}</Ctx.Provider>;
}

export function useTracker() {
  return useContext(Ctx);
}
```

Use it from any component:

```tsx
const { tracker, visitor } = useTracker();

if (visitor?.isReturning) {
  // Show "Welcome back" banner
}

const onCheckout = () => {
  tracker?.track("checkout_started", { plan: "pro", amount: 29 });
};
```

### Identify after login

When you know who the user is, attach attributes:

```ts
async function onLogin(user: { email: string; name: string; plan: string }) {
  tracker.identify({
    email: user.email,
    name: user.name,
    plan: user.plan,
  });
}
```

The visitor ID stays the same; the new attributes attach to it. Conversations from this point forward carry these attributes through the agent transcript and your dashboard.

### Track custom events alongside auto-tracking

```ts
// Auto-tracking captures page views and clicks automatically.
// Add domain-specific events on top.
tracker.track("watched_demo_video", {
  videoId: "intro-2026",
  durationSeconds: 47,
});

tracker.track("started_trial", {
  source: "homepage_hero_cta",
});
```

### Opting out

Visitors who opt out (e.g., GDPR consent banner choice):

```ts
tracker.destroy();
```

This stops sending events and removes all auto-track listeners. Re-init when the visitor opts back in.

`Do Not Track` is respected automatically — no events fire when `navigator.doNotTrack === "1"`.

### Excluding sensitive elements

Mark any element with `data-ll-private="true"` to exclude it from auto-tracked clicks:

```html
<section data-ll-private="true">
  <input name="ssn" />
  <button>Save</button>  <!-- Click on this won't be tracked -->
</section>
```

## Event batching and delivery

- Events are queued client-side.
- Flush triggers: every 5 seconds, OR when the queue reaches 50 events, OR when the page unloads.
- Failed POSTs retry with exponential backoff: 1s, 2s, 4s, 8s.
- Events that can't be delivered after 5 retries are dropped (no permanent buffer).

## Read next

- [Script-tag visitor tracking](/docs/develop/script-tag/visitor-tracking) — drop-in HTML version
- [`LiveKitSession`](/docs/develop/npm/sdk/livekit-session) — agent session that carries visitor ID through
