> ## Documentation Index
> Fetch the complete documentation index at: https://docs.result.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Web analytics

> Pageviews, sessions and custom events - no script tag, no cookies.

```ts theme={"dark"}
import { createClient } from "@resultdev/sdk";

export const backend = createClient({
  baseUrl: process.env.NEXT_PUBLIC_BACKEND_URL!,
  anonKey: process.env.NEXT_PUBLIC_BACKEND_ANON_KEY!,
  analytics: { siteId: "SITE_ID" },
});
```

`siteId` is the workspace id shown on the dashboard's Analytics > Web page.

That's the whole setup. When the client is created in a browser it tracks
pageviews (including SPA route changes via `pushState`/`replaceState`/
`popstate`/`hashchange` and back-forward cache restores), pageleaves, and
sessions on its own. No cookies, no fingerprinting: a random visitor id in
localStorage and a session id that rotates after 30 idle minutes.

<Note>
  In Next.js, import the client from a client component that the root layout
  renders - otherwise nothing runs in the browser. Tracking is a no-op during
  SSR and in server code.
</Note>

## Custom events

```ts theme={"dark"}
backend.analytics.track("Signup", { plan: "pro" }); // name capped at 64 chars
backend.analytics.identify(user.id);                // attach your own user id to later events
```

Declarative click events work without any JS:

```html theme={"dark"}
<button data-wa-event="Signup" data-wa-event-plan="pro">Sign up</button>
```

That click sends event `Signup` with prop `plan=pro`.

## Options

| Option          | Default  | What it does                               |
| --------------- | -------- | ------------------------------------------ |
| `siteId`        | required | Workspace id from Analytics > Web          |
| `autoTrack`     | `true`   | `false` disables automatic pageviews       |
| `domains`       | all      | `string[]` - only track on these hostnames |
| `excludeSearch` | `false`  | Drop `?query` from tracked URLs            |
| `excludeHash`   | `false`  | Drop `#hash` from tracked URLs             |
| `endpoint`      | managed  | Self-hosting only                          |

## Good to know

* Visitors can opt out on their own machine with
  `localStorage.rwa_disable = "1"`.
* Automation (`navigator.webdriver`) is never tracked.
* If the `wa.js` script tag is also on the page, whichever loads first wins -
  nothing double-counts.
