# SvelteKit

Add ProductLense to src/app.html in a SvelteKit app, then identify signed-in users from the root layout.

In SvelteKit, every page is rendered into `src/app.html`, so the script goes in its head once. Client-side navigation is recorded through the history API, and prerendered or server-rendered pages work the same way.

## Add the script

Paste the queue stub and the script tag before `%sveltekit.head%`. Replace `SITE_ID` with the id from Settings → Sites in the ProductLense dashboard.

```html title="src/app.html" {5-6}
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <script>window.productlense=window.productlense||function(){(window.productlense.q=window.productlense.q||[]).push(arguments)}</script>
    <script defer data-site="SITE_ID" src="https://api.productlense.app/a.js"></script>
    %sveltekit.head%
  </head>
  <body>
    <div style="display: contents">%sveltekit.body%</div>
  </body>
</html>
```

If you set a Content Security Policy in `svelte.config.js` (`kit.csp`), add `https://api.productlense.app` to `script-src` and `connect-src`. In nonce mode, give the inline stub `nonce="%sveltekit.nonce%"`; otherwise drop the stub and call `window.productlense?.(...)` with optional chaining.

## Identify users

Declare the global once:

```ts title="src/app.d.ts"
declare global {
  interface Window {
    productlense?: (...args: unknown[]) => void;
  }
}

export {};
```

Then identify from the root layout, with the signed-in user from your layout data:

```svelte title="src/routes/+layout.svelte" {5}
<script lang="ts">
  let { data, children } = $props();

  $effect(() => {
    if (data.user) window.productlense?.('identify', data.user.id);
  });
</script>

{@render children()}
```

Use the same id you store on the customer in your billing provider; see [how payments are attributed](/docs/revenue/attribution).

## Custom events

```svelte
<button onclick={() => window.productlense?.('event', 'Upgrade clicked', { plan: 'growth' })}>
  Upgrade
</button>
```

See [custom events](/docs/track/custom-events) for naming rules.

## Verify your installation

1. Deploy, then open your site in a normal browser window.
2. Open the Live page in the ProductLense dashboard. Your visit appears within a few seconds.
3. In the browser's developer tools, the Network tab shows a `POST` to `https://api.productlense.app/api/e` with status `204`. Navigate to another page: a second pageview follows.

`vite dev` runs on `localhost`, where nothing is sent unless you add `data-dev="true"` to the tag. Ad blockers in your own browser may block the request. If the visit does not appear, follow [Verify your installation](/docs/install/verify).
