SGA Growth · Reporting · Setup Guide

Google API Setup — GA4, GSC, GBP, GTM

One Google Cloud project, one service account, four APIs — the plumbing behind the Patient Funnel data pipeline.
This Week Playbook › SLT deck ›
The Architecture
┌──────────────────────────────────────────────────────────────┐
│  Google Cloud Project:  sga-analytics-ingest                 │
│                                                              │
│  ├─ Enabled APIs                                             │
│  │   ├─ analyticsdata.googleapis.com        (GA4 data)       │
│  │   ├─ analyticsadmin.googleapis.com       (GA4 admin)      │
│  │   ├─ searchconsole.googleapis.com        (GSC)            │
│  │   ├─ businessprofileperformance.googleapis.com  (GBP)     │
│  │   ├─ mybusinessbusinessinformation.googleapis.com (GBP)   │
│  │   └─ tagmanager.googleapis.com           (GTM)            │
│  │                                                           │
│  └─ Service Account                                          │
│      sga-analytics-reader@sga-analytics-ingest.iam.…         │
│      ↓ Amy grants this ONE email access to each property     │
│                                                              │
│  Access grants (20 practices × 4 platforms = 80 grants):     │
│  ├─ GA4:  admin.google.com/analytics → property → Access     │
│  ├─ GSC:  search.google.com/search-console → property → Users│
│  ├─ GBP:  business.google.com → location → Users             │
│  └─ GTM:  tagmanager.google.com → container → Admin → Users  │
│                                                              │
│  Data pulls (Dakota's monthly extractors):                   │
│  ├─ GA4 sessions ─────→ data/output/ga4-sessions-YYYY-MM.csv │
│  ├─ GSC queries  ─────→ data/output/gsc-YYYY-MM.csv          │
│  ├─ GBP metrics  ─────→ data/output/gbp-perf-YYYY-MM.csv     │
│  └─ GTM containers ──→ (deployment only — no data pull)     │
└──────────────────────────────────────────────────────────────┘
API Roles

What each of the 4 APIs does

PlatformAPI endpointWhat you getAuth
GA4 analyticsdata.googleapis.com
analyticsadmin.googleapis.com
Sessions, users, events, engagement time, conversions, custom dimensions. Property-level Viewer role required. Service account · Instant
GSC searchconsole.googleapis.com Impressions, clicks, CTR, average position by query, page, country, device. Site-verified property required. Service account · Instant
GBP businessprofileperformance.googleapis.com
mybusinessbusinessinformation.googleapis.com
Profile views, search views, calls, direction requests, website clicks, message counts. Also profile CRUD + reviews read. Service account · Restricted access (2–6 wk approval)
GTM tagmanager.googleapis.com Read/write of containers, tags, triggers, variables. NOT a data source — used to deploy standardized tracking across sites. Service account · Instant
Phase 1 · One-Time Setup

GCP project + APIs + service account

~45 min · This week (Aug 12–13) · Amy or Dakota
Goal: a live Google Cloud project with all 5 APIs enabled and a JSON credentials file for the service account, stored securely.
1. Create the Google Cloud project
~5 min
Go to console.cloud.google.com logged in as the SGA Google Workspace admin (probably amcneill@gen4dental.com or a shared admin address).
  1. Project dropdown (top-left, next to "Google Cloud") → New Project
  2. Name: sga-analytics-ingest
  3. Organization: gen4dental.com (or the SGA workspace domain if separate)
  4. Note the auto-generated Project ID (e.g., sga-analytics-ingest-461823) — you'll need it for API calls
  5. Enable billing on the project (required by some Google APIs even for free-tier quotas). Link a billing account or create one with a card on file.
2. Enable the 6 APIs
~10 min
In the new project: Navigation menu → APIs & Services → Library. Search for and click Enable on each:
  • Google Analytics Data API
  • Google Analytics Admin API
  • Search Console API
  • Business Profile Performance API
  • My Business Business Information API
  • Tag Manager API
Or do it in one shot with the gcloud CLI:
gcloud CLI (faster)gcloud config set project sga-analytics-ingest gcloud services enable \ analyticsdata.googleapis.com \ analyticsadmin.googleapis.com \ searchconsole.googleapis.com \ businessprofileperformance.googleapis.com \ mybusinessbusinessinformation.googleapis.com \ tagmanager.googleapis.com
3. Create the service account
~10 min
IAM & Admin → Service Accounts → Create Service Account
  1. Name: sga-analytics-reader
  2. Description: "Read-only service account for GA4, GSC, GBP, GTM data extraction — Patient Funnel + downstream reports"
  3. Skip granting project-level roles — access is granted per property/entity in Phase 2
  4. Skip granting user access
  5. Finish. Note the email: sga-analytics-reader@sga-analytics-ingest-461823.iam.gserviceaccount.com
Then generate the JSON key:
  1. Click the service account → Keys tab → Add Key → Create new key → JSON → Create
  2. A file downloads. Save to 1Password or a secure secrets store immediately. Do NOT commit to git.
  3. Suggested path on Amy's Mac: ~/.config/sga/gcp-sga-analytics-reader.json (chmod 600)
  4. Also upload to Railway as an env var for Dakota's monthly extractors — GCP_SA_KEY_JSON (paste the entire JSON contents)
Security
This JSON is the keys to every property you grant it access to. Treat it like a database password. Rotate annually. If leaked, revoke via IAM & Admin → Service Accounts → Keys.
4. Apply for GBP Performance API restricted access
~20 min (approval: 2–6 weeks)
This is the long-lead item — start today so it can approve by mid-September.
  1. Go to developers.google.com/my-business/content/prereqs
  2. Fill out the "Business Profile API request access form" linked from that page
  3. You'll need: GCP Project ID (from Phase 1 Step 1), business purpose, expected daily call volume, contact email
  4. Business purpose text to use: "Multi-location dental group (~260 practices; ~20 in initial Patient Funnel scope). Ingesting monthly GBP performance metrics (profile views, calls, direction requests, website clicks) for internal per-practice reporting and marketing performance analysis. No data resold, no external distribution."
  5. Google reviews and responds by email. Typical turnaround: 2–4 weeks; can slip to 6.
Meanwhile
The Patient Funnel already uses SerpAPI for Google Reviews counts + ratings (see SLT deck Slide 13). That stays in place until GBP API is approved. Once approved, we can either replace SerpAPI (cost savings) or run both for cross-validation.
Phase 2 · Per-Property Access Grants

Grant the service account access on all 20 × 4 properties

~2 weeks · Aug 15–29 · Amy + Growth Managers + MSPs
Goal: the service account email is a viewer on all 20 GA4 properties, all 20 GSC properties, all 20 GBP locations, and all 20 GTM containers that exist. Target: 80 grants total (fewer if some practices don't have a GTM container yet — that's expected).
Access strategy
Amy directly adds the service account on any property where SGA already holds admin (roughly 9 of 20 GA4, 12 of 20 GSC, 20 of 20 GBP, ~5 of 20 GTM). For the rest, the MSP or website owner does it — use the outreach template in the This Week Playbook Day 4.
GA4 Property Viewer role
  1. Go to analytics.google.com and select the property
  2. Admin (gear icon, bottom-left) → Property Access Management
  3. Blue "+" top-right → Add users
  4. Email: sga-analytics-reader@sga-analytics-ingest-461823.iam.gserviceaccount.com
  5. Direct roles: Viewer · Uncheck "Notify by email" (service accounts don't have inboxes)
  6. Add
Coverage target: 20 of 20. Today: 9 of 20 on the SGA GA4 access sheet — the other 11 need MSP outreach.
GSC Restricted user role
  1. Go to search.google.com/search-console and select the property
  2. Settings (gear icon, left nav bottom) → Users and permissions
  3. Add user (top-right)
  4. Email: sga-analytics-reader@sga-analytics-ingest-461823.iam.gserviceaccount.com
  5. Permission: Restricted (Full only needed if you'll write settings via API)
  6. Add
Coverage target: 20 of 20. Note: property must be VERIFIED first — for practices without GSC, that's a prerequisite step (DNS TXT record via the MSP).
GBP Manager role
  1. Go to business.google.com and open the location
  2. 3-dot menu → Business Profile settings → Managers
  3. Add users
  4. Email: sga-analytics-reader@sga-analytics-ingest-461823.iam.gserviceaccount.com
  5. Access: Manager (Site Manager is NOT enough for the API)
  6. Invite
Coverage target: 20 of 20. GBP quirk: the invite must be ACCEPTED — but service accounts can't accept email invites. Workaround: use the "Business Profile Manager" bulk-management interface where SGA is the primary owner; those grants take effect without the accept step.
GTM Container Read (or higher)
  1. Go to tagmanager.google.com and open the account
  2. Admin tab → Account User Management (or Container User Management)
  3. Blue "+" → Add users
  4. Email: sga-analytics-reader@sga-analytics-ingest-461823.iam.gserviceaccount.com
  5. Account permissions: User · Container permissions: Read (Edit/Publish only if we plan to deploy tags via API — see Phase 5)
  6. Invite
Coverage target: variable — GTM only exists where a container was set up. Expect ~5–10 of 20 today; the rest need containers created as a separate workstream.
Phase 3 · Test Each API

Prove access works before Dakota wires the extractors

~1 hr · Aug 22–26 · Amy or Dakota
Goal: a working sample call for each API — GA4, GSC, GBP-info (GBP-perf if approved), GTM. Prove the credentials chain end-to-end so Dakota can build extractors with confidence.
Sample call — GA4 Data API (sessions for one property)
Python (google-analytics-data client)from google.analytics.data_v1beta import BetaAnalyticsDataClient from google.analytics.data_v1beta.types import ( DateRange, Metric, RunReportRequest, ) import os os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = "~/.config/sga/gcp-sga-analytics-reader.json" client = BetaAnalyticsDataClient() resp = client.run_report(RunReportRequest( property=f"properties/{GA4_PROPERTY_ID}", # e.g., 415123456 date_ranges=[DateRange(start_date="2026-08-01", end_date="2026-08-12")], metrics=[Metric(name="sessions"), Metric(name="engagedSessions")], )) for row in resp.rows: print(row.metric_values)
Sample call — Search Console API (top queries for one site)
Python (google-api-python-client)from googleapiclient.discovery import build from google.oauth2 import service_account creds = service_account.Credentials.from_service_account_file( "~/.config/sga/gcp-sga-analytics-reader.json", scopes=["https://www.googleapis.com/auth/webmasters.readonly"], ) service = build("searchconsole", "v1", credentials=creds) resp = service.searchanalytics().query( siteUrl="https://www.smilegulfcoast.com/", # must exactly match GSC property body={ "startDate": "2026-08-01", "endDate": "2026-08-12", "dimensions": ["query"], "rowLimit": 25, }, ).execute() for row in resp.get("rows", []): print(row["keys"][0], row["clicks"], row["impressions"])
Sample call — GBP Business Information API (list locations)
Works without restricted access. Use this first to prove the credential works before the perf API is approved.
Pythonfrom googleapiclient.discovery import build from google.oauth2 import service_account creds = service_account.Credentials.from_service_account_file( "~/.config/sga/gcp-sga-analytics-reader.json", scopes=["https://www.googleapis.com/auth/business.manage"], ) service = build("mybusinessbusinessinformation", "v1", credentials=creds) resp = service.accounts().locations().list( parent=f"accounts/{GBP_ACCOUNT_ID}", readMask="name,title,storefrontAddress", ).execute() print(resp)
Sample call — GTM API (list containers)
Pythonfrom googleapiclient.discovery import build from google.oauth2 import service_account creds = service_account.Credentials.from_service_account_file( "~/.config/sga/gcp-sga-analytics-reader.json", scopes=["https://www.googleapis.com/auth/tagmanager.readonly"], ) service = build("tagmanager", "v2", credentials=creds) accounts = service.accounts().list().execute() for acct in accounts.get("account", []): containers = service.accounts().containers().list( parent=acct["path"] ).execute() print(acct["name"], "→", [c["name"] for c in containers.get("container", [])])
Phase 4 · Post-Launch Enrichment

Once Sept 5 v1 is out — layer in GSC + GBP perf

Sept 5 → Oct 5 · Dakota
Goal: v2 of the Patient Funnel (Oct 5 for Sept data) adds a GSC row to Stage 2 (organic queries context) and — if GBP restricted access is approved — a GBP row to Stage 3 (calls direct from Google, direction requests).
Add GSC to Stage 2
Extract: monthly impressions + clicks + top 5 queries per property. Report placement: next to GA4 sessions on Stage 2. Value: RODs can see WHICH queries are driving organic traffic — often reveals branded-vs-unbranded splits and gaps (e.g., "invisalign" ranking on page 3).
Replace or overlay SerpAPI with GBP Performance
Once GBP API restricted access is approved: SerpAPI gives us new-reviews-per-month + star rating; GBP Performance API gives us direction requests, calls from Google, website clicks from GBP, profile views. All are net-new to the funnel. Report placement: enrich Stage 3 (Opportunities) with GBP-sourced calls and direction requests as a separate lane from PeerLogic phone.
Phase 5 · GTM Standardization

Separate workstream: uniform tracking across the 20 sites

Q4 2026 · Adam + Dakota
Goal: every practice site runs a standardized GTM container that fires GA4 events, Google Ads conversions, and Meta pixels in a uniform way. Data quality across the 20 sites becomes consistent by construction, not by luck.
This is a separate initiative from the Patient Funnel report
The Patient Funnel READS data. This project WRITES tracking config. They benefit from the same GTM API + service account but are otherwise independent. Suggested owner: Adam (paid-media / tracking) coordinating with Dakota (engineering).
Prerequisite: every site needs a GTM container
Sites without GTM today need a container created and the snippet added to the site (dev work, MSP-side). Only after that does the GTM API become usable for tag deployment. Expected effort: 1 hr per site × ~10 sites without GTM = 10 hrs of MSP time.
Build the standard SGA GTM config
Define the standard event set (form submit, phone click, appointment CTA click, chat open, etc.), the GA4 event names, the conversion IDs to fire for Google Ads, and the Meta pixel events. Bundle as a GTM template that gets deployed via API to every practice container. When a new practice joins the Focus roster, one API call bootstraps the entire tracking stack.

Related tasks + follow-ups