# Quickstart

Install the script, see your first pageview, and connect billing in about five minutes.

This guide takes a new site from nothing to its first attributed payment. You need a ProductLense account, access to your site's HTML or layout file, and admin access to your billing provider.

## 1. Create a site

Sign in at [app.productlense.app](https://app.productlense.app/login) and add a site with its hostname, for example `example.com`. A bare hostname also accepts its `www.` variant, and `*.example.com` accepts every subdomain and the apex. Events from any other hostname are rejected.

Setup then checks your homepage once to see what it is built with, and opens the install step on the right framework: the code with your site id already in it, the file it goes in, and a prompt you can paste into Claude Code, Codex, Cursor or Lovable (or run as a one-line `claude` or `codex` command). If your site is not online yet, pick the framework yourself.

Copy the site id from the site's settings. It is a UUID; the snippets below call it `SITE_ID`.

## 2. Add the script

Put the script in the `<head>` of every page. The first line is an optional queue stub: it lets you call `window.productlense(...)` before the deferred script has loaded, and the calls are replayed in order.

```html tab="HTML" title="index.html"
<head>
  <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>
</head>
```

```tsx tab="Next.js" title="app/layout.tsx" {9-13}
import Script from 'next/script';
import type { ReactNode } from 'react';

export default function RootLayout({ children }: { children: ReactNode }) {
  return (
    <html lang="en">
      <body>
        {children}
        <Script
          src="https://api.productlense.app/a.js"
          data-site="SITE_ID"
          strategy="afterInteractive"
        />
      </body>
    </html>
  );
}
```

```html tab="React" title="index.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>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>
```

```html tab="SvelteKit" 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>
```

```ts tab="Nuxt" title="nuxt.config.ts" {5}
export default defineNuxtConfig({
  app: {
    head: {
      script: [
        { src: 'https://api.productlense.app/a.js', defer: true, 'data-site': 'SITE_ID' },
      ],
    },
  },
});
```

```astro tab="Astro" title="src/layouts/Layout.astro" {8}
---
const { title } = Astro.props;
---
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>{title}</title>
    <script is:inline defer data-site="SITE_ID" src="https://api.productlense.app/a.js"></script>
  </head>
  <body>
    <slot />
  </body>
</html>
```

Other platforms (WordPress, Webflow, Framer, Shopify, Google Tag Manager) have their own pages under Install, starting with the [script tag](/docs/install/script-tag).

## 3. See the first pageview

Deploy, open your site in a normal browser window, and open the Live page in the dashboard. Your visit appears within a few seconds: the script batches events for up to one second before sending them.

> [!NOTE]
> Nothing is sent from `localhost` unless the script tag has `data-dev="true"`, and nothing is sent from automated browsers (`navigator.webdriver`). If the Live page stays empty, work through [Verify your installation](/docs/install/verify).

## 4. Identify signed-in users

After signup and after login, link the visitor to your own user id. This is what lets a later payment find the channel that brought the person.

```js
window.productlense('identify', 'user_123');
```

Use the same id on the customer in your billing provider (for example `metadata.pl_user_id` on a Stripe customer). That id is the most reliable link between a payment and a visitor. Details are in [Identify users](/docs/track/identify-users).

## 5. Connect billing

In the dashboard, open the site's billing settings, pick your provider, paste a read-only key, and add the webhook URL ProductLense shows. ProductLense checks the key with one read call, backfills the last 12 months, then keeps up through webhooks and a nightly reconcile.

> [!IMPORTANT]
> Every plan includes one billing connection per site, Free too; Growth and Scale allow any number. See [Plans and limits](/docs/account/plans-and-limits).

Each provider has a page with the exact keys, webhook events and fee handling: start at [Connect billing](/docs/revenue/connect-billing). If your provider is not listed, send payments yourself with the [Payments API](/docs/api/payments).

## What you have now

- Visitors, sessions, pages and channels on the Overview.
- Revenue by channel as soon as the backfill finishes and identified customers pay.
- Profit per channel once you [add ad spend](/docs/profit/ad-spend).
