Mike HolpStart hereAll videos

Build guide · By · Updated

Track React analytics only after consent.

A click on a membership button shows interest. It does not prove someone paid. This guide follows the optional tracking used on this website: a clear choice, a consent guard, and separate event names for outbound clicks and completed actions.

Start with a local copy

Use the site’s public repository. You’ll need Node.js, npm, and basic JavaScript. The automated checks use mocked providers, so they do not send analytics or require a paid service.

git clone https://github.com/mikeholp87/ai-income-lab.git
cd ai-income-lab
npm ci
node --test src/tracking.test.js
npm run dev

If you experiment in a fork, remove or replace the live provider IDs before enabling tracking. An analytics ID is not a secret, but sending your tests to somebody else’s property pollutes their reports.

Name the choice accurately

When a choice enables both Google Analytics and Meta Pixel, say “Analytics & marketing” and identify both providers. Keep Decline and Allow accessible. A separate provider that runs regardless of this preference must be described separately in the privacy notice.

Store the choice, provide a way to reopen it, and treat missing or unreadable storage as no permission for optional tracking. Avoid loading the optional scripts simply because the page mounted.

Put the guard where every event uses it

export function trackGoogleEvent(name, parameters = {}) {
  if (typeof window === 'undefined'
      || getTrackingConsent() !== 'granted'
      || typeof window.gtag !== 'function') return false;
  window.gtag('event', name, parameters);
  return true;
}

In this project, src/tracking.js owns this check. The loading function also checks consent. Repeated clicks on Allow reuse the initialized providers rather than inserting duplicate scripts.

When the choice changes to Decline, revoke consent through the provider APIs and stop sending optional application events. This does not mean a provider already loaded in the document ceases all network activity; inspect the provider’s behavior and explain the policy accurately.

Give each event one meaning

EventWhat it establishes
CTA ClickedThe visitor activated a link or action.
Skool Outbound ClickedThe visitor followed a membership link.
Call RequestedThe embedded scheduler received the request. This calendar requires manual confirmation.
Confirmed paid membershipA trusted payment or membership record confirms payment; a click cannot supply this evidence.

Record placement and campaign details rather than names, email addresses, or booking notes. Forward the same UTM campaign parameters to the destination so its records can be reconciled with your traffic.

Test the choices

  1. In a fresh local browser session, inspect network requests before making a choice. Google and Meta tracking scripts should be absent.
  2. Choose Decline and follow a few links. Optional Google/Meta events should remain off.
  3. With providers mocked or routed to your own test property, choose Allow both. Confirm one script per provider.
  4. Reopen Privacy choices, decline, then allow again. Confirm consent updates and that scripts are not duplicated.
  5. Inspect your data definitions: outbound clicks and completed bookings must remain separate counts.

The repository’s tracking tests cover loading once, restoring consent, and guarding outbound events. Browser checks are still needed because provider scripts run outside those unit tests.

When a check fails

If an optional event fires before consent, route it through the shared guard in src/tracking.js and rerun node --test src/tracking.test.js. If scripts appear twice, check the initialization guard before adding another event listener. Test with mocked providers so you can inspect calls without sending real analytics.

Reconcile before optimizing

For a fixed date range, compare campaign clicks with actual scheduler and membership records. Deduplicate using provider transaction or booking IDs, exclude canceled/refunded outcomes according to a documented rule, and leave missing attribution labeled unknown. Never guess a match from timing alone.

Only then compare page versions. A shorter hero might increase clicks while producing the same number of paying members; the two observations answer different questions.

Choose another build or ask a question.