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

# Install the tag

> The script tag itself — where it goes, what it does on load, and how to confirm it worked.

One script tag handles both jobs on your website: recording page views, and capturing the forms you point at allGood.

```html theme={null}
<script src="https://mk.brand.com/_ag/v1.js"
        data-ag-key="agsk_..." async></script>
```

Copy the real version from **Settings → Web Tracking**, which fills in your domain and key. That's the whole install — there's nothing to register first, and no per-site configuration.

## The two attributes

| Attribute     | Needed for    | Notes                                                                                                                                                             |
| ------------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `src`         | Everything    | Must point at your connected allGood domain. The script reads its own address to learn where to send things, so a page never has to be told the endpoint          |
| `data-ag-key` | Tracking only | Not needed if the page only carries a form — forms are identified by their own id and gated by the [allowed origins list](/mk/developer/web-edge/allowed-origins) |

The key can also ride in the URL as `?k=…`. That form exists for Google Tag Manager, which can inject a URL but can't set an attribute.

## Where to put it

In `<head>`, with `async`, on every page you want tracked.

Loading the script twice on one page is safe — the second copy sees the first and stops. Loading it earlier doesn't make anything send earlier, because it fetches a small configuration file first and sends nothing until that lands.

## What happens on load

1. It reads its own address and key.
2. It finds every form on the page marked for allGood and binds them.
3. It fetches its configuration in one request covering the whole page.
4. It adds the honeypot field, and the bot-check widget on forms that need one.
5. It starts watching for navigation, so single-page-app route changes count as page views.
6. It records the first page view — or holds it, if consent hasn't been answered.
7. It fires an `allgood:ready` event on the page.

If the page's origin isn't on your allowed list, step 3 says so and the script writes a warning to the browser console.

## Page views

With **Automatic page views** on, the script records a page view carrying the URL, path, title, referrer, and any `utm_` parameters or advertising click ids it finds.

**Repeat views are not double-counted.** A page view is recorded once per unique path and query string, so a route change back to the same place within one page load doesn't record a second one. A full reload does.

**Single-page apps work without configuration.** Anything using the browser's History API — React Router, Next.js client navigation, Vue Router and so on — produces page views on route change, including back and forward.

<Note>
  Hash changes don't count as navigation. `#section` anchors don't produce a page view, because the path hasn't changed. If your app routes on the hash, turn off automatic page views and record them yourself with [`track()`](/mk/developer/web-edge/identify-and-track).
</Note>

## Personal data in URLs is removed

Query values that look like an email address, or that are very long, are replaced before the URL is stored. The key stays, so you can see something was there. Don't put personal data in a URL and expect it to survive.

## Pages allGood hosts

Landing pages on your allGood subdomain record a page view **without any script at all**, on every visit. So a hosted page doesn't need the tag for page views. It does still need it for [`identify()` and `track()`](/mk/developer/web-edge/identify-and-track), and for form capture.

## Content Security Policy

If your site sets a CSP, the tag needs:

| Directive     | Value                               | Why                                             |
| ------------- | ----------------------------------- | ----------------------------------------------- |
| `script-src`  | `https://mk.brand.com`              | To load the script                              |
| `connect-src` | `https://mk.brand.com`              | To send events and submissions                  |
| `script-src`  | `https://challenges.cloudflare.com` | Only if a form on the page requires a bot check |
| `frame-src`   | `https://challenges.cloudflare.com` | Same                                            |

## Check it worked

1. **Console** — no message beginning `[allGood]`. If there is one, it names the exact problem.
2. **Console** — `window.allgood.version` returns a version string.
3. **Network** — filter on `_ag`; the configuration request should succeed, and once consent allows it, so should the event request.

If there's no event request at all and no errors, the tag is holding events waiting for consent. See [What consent gates](/mk/developer/web-edge/consent-behavior).

## Next

→ [Capture a form](/mk/developer/web-edge/capture-a-form) or [identify and track](/mk/developer/web-edge/identify-and-track). Only reachable through a tag manager? [Install with GTM](/mk/developer/web-edge/install-with-gtm).
