iterateTo

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. 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 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>