# Tracking spec — Apex Praise Electric

Written the way I would hand it to you on day one of a new account. Every event below is live on this site right now; open the console, run `window.dataLayer`, and you will see them fire.

## Stack

| Layer | Tool | Why |
|---|---|---|
| Tag container | Google Tag Manager (`GTM-XXXXXXX` placeholder in `<head>` + `<body>`) | Nothing hardcoded. Tags change without a developer and without a deploy. |
| Analytics | GA4, configured **inside GTM** | One GA4 config tag, events forwarded from the dataLayer. No `gtag.js` in the page source. |
| Call tracking | CallRail, dynamic number insertion (swap script commented in `<head>`) | A separate tracking number per source — Google Ads, LSA, GBP, organic, direct. Without DNI you cannot tell a paid call from an organic one, and calls are the majority of home-services conversions. |
| Conversion page | `/thank-you.html` | A real pageview, not a JS-only event. Survives ad blockers better and gives a destination goal that Google Ads can import without Enhanced Conversions guesswork. |

## dataLayer events

| Event | Fires when | Parameters | Imported to Google Ads as |
|---|---|---|---|
| `call_click` | Any `tel:` link is clicked, anywhere on the site | `placement` (`hero`, `header`, `sticky_bar`, `footer`, `service_hero`, `city_hero`, `emergency_block`, …), `link_url`, `page_path` | Secondary conversion. The real call conversion comes from CallRail. |
| `text_click` | Any `sms:` link is clicked | same | Secondary |
| `form_start` | First interaction with any booking form | `form_name`, `page_path` | Not a conversion — a funnel step. Tells you whether a bad CPL is a traffic problem or a form problem. |
| `form_submit` | Booking form submitted | `form_name`, `service`, `slot`, `zip`, `page_path` | Secondary |
| `booking_confirmed` | Immediately after a valid submit | `form_name`, `value` | **Primary conversion** |
| `booking_confirmed_page` | `/thank-you.html` loads | `service`, `slot` | **Primary conversion** (destination) |
| `calculator_complete` | Panel-upgrade calculator returns an estimate | `calculator`, `home_age`, `panel_amps`, `ev_charger`, `zip`, `estimate_low`, `estimate_high` | Secondary. High-intent audience seed for remarketing and PMax. |
| `coupon_view` | Coupon strip scrolls into view (once per page) | `page_path` | Engagement only. Answers "do people actually reach the offer?" |

`placement` on `call_click` is the parameter that pays for itself. It tells you whether the sticky mobile bar or the hero button is producing calls, which changes the layout decision, not just the report.

## Placement of the container

- GTM head snippet is the first script in `<head>`, before the stylesheet, so tags are not blocked by render.
- `<noscript>` iframe is the first element in `<body>`.
- `site.js` is `defer`red — it only pushes to `dataLayer`, which GTM creates independently, so load order cannot break it.

## What the weekly report contains

One page, same every week, no dashboard tour:

1. Spend, calls, forms, **booked jobs**, **cost per booked job** — by campaign.
2. Revenue by service and by city page.
3. Which search terms I added as negatives and what that saved.
4. What I changed, and the one thing I am testing next week.

Cost per lead is a vanity metric in home services. A $22 lead that never books is worse than a $60 lead that turns into a $3,200 panel upgrade. The published pricing and the calculator on this site exist specifically to move that ratio.

## Before go-live checklist

- [ ] Replace `GTM-XXXXXXX` with the live container ID (2 places: head script, noscript iframe).
- [ ] Uncomment the CallRail swap script and insert the company/account IDs.
- [ ] GA4 property created, config tag firing on All Pages.
- [ ] Custom event tags in GTM for each event above, triggered on Custom Event triggers.
- [ ] Mark `booking_confirmed` and `booking_confirmed_page` as key events in GA4.
- [ ] Link GA4 to Google Ads; import both as conversions. Set everything else to Secondary.
- [ ] CallRail → Google Ads integration on, with a 60-second qualified-call threshold.
- [ ] Verify in GTM Preview and GA4 DebugView before spending a dollar.
