# Add Google Analytics

> Install Google Analytics 4 (GA4) into a website's codebase — the base gtag tag plus event tracking — wiring it into the real framework so pageviews fire on every route and meaningful interactions are tracked. Use this whenever someone wants to add, install, set up, wire up, or instrument Google Analytics / GA4 / gtag / a measurement ID (G-XXXXXXXXXX) on their site, or asks to "track events", "add analytics", "set up conversion tracking", or "get analytics working before launch" — even if they don't name GA4 specifically and even if they just hand you a measurement ID and a repo. Auto-detects the stack (static HTML, React SPA, Next.js, and similar) and writes the install in the idiomatic way for that stack. This skill writes code into the project; it is not an audit-only report.

- Skill: `breroz/add-google-analytics` (Agent Skill, multi-file: 6 files)
- Install (CLI): `npx skillmds@latest add breroz/add-google-analytics`
- Raw SKILL.md: https://api.skillmd.com/api/skills/breroz/add-google-analytics/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: BreRoz (https://skillmd.com/u/breroz)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/breroz/add-google-analytics

---


# Add Google Analytics (GA4)

Install GA4 into a codebase so it actually collects useful data the moment the site ships: the base tag on every page, correct pageviews across navigation (the part naive installs get wrong), and event tracking for the interactions that matter — without flooding the property with duplicates.

## What "done" looks like

A teammate could deploy, open GA4 Realtime, click around the site, and see pageviews on every route plus named events for the important actions — with no duplicate or reserved-name events muddying the data, and the build still passing.

## The one idea that makes this skill good: don't double-track

New GA4 web data streams have **Enhanced Measurement on by default**. With just the base tag installed, GA4 *already* auto-collects: `page_view`, `scroll` (at 90% depth), outbound link `click`, `view_search_results` (site search), video engagement, `file_download`, and `form_start` / `form_submit`.

So "track everything aggressively" does **not** mean firing `gtag('event', 'scroll')` or `gtag('event', 'file_download')` yourself. Re-emitting those reuses GA4's reserved/automatic event names and produces duplicate, conflicting data — which Google explicitly warns against. Aggressive-but-correct instrumentation means: let Enhanced Measurement handle its share, and **add manual events only for what it misses**:

- **SPA / client-side route changes** — the single most common broken thing. Enhanced Measurement's pageview can miss History API navigations, so SPAs under-report pageviews badly unless you wire route changes explicitly.
- **Non-link clicks** — buttons, CTAs, `role="button"`, JS-driven actions. Enhanced Measurement only catches *outbound link* clicks, not internal buttons/CTAs.
- **Named conversions / recommended events** — `generate_lead`, `sign_up`, `purchase`, `contact_form_submit`, etc. These are never automatic; they carry the business value.
- **Gaps in auto-tracking** — file types outside GA4's default download list, non-YouTube video, AJAX forms that don't trip `form_submit`.

When you instrument forms, prefer a meaningful named event (`generate_lead`, `contact_form_submit`) over re-firing raw `form_submit`, so the action is reportable as a conversion rather than colliding with the automatic event.

## Before you touch any code

1. **Get the Measurement ID.** It looks like `G-XXXXXXXXXX`. The user supplies a fresh one at runtime — if it isn't in the request, ask for it before writing the tag. If they genuinely don't have it yet, fall back to an env var / placeholder and tell them clearly where to drop it in. Never invent an ID, and never ship a literal `G-XXXXXXXXXX`.

   **Every `G-XXXXXXXXXX` in this skill and its reference files is a placeholder for illustration only — not a default and not a real property.** Before writing any file, substitute the exact ID the user gave you for this run into every spot the placeholder appears. After writing, grep the changed files for `G-XXXXXXXXXX` to confirm none of the placeholder slipped through.
2. **Confirm scope in one line** if unclear (e.g. "base tag + pageviews + click/CTA/form/conversion events across the whole app — sound right?"). Default to comprehensive since that's the usual intent here.

## Workflow

### Step 1 — Detect the stack

Look at the project root before assuming anything. Check `package.json` dependencies and lockfiles, config files, and directory layout:

- `next` in deps, or `next.config.*`, or an `app/` or `pages/` dir → **Next.js** → read `references/install-nextjs.md`
- `react` + a bundler (`vite`, `react-scripts`), `index.html` with a single `<div id="root">`, client-side router (`react-router-dom`) → **React SPA** → read `references/install-react-spa.md`
- Plain `.html` files, no build step, or a static-site output → **Static HTML** → read `references/install-static-html.md`
- Something else (Vue, SvelteKit, Astro, Remix, Rails, plain server-rendered templates): apply the closest-matching reference's *principles* — base tag in the shared document head/layout, manual pageviews if routing is client-side, delegated event tracking — and say which pattern you adapted and why. The references teach the reasoning, not just the snippet.

State what you detected and which install path you're taking before editing, so the user can correct a wrong guess cheaply.

### Step 2 — Check for an existing install (idempotency)

Grep the codebase first: `gtag(`, `googletagmanager.com/gtag/js`, `dataLayer`, `G-`, `@next/third-parties`, `GoogleAnalytics`, `react-ga`. If GA is already partly there:

- **Same or no ID, partial install** → complete/repair it; don't add a second tag. Two tags = doubled pageviews.
- **A different ID** → flag it and ask whether to replace, keep both (rare; intentional dual-tagging), or leave it. Don't silently clobber.
- **GTM present** → tell the user; adding gtag alongside GTM-managed GA double-counts. Usually the right move is to route GA4 through their existing GTM container instead — confirm before proceeding.

### Step 3 — Install the base tag

Follow the chosen reference. The universal requirements regardless of stack:

- The tag loads on **every** page — put it in the shared layout/template/document head, never one page at a time.
- The Measurement ID lives in **one** place (a config constant or, preferably, an env var the framework exposes to the client: `NEXT_PUBLIC_*` for Next, `VITE_*` for Vite). One source of truth.
- The GA script loads without blocking render (async, or the framework's script primitive).

### Step 4 — Instrument events

Apply the dedup principle above. The mechanics, the full event catalog, GA4 naming rules, and the reusable auto-tracking helper live in `references/events.md` and `assets/ga-autotrack.js` — read the reference before writing event code.

The shape of a good install:
- A single tiny `trackEvent(name, params)` wrapper so call sites never touch `gtag` directly (and so analytics is one easy thing to find/swap later).
- A declarative, delegated auto-tracker for clicks/CTAs driven by `data-ga-*` attributes, mounted once — instead of hand-wiring an `onClick` to every button. `assets/ga-autotrack.js` is the vanilla version; adapt it to the stack.
- Explicit named events for conversions and any custom interaction the codebase reveals (search the code for forms, checkout/cart logic, signup flows, downloads, modals, video).

Read the actual components/pages to find what's worth tracking — don't just instrument a generic list. The valuable events are the ones specific to *this* product.

### Step 5 — Verify it actually works

Don't hand back an install you haven't checked:

- Run the build / typecheck (`npm run build`, `tsc --noEmit`, etc.). The install must not break the build.
- Grep to confirm the tag is in the shared layout and the ID resolves (env var defined, not an empty string).
- Confirm exactly **one** GA tag loads (no duplicate from a prior install).
- List every event you added with its trigger and parameters, so the user knows what to expect in GA4.

### Step 6 — Report and hand off

Give the user:
1. **What changed** — files touched, the tag location, where the ID is configured.
2. **Events added** — table of event name, trigger, parameters, and whether it should be marked a Key Event (conversion) in GA4.
3. **Enhanced Measurement note** — remind them which events come automatically so they understand the full picture and don't manually re-add them.
4. **A Realtime verification checklist** they can run right after deploy — concrete: open GA4 → Reports → Realtime, do action X, expect event Y with parameter Z. Include the base pageview check plus one row per custom event.
5. **Key Event recommendations** — which of the new events to flag as conversions in the GA4 UI (this can't be done from code), e.g. `generate_lead`, `sign_up`, `purchase`.

## Conventions (GA4)

- Event names: lowercase `snake_case`, letters/numbers/underscores only — no spaces or hyphens. Names are case-sensitive.
- Never reuse GA4 reserved/automatic names for your own different-meaning events (`page_view`, `scroll`, `click`, `file_download`, `form_start`, `form_submit`, `session_start`, `first_visit`, etc.). Use Google's **recommended** event names where one fits the action (`generate_lead`, `sign_up`, `login`, `purchase`, `search`, `select_content`, `share`) — matching them unlocks GA4's prebuilt reporting.
- Parameters: prefer informative, low-cardinality values (`button_text`, `link_url`, `page_path`, `page_title`, `section`, `form_id`, `item_id`). Avoid putting PII (emails, names, raw query strings) into parameters.

## Reference files

- `references/install-nextjs.md` — App Router & Pages Router; the official `@next/third-parties` `GoogleAnalytics` component (handles route-change pageviews for you), env-var setup, and where manual events still belong.
- `references/install-react-spa.md` — base tag in `index.html`, manual SPA pageview tracking on router changes (the part that's easy to get wrong), and the `trackEvent` util.
- `references/install-static-html.md` — the gtag snippet, keeping it DRY across multiple HTML files / includes, and wiring the auto-tracker.
- `references/events.md` — Enhanced Measurement vs. manual responsibilities, the recommended-events catalog, naming rules, the `data-ga-*` pattern, and ready-to-paste event code.
- `assets/ga-autotrack.js` — drop-in vanilla delegated click/CTA tracker plus the `trackEvent` wrapper.

