---
name: himetrica-install
description: Install Himetrica analytics in a web app with the HTML script tag, and identify signed-in users with the app's own user id. Use when the user asks to add Himetrica, install the Himetrica tracker, set up analytics/visitor tracking with Himetrica, or before any other himetrica-* skill (user journey card, source column, admin KPIs, live now) when the tracker is not installed yet.
---

# Install Himetrica (web)

Goal: every page of the product loads the Himetrica tracker, and every signed-in user is
identified with **the same user id the app's database (and admin panel) uses**. That id
is what lets the other himetrica-* skills look a user up from the admin panel.

## 0. Gather

- **Public tracker key** (`hm_` + hex, NOT `hm_sk_`). Found in Himetrica > project settings.
  Ask the user for it if it is not in the env. It is public by design, safe in client code.
- **Where auth state lives**: find the place where the app knows the current user on the
  client (auth provider, `onAuthStateChange`, session hook, `/me` fetch). You will hook
  `identify` there.
- **Which app is the product**: install in the app your *end users* use (marketing site
  and the product itself). If the admin panel is a separate app, do NOT install the tracker
  there. If it lives in the same app (e.g. `/admin`), keep the tracker out of the admin
  layout (see step 1).

## 1. Script tag

Always use the plain HTML tag, in every framework. Put it in the `<head>` of the root
document so it runs on every page:

```html
<script defer src="https://cdn.himetrica.com/tracker.js" data-api-key="hm_YOUR_PUBLIC_KEY"></script>
```

Where "root document" is:

| Stack | File |
| --- | --- |
| Plain HTML / Vite / CRA | `index.html` (`public/index.html` for CRA) |
| Next.js App Router | `<head>` in `app/layout.tsx` (a plain `<script defer ...>` element) |
| Next.js Pages Router | `pages/_document.tsx`, inside `<Head>` |
| Nuxt | `app.head.script` in `nuxt.config.ts` with `defer: true` and `'data-api-key'` |
| SvelteKit | `src/app.html` |
| Astro | the base layout's `<head>` |

Read the key from the framework's public env var when there is one
(`NEXT_PUBLIC_HIMETRICA_KEY`, `VITE_HIMETRICA_KEY`, ...), otherwise inline it.

Admin inside the same app: admins browsing their own panel should not count as visitors.
- Next.js App Router with the admin in its own route group: instead of the root layout,
  load the same tag via `next/script` (`src`, `data-api-key`, `strategy="afterInteractive"`)
  in the layout of the public/product route group only. A plain `<script>` in a nested
  layout does not run reliably; `next/script` does.
- Single-page app where admin and product share one `index.html`: the tag can't be scoped
  by route. Tell the user; it's acceptable, or they can move the admin to its own app.

Optional, same pattern, only if the user wants them:
`https://cdn.himetrica.com/vitals.js` (Web Vitals) and `https://cdn.himetrica.com/errors.js`
(JS errors).

## 2. Safe caller

The tracker is `defer`red, so `window.himetrica` may not exist yet when auth resolves.
Add this tiny helper (client-only module) and use it for every call:

```ts
// lib/himetrica.client.ts
type Method = "identify" | "track";

export function himetrica(method: Method, ...args: unknown[]) {
  if (typeof window === "undefined") return; // never on the server
  const run = () => (window as any).himetrica?.[method]?.(...args);
  if ((window as any).himetrica || document.readyState === "complete") return run();
  window.addEventListener("load", run, { once: true });
}
```

## 3. Identify

Call it whenever a signed-in user is known on the client: right after login/signup AND on
page load when a session already exists (auth listeners usually fire for both).

```ts
himetrica("identify", {
  userId: user.id,       // REQUIRED: the primary key the app's DB/admin uses for this user
  email: user.email,
  name: user.name ?? undefined,
});
```

Rules:
- `userId` must be the app's own stable user id (DB primary key, Supabase `auth.users.id`,
  Clerk `user.id`...). Not a username, not something that changes. The admin panel skills
  look users up by this exact value.
- Extra string/number/boolean keys are stored as visitor metadata (e.g. `plan: "pro"`).
  Don't send secrets or tokens.
- Client-side only. Never call it from server components, API routes, or server actions.

Logout needs nothing. Don't call `reset()` or clear Himetrica storage: when a different
user identifies on the same browser, Himetrica splits the identities server-side.

## 4. Optional: key events

If the user wants, add `himetrica("track", "event_name", { ...props })` on the few actions
that matter (signup completed, first project created, checkout started). snake_case names,
small flat props. Don't instrument every click.

## 5. Verify

The tracker is a no-op on `localhost`/`127.0.0.1` on purpose. To verify, deploy (or use a
preview URL), open the site, log in, then check Himetrica > Realtime and the visitor's
profile (it should show the name/email). Tell the user this instead of debugging "no data"
on localhost.

## Done when

- [ ] Script tag in the root `<head>`, public key (`hm_`), not in the admin layout.
- [ ] `identify` with the app's user id on login and on load with an existing session.
- [ ] No `hm_sk_` key anywhere in client code.
