> ## Documentation Index
> Fetch the complete documentation index at: https://docs.puntego.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Framework guides

> Mount Puntego in Next.js, React, and single-page apps, with a no-code Google Tag Manager path.

Puntego installs with a single script tag, but most apps want a tighter
integration: a layout that mounts the guide once, declared targets that raise
action success, and a no-code path for non-engineers. This page covers the
common stacks.

If you just want the raw script tag, see the [install guide](/install).

<Note>
  The script-tag and Google Tag Manager paths work today. The `@puntego/react`
  and `@puntego/embed` npm packages are rolling out — if `npm install` returns a
  404, the package has not published yet, so use the [install script](/install)
  in the meantime.
</Note>

<h2 id="nextjs">
  Next.js (App Router)
</h2>

Install the React wrapper and its peers:

<CodeGroup>
  ```bash npm theme={null}
  npm install @puntego/react @puntego/embed react
  ```

  ```bash pnpm theme={null}
  pnpm add @puntego/react @puntego/embed react
  ```

  ```bash yarn theme={null}
  yarn add @puntego/react @puntego/embed react
  ```

  ```bash bun theme={null}
  bun add @puntego/react @puntego/embed react
  ```
</CodeGroup>

Mount the provider once in your root layout. Because `<PuntegoProvider>` only
loads the guide in a client effect, it is safe to render on the server. Pass both
`appId` and `apiUrl` — `apiUrl` is required, since without a reachable worker URL
the runtime cannot boot.

<Tabs>
  <Tab title="Standard">
    ```tsx theme={null}
    // app/layout.tsx
    import { PuntegoProvider } from '@puntego/react';

    export default function RootLayout({ children }: { children: React.ReactNode }) {
      return (
        <html lang="en">
          <body>
            <PuntegoProvider
              appId="gp_your_app_id"
              apiUrl="https://worker.puntego.com"
            >
              {children}
            </PuntegoProvider>
          </body>
        </html>
      );
    }
    ```
  </Tab>

  <Tab title="With CSP nonce">
    If you serve a strict Content Security Policy with a per-request nonce, read
    it from `next/headers` and pass it to the provider. It is propagated to both
    `nonce` and `data-nonce` on the boot script. Keep `apiUrl` — the nonce does
    not replace it.

    ```tsx theme={null}
    // app/layout.tsx
    import { headers } from 'next/headers';
    import { PuntegoProvider } from '@puntego/react';

    export default async function RootLayout({ children }: { children: React.ReactNode }) {
      const nonce = (await headers()).get('x-nonce') ?? undefined;
      return (
        <html lang="en">
          <body>
            <PuntegoProvider
              appId="gp_your_app_id"
              apiUrl="https://worker.puntego.com"
              nonce={nonce}
            >
              {children}
            </PuntegoProvider>
          </body>
        </html>
      );
    }
    ```

    Allow the boot origin in `script-src` and the worker origin in
    `connect-src`. See [the CSP guide](/csp) for the full policy.
  </Tab>
</Tabs>

### Declare targets

Declared targets are the highest-priority grounding tier — the guide resolves
them before falling back to DOM heuristics, which raises action success. Declare
the elements that matter on each page; the hook registers on mount and
unregisters on unmount.

```tsx theme={null}
'use client';

import { useRef } from 'react';
import { usePuntegoTarget } from '@puntego/react';

export function CheckoutButton() {
  const ref = useRef<HTMLButtonElement>(null);
  usePuntegoTarget(ref, { id: 'checkout', description: 'Primary checkout CTA' });
  return <button ref={ref} type="button">Check out</button>;
}
```

<h2 id="react">
  React
</h2>

The same `@puntego/react` package works in any React 18+ app (Vite, CRA,
Remix). Wrap your app once in `<PuntegoProvider>` (with `appId` and `apiUrl`),
then use `usePuntegoTarget` and `usePuntegoAction` to declare targets and
actions per component. Use `usePuntego()` for imperative calls such as `point`
or `sendMessage`. See the [SDK reference](/sdk-reference) for the full surface.

<h2 id="spa">
  Single-page apps and client-side routing
</h2>

The runtime hooks `history.pushState`, `popstate`, and `hashchange`, so
client-side route changes are detected automatically — there is nothing to wire
up for React Router, Vue Router, or SvelteKit navigation. The guide re-reads the
page on each route change, and an in-progress tour resumes across navigations.

For accuracy: the runtime compares the pathname, so query-only changes and
`replaceState` updates are deliberately not treated as navigations (many apps
sync scroll position or filters into the query string, and re-reading on every
such change would thrash). If you mount or unmount declared targets across those
transitions, call the registration hooks — use the framework hooks, or call
`window.Puntego.registerTarget` / `unregisterTarget` from your own lifecycle —
so the registry always matches what is on screen.

<h2 id="gtm">
  Google Tag Manager (no code)
</h2>

If you cannot edit your site's HTML but you have a GTM container, use the
community template.

<Steps>
  <Step title="Import the template">
    In GTM, open **Templates → Tag Templates → New**, then import the template.
    Get it by [downloading the Puntego Embed template](https://puntego.com/gtm/template.tpl),
    or find **Puntego Embed** in the GTM Community Template Gallery.
  </Step>

  <Step title="Add and configure the tag">
    Add a **Puntego Embed** tag and fill in your **App ID** and **Worker API
    origin** (copy both from **Dashboard → Install**).
  </Step>

  <Step title="Trigger, preview, publish">
    Trigger on **All Pages** (Initialization), then Preview and Publish.
  </Step>
</Steps>

The tag injects `boot.js` once and publishes a `window.__PUNTEGO_CONFIG__`
object that the boot script reads when no `data-app-id` attribute is present.
The GTM and hand-pasted paths share the same runtime.

## Programmatic loader

For custom integrations, the loader injects the boot script imperatively and is
SSR-safe (a no-op on the server):

```ts theme={null}
import { loadPuntego, whenPuntegoReady } from '@puntego/embed/loader';

loadPuntego({ appId: 'gp_your_app_id', apiUrl: 'https://worker.puntego.com' });
const sdk = await whenPuntegoReady();
sdk?.registerTarget('#checkout', { id: 'checkout', description: 'Checkout' });
```

## Next steps

<CardGroup cols={2}>
  <Card title="Install" icon="download" href="/install">
    The raw script tag and every launch attribute.
  </Card>

  <Card title="Configuration" icon="sliders" href="/configuration">
    Tune launcher mode, routes, voice, and wake behavior.
  </Card>

  <Card title="SDK reference" icon="code" href="/sdk-reference">
    Imperative methods, hooks, and runtime events.
  </Card>

  <Card title="Guide Tools SDK" icon="wrench" href="/guide-tools-sdk">
    Build product-owned helpers and declared targets.
  </Card>

  <Card title="CSP" icon="shield" href="/csp">
    The full Content Security Policy for strict sites.
  </Card>

  <Card title="Domains" icon="globe" href="/domains">
    Allow the origins where the guide may mount.
  </Card>
</CardGroup>
