Skip to content

SEO Specialist

Lead Tracking (Monthly)

Needs review — This SOP contains our content but has not been verified by Nick. Treat as a working draft until marked Live.

Last Updated: 2026-04-21 Version: 1.0 Tier: Monthly Operational Audit


Tracking breaks silently. Ad-blockers get updated, MP secrets get rotated incorrectly, service accounts lose permissions, CF Pages env vars get cleared during a redeploy. The client never complains because they still see calls coming in — they just don’t know that half the calls are uncredited.

This SOP catches broken tracking before the monthly report goes out with wrong numbers.

When to Run: First week of every month, before writing client deliverables Owner: SEO Specialist Timeline: 20 minutes per client site


For each client and for Tekton’s own sites (BCT, Tekton Growth):

  1. Is gtag still firing on production?
  2. Are generate_lead events still firing on form submits, both client and server-side?
  3. Is GSC still connected to GA4?
  4. Does the GA4 lead count match the real lead count in GHL (or the client’s CRM) within ±10%?
  5. Are any sources going to 0 leads when they should have leads?

Any mismatch = investigate before the month’s report goes out.


Section 1: Live Tag Check (per client, 2 min)

Section titled “Section 1: Live Tag Check (per client, 2 min)”
  1. Open the client’s live site in an incognito window
  2. DevTools → Network → filter collect
  3. Reload the page
  4. Confirm at least one POST to https://www.google-analytics.com/g/collect?...&tid=G-XXXXXXXX returns 204

If missing:

  • Disable ad-blocker first, re-test
  • If still missing: the GA4 tag is broken. Run through /gsc-verify Phase 4 to diagnose. Most common cause: someone edited a theme/layout file and removed the gtag block.

Log: Pass/Fail into the monthly audit sheet.


Section 2: generate_lead Firing Check (per client, 3 min)

Section titled “Section 2: generate_lead Firing Check (per client, 3 min)”
  1. Pick one form on the site (newsletter, contact, lead magnet)
  2. Submit a test with a throwaway email (tracking-test+<client>-<YYYYMM>@tektongrowth.com)
  3. Go to GA4 → Reports → Realtime
  4. Confirm a generate_lead event appears within 60 seconds
  5. Check the event card — should show both source_channel=client and source_channel=server if the server-side MP path is wired
  6. If only client fires: server-side is broken (MP secret invalid, env vars missing, or API endpoint isn’t calling sendGa4Event)
  7. If only server fires: client-side is broken (gtag blocked or bctTrackLead not called from handler)
  8. If neither fires: full tracking failure — escalate immediately

Log: Client-side: Pass/Fail, Server-side: Pass/Fail/N/A into the monthly audit sheet.

Note: Remove the test lead from GHL and Resend afterward so it doesn’t skew client’s list.


Section 3: GSC Data Flowing into GA4 (per client, 2 min)

Section titled “Section 3: GSC Data Flowing into GA4 (per client, 2 min)”
  1. GA4 → Reports → Acquisition → Search Console → Queries
  2. Confirm there is data in the last 7 days
  3. If “no data” when you expect organic: the GSC↔GA4 product link was broken (happens if the GSC property was re-verified or the GA4 property was moved)

To fix a broken link: GA4 Admin → Product links → Search Console links → unlink the old, re-add. Data re-populates within 24h.

Log: Pass/Fail per client.


Section 4: Lead Count Reconciliation (per client, 8 min)

Section titled “Section 4: Lead Count Reconciliation (per client, 8 min)”

This is the most important check. GA4’s conversion count should be within ±10% of the real lead count.

From GA4 (for the previous month):

  • Reports → Acquisition → Traffic acquisition
  • Secondary dimension: source_channel (custom dimension we set)
  • Metric: Key events → generate_lead
  • Split out totals by source_channel:
    • Client-side total: generate_lead where source_channel = client
    • Server-side total: generate_lead where source_channel = server
    • Server-side is the ground-truth lead count — it fires once per successful form submission regardless of browser

From GHL (for the same period):

  • Contacts → filter by tag containing bct-newsletter, resource-*, or whatever tag is set for this client’s form sources
  • OR: count the relevant tagged contacts created during the month
  • This is the client’s “real” lead count (assumes GHL is the system of record)
SourceExpected matchAcceptable variance
source_channel=server total= GHL tagged contact count±5%
source_channel=client total< server total (ad-blockers skip it)~85% of server count
  • Server count > GHL count by >10%: double-counting (form handler firing MP on non-success path, or duplicate events being sent). Check the subscribe.js or equivalent for idempotency.
  • Server count < GHL count by >10%: MP silently failing. Check CF Pages Function logs for [ga4-mp] errors. Most common: env vars got cleared on redeploy.
  • Client count > server count: suspicious — should never happen. Probably source_channel param missing on one side. Inspect the tracking JS.

Log: GA4 server count, GHL count, variance %, notes into the monthly audit sheet.


Section 5: Source Distribution Sanity (per client, 5 min)

Section titled “Section 5: Source Distribution Sanity (per client, 5 min)”

Look at where leads are coming FROM in GA4:

  1. Reports → Acquisition → Traffic acquisition → filter to generate_lead events
  2. Review the session source/medium breakdown

Red flags to investigate:

  • 100% of leads from (direct) / (none) — UTMs are probably not being captured. Check that bctGetAttribution still reads localStorage correctly.
  • 0 leads from google / organic while GSC shows 100+ clicks — GSC↔GA4 link is broken OR the attribution object isn’t being passed through the subscribe call.
  • All leads from the same UTM campaign month-over-month with no variance — probably a stale UTM in the capture cookie (90-day TTL might be sticking too long on returning visitors). Not broken, but worth noting in the monthly report.

Log: Notable source distribution changes into the monthly audit sheet.


Run the same 5 checks on:

  • Blue Collar Techy (https://bluecollartechy.com/)
  • Tekton Growth (https://tektongrowth.com)

Same SOP, just the sites are ours.


Put results into /Users/nick/Projects/seo-ops-skills/results/<YYYY-MM>/monthly-tracking-audit.md with this shape:

# Monthly Tracking Audit — YYYY-MM
## Per-Client Results
| Client | Tag Live | generate_lead | GSC→GA4 | Server MP | Variance | Notes |
|---|---|---|---|---|---|---|
| Client A | ✓ | ✓/✓ | ✓ | ✓ | +3% | |
| Client B | ✓ | ✓/✗ | ✓ | ✗ | -18% | MP secret rotated, env var stale — fixed |
...
## Action Items (for next month or urgent)
- [ ] Client B: redeploy to pick up new MP secret
- [ ] Client C: investigate why GSC↔GA4 link dropped

Surface any RED items in the Monday team standup and in the client’s monthly report if it affects their numbers.


”GA4 shows zero generate_lead events this month but GHL has 30 contacts”

Section titled “”GA4 shows zero generate_lead events this month but GHL has 30 contacts””
  1. Client-side broken: check window.bctTrackLead on the live site (DevTools console)
  2. Server-side broken: CF Pages → Settings → Environment variables. GA4_MP_SECRET present?
  3. If env vars present: check CF Pages Function logs for [ga4-mp] 400s (usually means stale secret or wrong property)
  4. Redeploy after fixing env vars (not optional — functions pick up env at deploy time)

“generate_lead count is 2x GHL contact count”

Section titled ““generate_lead count is 2x GHL contact count””
  1. Double-firing. Check the client-side form handler — is bctTrackLead inside a retry loop?
  2. Check subscribe.js — is sendGa4Event called outside the if (!result.already_subscribed) guard?

”All leads attributed to (direct) / (none)”

Section titled “”All leads attributed to (direct) / (none)””
  1. bctGetAttribution not running. Check the tracking JS file loads on every page
  2. UTM capture broken. Test: visit site with ?utm_source=test&utm_medium=test then open console, run window.bctGetAttribution() — should show utm_source: "test"

  • v1.0 (2026-04-21): Initial SOP. Monthly audit for client + Tekton-owned tracking stacks.