```html

Automated GA4 Audit, Deep Link Navigation, and Multi-Site Traffic Instrumentation

Over the past development session, we implemented a comprehensive Google Analytics 4 audit system, fixed dashboard deep linking, and ensured consistent GA instrumentation across all customer-facing platforms. This post covers the technical architecture, infrastructure decisions, and the orchestrator-driven workflow that powers this system.

What Was Done

  • Deployed automated GA4 code audit across all site HTML files to detect missing or misconfigured tracking
  • Implemented hash-based deep linking in the progress dashboard to support shareable card URLs
  • Created reusable authentication scripts for GA4 Data API and Google Business Profile access
  • Built orchestrator workflow to pull 30-day traffic data, generate recommendations, and surface findings as dashboard cards
  • Mapped all GA4 property IDs across platforms and verified Search Console integration

Technical Details: GA4 Code Audit

The audit system scans the HTML source for each site's templates and deployed pages, checking for the presence and correct configuration of the GA4 measurement tag. This is critical because even one page without tracking creates blind spots in your traffic data.

Files Created:

  • /Users/cb/Documents/repos/tools/reauth_ga.py — Service account authentication and token refresh for GA4 Data API
  • /Users/cb/Documents/repos/tools/preflight_check.py — Pre-deployment validation script that verifies GA code presence before pushing to production

Approach:

Rather than parsing JavaScript bundles (which are minified and fragile), we check the raw HTML served from each domain. The audit extracts the <script async src="https://www.googletagmanager.com/gtag/js?id=G-*"> tag and verifies the property ID matches the expected value for that site.


# Example command to audit a single site
python3 /path/to/tools/preflight_check.py \
  --site queenofsandiego.com \
  --expected-ga-id G-ABC123XYZ

The system discovered several sites with either missing GA tags or outdated Universal Analytics (GA3) codes. These were prioritized as high-impact operational debt.

Infrastructure: GA4 Data API Access

Pulling traffic data programmatically requires OAuth credentials with the correct scopes. We use a service account approach:

  • Service Account Email: Stored securely in our credential manager (not in repo)
  • Required Scope: https://www.googleapis.com/auth/analytics.readonly
  • GA4 Property IDs Mapped:
    • queenofsandiego.com — Property ID 123456789
    • sailjada.com — Property ID 234567890
    • burialsatsea.com — Property ID 345678901

The reauth_ga.py script handles token refresh automatically. It checks token expiration and re-authenticates only when necessary, reducing API overhead.


# Fetch last 30 days of traffic data for a specific property
from google.analytics.data_v1beta import BetaAnalyticsDataClient
from google.analytics.data_v1beta.types import RunReportRequest

client = BetaAnalyticsDataClient(credentials=service_account_credentials)

request = RunReportRequest(
    property=f"properties/{PROPERTY_ID}",
    date_ranges=[{"start_date": "30daysAgo", "end_date": "today"}],
    dimensions=[{"name": "pagePath"}],
    metrics=[{"name": "screenPageViews"}, {"name": "bounceRate"}],
)

response = client.run_report(request)

This data is then fed to the orchestrator, which generates a structured report and creates a dashboard card with findings.

Dashboard Deep Linking Architecture

The progress dashboard (progress.queenofsandiego.com) uses hash-based routing to support deep links to specific cards. This allows engineers to share a URL like:


https://progress.queenofsandiego.com/#card-t-31aa2593

Implementation Details:

The dashboard JavaScript includes a hash listener that parses the fragment identifier and scrolls to (or highlights) the referenced card:


window.addEventListener("hashchange", function() {
  const cardId = window.location.hash.replace("#card-", "");
  const cardElement = document.getElementById(cardId);
  if (cardElement) {
    cardElement.scrollIntoView({ behavior: "smooth" });
    cardElement.classList.add("highlight");
  }
});

Each card in the HTML is assigned an id attribute following the pattern card-{task-id}. The orchestrator generates these IDs deterministically based on card content and timestamp, ensuring URLs remain stable across page refreshes.

Orchestrator Workflow Integration

The orchestrator is a multi-step agent that:

  1. Scans HTML across all repos for GA code presence and property ID correctness
  2. Pulls GA4 traffic data for the last 30 days using the Data API
  3. Checks Constant Contact for scheduled email campaigns
  4. Generates recommendations based on traffic patterns (traffic sources, bounce rates, top pages)
  5. Creates a dashboard card with the full report, which lands automatically at progress.queenofsandiego.com

This is implemented as a long-running background task that spawns asynchronously. The user receives a summary in the console and a deep link to the card when complete.

Key Decisions

Why HTML-based GA code audit instead of JavaScript parsing? Minified JavaScript is brittle and changes with every build. By checking the source HTML, we have a single source of truth that's independent of build processes and transpilers.

Why hash routing instead of query parameters? Hash-based routing doesn't trigger a server request, so deep links work instantly without roundtrips. It also allows the page to load fully before JavaScript detects the fragment and highlights the card, preventing layout shift.

Why service account OAuth instead of user tokens? Service accounts never expire (they use key files), so the system can run unattended. User tokens require periodic re-authentication and add operational overhead. Service accounts are also easier to audit in a shared team environment.

Search Console and GBP Integration

We also verified Search Console integration by:

  • Uploading an HTML verification file to the S3 origin bucket for dangerouscentaur.com (S3 bucket name withheld; stored in infrastructure config)
  • Adding the domain to Google Search Console and submitting the sitemap
  • Checking GBP (Google Business Profile) token scopes to ensure Account Management API access

Files created for GBP authentication:

  • /Users/cb/Documents/repos/tools/reauth_gbp.py — Service account auth for G