# Install the widget

Add the feedback launcher to any page — a script tag, the React component, or `npx iterateto init`.

## Quickstart

Add one script tag to any page. It can go in `<head>` or at the end of `<body>` — it does not matter, because the loader is tiny and async and pulls the widget UI on demand. The widget renders in a shadow root, so your page styles are never affected.

```html
<script async src="https://iterateto.com/w/v1.js" data-key="pk_..."></script>
```

Replace `pk_...` with your project's public key from [the dashboard](/dashboard/projects). A launcher pill appears in the corner; that is the whole install.

## Install with the CLI

`npx iterateto init` detects your framework, writes the embed in the right place, and wires env for you. Pass `--key` to skip the prompt, and `--yes` for non-interactive use (CI, or an AI agent running it for you).

```bash
npx iterateto init --key pk_... --yes
```

Want to see what it will do first? Run `iterateto info --json` to print the detected framework and current install state, or run `init` without `--yes` to review each change before it is written.

## React / Next.js component

`@iterateto/react` wraps the loader as a component. Install it, then mount it once near the root of your app.

```bash
npm install @iterateto/react
```

```tsx
import { IterateTo } from "@iterateto/react";

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        {children}
        <IterateTo publicKey="pk_..." />
      </body>
    </html>
  );
}
```

In a plain Next.js app without the package, use `next/script` with `strategy="afterInteractive"` in your root layout's `<body>` and pass `data-key` as a prop. Avoid `worker` (Partytown) and `type="module"` — use the config object below for those.

## Runtime API

The widget exposes a global `iterateTo` function: `iterateTo("open" | "close")`, `iterateTo("identify", { ... })`, and `iterateTo("metadata", { ... })`. Use `identify` to attach who is reporting and `metadata` for app state (both take a flat object, max 20 keys).

Because the loader is async, `window.iterateTo` does not exist until it runs. Install the one-line queue stub **before** the script tag so calls made early are buffered and replayed once the widget is ready.

```html
<script>
  window.iterateTo = window.iterateTo || function () { (window.iterateTo.q = window.iterateTo.q || []).push(arguments) };
</script>
<script async src="https://iterateto.com/w/v1.js" data-key="pk_..."></script>
<script>
  // Attach the signed-in user to future reports — safe even before the
  // widget has loaded; the queue stub buffers it.
  iterateTo("identify", {
    id: "user_123",
    email: "ada@example.com",
    name: "Ada Lovelace",
    plan: "pro",
  });

  // Arbitrary app state, merged into report metadata
  iterateTo("metadata", { build: "2026.07.24", featureFlags: "checkout-v2" });

  // Open or close the panel programmatically (e.g. from your own button)
  iterateTo("open");
  iterateTo("close");
</script>
```

## Configuration attributes

- `data-key` (required) — your project's public key (starts with `pk_`). Safe to embed publicly.
- `data-position` (optional) — `bottom-right` (default) or `bottom-left`. Overrides the position set in project settings.

See [Widget configuration](/docs/widget) for the full set of settings and targeting attributes.

## Frameworks & tag managers

The plain `<script>` tag works anywhere. If the loader can't find its own tag (you import it as an ES module, or a tag manager rewrites the script and strips `data-*`), configure it declaratively instead — set `window.iterateToConfig` **before** the loader runs.

```html
<script>
  // Set BEFORE the loader runs. Overrides any data-* attributes.
  window.iterateToConfig = {
    key: "pk_...",
    host: "https://iterateto.com",   // required in the module/no-tag case; otherwise derived from the script src
    position: "bottom-right",
  };
</script>
<script async src="https://iterateto.com/w/v1.js"></script>
```
