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.
<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).
npx iterateto init --key pk_... --yesWant 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.
npm install @iterateto/reactimport { 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.
<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 withpk_). Safe to embed publicly.data-position(optional) —bottom-right(default) orbottom-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.
<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>