Bright Side Plumbing & Heating
Mastering Google Analytics 4 and Google Tag Manager for revenue-tied measurement
4.9 stars, 384+ Google reviews | $3M to $6M | callbrightside.com
Companion document to the Nexus AI Command Center & Google AI Ads Playbook
Bright Side spends $35K/month on marketing with a $200 CPL and an 80% booking rate. The constraint is volume, not close rate. GA4 and GTM are the measurement infrastructure that tells you which volume is worth buying more of.
| Without Proper GA4 + GTM | With Proper GA4 + GTM |
|---|---|
| "We got 175 leads this month" | "We got 42 sewer leads from Google Ads at $312 CPL generating $189K in invoiced revenue" |
| "Our bounce rate is 65%" | "Sewer repair page visitors who scroll past the 5th-gen trust badge convert at 8.2%, versus 3.1% for those who bounce before it" |
| "People are clicking the phone number" | "Mobile users from 66209 who called after viewing the sewer camera page have a $7,800 average job value" |
| "Traffic is up this month" | "Organic sewer keywords drove 18 form submissions at $0 CPL; 14 became booked jobs totaling $48K revenue" |
| Business Goal | GA4 Capability | GTM Role |
|---|---|---|
| Prove which channels generate sewer revenue | Attribution reporting with offline conversion import from ServiceTitan | Captures GCLID, UTM parameters, and user data at every form/call touchpoint |
| Reduce CPL from $200 to $120 | Key event tracking with accurate conversion counts feeds Smart Bidding | Fires conversion tags only for qualified actions, not page views |
| Scale to 500+ leads/month | Audience segments exported to Google Ads for lookalike targeting | Collects the behavioral signals that define high-value audience segments |
| Justify $35K/month spend to ownership | Revenue-tied dashboards in Looker Studio pulling from GA4 + ServiceTitan | Ensures every data point flowing into GA4 is accurate and complete |
| Win against KC plumbing competitors | Funnel analysis reveals where competitors' leads leak; yours convert | Tracks micro-conversions (scroll depth, video views, review reads) that predict macro-conversions |
GA4 replaced Universal Analytics in July 2023. Every interaction on callbrightside.com is now tracked as an event. Understanding the event model is the foundation for everything else in this playbook.
| Event Type | Definition | Bright Side Examples |
|---|---|---|
| Automatically Collected | Events GA4 collects with no configuration. Always active. | page_view, session_start, first_visit, user_engagement, scroll (90% depth) |
| Enhanced Measurement | Events enabled with a toggle in GA4 Admin. No code required. | scroll, outbound_click, site_search, video_start, video_progress, video_complete, file_download, form_interaction |
| Recommended Events | Google-defined event names you implement manually. GA4 recognizes the names and provides built-in reporting. | generate_lead (form submit), purchase (offline import from ServiceTitan), sign_up (newsletter), search (site search with service terms) |
| Custom Events | Events you define for business-specific actions. Use only when no recommended event fits. | click_to_call, schedule_service, review_click, service_page_view, chat_start |
Every event can carry parameters (metadata about the event) and be associated with user properties (metadata about the user). This is how GA4 builds rich data without the rigid "Category / Action / Label" structure from Universal Analytics.
Event name: generate_lead Parameters: form_id: "sewer-repair-contact" form_location: "sewer-repair-page-hero" service_type: "sewer_repair" lead_value: 500 source_medium: "google / cpc" User Properties: zip_code: "66209" customer_type: "new" device_category: "mobile"
This single event tells you: a new mobile user from Leawood submitted the sewer repair contact form in the hero section, arriving via Google Ads paid search, with an estimated lead value of $500. That is actionable data.
This distinction matters for every report and exploration you build:
| Concept | Definition | Bright Side Examples |
|---|---|---|
| Dimension | A descriptive attribute. Text-based. Answers "what" or "which." | Source/Medium, Page path, Service type, City, Device category, Campaign name |
| Metric | A quantitative measurement. Number-based. Answers "how many" or "how much." | Sessions, Key events, Event count, Engagement rate, Average engagement time, Revenue |
A GA4 property connects to your website through a data stream. Bright Side needs one web data stream for callbrightside.com. The data stream generates a Measurement ID (format: G-XXXXXXXXXX) which is used by GTM to send data to GA4.
GA4 uses data-driven attribution as its default model. This means GA4 uses machine learning to assign credit for conversions across all touchpoints, not just the last click. For Bright Side, this matters because a homeowner might:
Data-driven attribution distributes the $7,500 conversion value across all three touchpoints based on their actual influence, rather than giving 100% credit to the last click. This is critical for justifying both paid and organic spend to Kalen and Stephanie.
This section covers the exact GA4 property configuration for Bright Side. Every setting here maps to a Skillshop concept and a business outcome.
| Setting | Recommended Value | Why |
|---|---|---|
| Property name | Bright Side Plumbing - Production | Clear identification; add a second property for staging/testing if needed |
| Reporting time zone | Central Time (US & Canada) | Matches Overland Park, KS business hours |
| Currency | USD | Revenue values from ServiceTitan are in USD |
| Industry category | Home & Garden | Closest match for plumbing; enables industry benchmarking |
| Setting | Recommended Value | Why |
|---|---|---|
| Stream URL | https://callbrightside.com | Primary domain |
| Stream name | callbrightside.com - Web | Descriptive name |
| Enhanced Measurement | ALL toggles ON | Free data collection: scrolls, outbound clicks, site search, video engagement, file downloads, form interactions |
| Internal traffic filter | Office IP: 12022 Blue Valley Pkwy network | Exclude staff visits from skewing data. Also exclude Robert's IP and agency IPs. |
| Cross-domain measurement | Not needed unless HubSpot forms use a different domain | If HubSpot forms redirect to a *.hubspot.com domain, add cross-domain tracking |
| Setting | Recommended Value | Why |
|---|---|---|
| Event data retention | 14 months (maximum) | Allows year-over-year comparisons in Explorations. Standard reports are unaffected by this setting. |
| Reset user data on new activity | ON | Extends the 14-month window for active users |
| Google Signals | ON | Enables cross-device tracking and demographic reporting. Required for remarketing audiences. |
| Granular location and device data | ON | Enables city-level and device-model reporting. Critical for KC metro zip code analysis. |
| Ads personalization | ON | Required for audience export to Google Ads |
Create these data filters in GA4 Admin to prevent internal activity from contaminating conversion data:
| Filter | Condition | Action |
|---|---|---|
| Bright Side Office | IP address matches the 12022 Blue Valley Pkwy office network | Exclude from reporting |
| Robert / Dove Web Consulting | Robert's home/office IP | Exclude from reporting |
| Russ / Dir of Digital Marketing | Russ Satterfield's IP | Exclude from reporting |
| Developer/staging traffic | Hostname does not equal callbrightside.com | Exclude from reporting |
Important: GA4 data filters are permanent. Filtered data cannot be recovered. Always test filters in "Testing" state before switching to "Active."
Google Tag Manager is the control center for all tracking code on callbrightside.com. Instead of asking a developer to add code to every page, GTM lets you deploy, modify, and remove tracking tags through a web interface. Every GA4 event, every Google Ads conversion tag, every HubSpot tracking pixel, and the ClickCease script should run through GTM.
| Component | Definition | Analogy | Bright Side Example |
|---|---|---|---|
| Tag | A piece of code that sends data to a third-party service | The mail carrier delivering a package | GA4 Event tag that sends generate_lead to Google Analytics when someone submits a form |
| Trigger | A condition that tells a tag when to fire | The doorbell that activates the carrier | "Fire when Form ID equals sewer-contact-form and Event equals gtm.formSubmit" |
| Variable | A dynamic value used by tags and triggers | The address label on the package | A Data Layer Variable that reads formServiceType to determine if the lead is for sewer, water heater, or drain cleaning |
The data layer is a JavaScript object (window.dataLayer) that serves as the bridge between your website and GTM. When something happens on callbrightside.com (form submit, phone click, page load), the website pushes structured data to the data layer. GTM reads from the data layer to populate tags.
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
'event': 'form_submission',
'form_id': 'sewer-repair-contact',
'form_location': 'hero-section',
'service_type': 'sewer_repair',
'lead_value': 500,
'user_email_hash': 'a1b2c3...', // SHA-256 hashed
'user_phone_hash': 'd4e5f6...' // SHA-256 hashed
});
GTM then uses Data Layer Variables to read each field and pass them as parameters to the GA4 Event tag and the Google Ads Conversion tag simultaneously.
| Tag Type | Purpose | Count Needed |
|---|---|---|
| GA4 Configuration | Loads GA4 on every page, sends page_view event, sets Measurement ID | 1 |
| GA4 Event | Sends custom/recommended events to GA4 (one per event type) | 8-12 |
| Google Ads Conversion Tracking | Fires when a lead action occurs; feeds Smart Bidding | 3-4 |
| Google Ads Remarketing | Builds remarketing audiences based on page visits | 1 |
| HubSpot Tracking Code | Connects website activity to HubSpot CRM contacts | 1 |
| ClickCease | Click fraud detection for Google Ads traffic | 1 |
| Consent Mode Configuration | Sets default consent state and updates on user choice | 2 |
GTM tracks changes through workspaces (draft changes), versions (published snapshots), and environments (where code runs). Best practices for Bright Side:
v12 - Added sewer form tracking + consent modeThis section defines the complete tag, trigger, and variable inventory for the Bright Side GTM container (GTM-M3L9374). Think of this as the blueprint; Section 6 covers the event strategy in detail.
| Setting | Value |
|---|---|
| Container name | callbrightside.com |
| Container type | Web |
| Container ID | GTM-M3L9374 (verified live on callbrightside.com, Mar 2026) |
| Installation | GTM snippet in <head> (via Oxygen Builder Code Block or WPCode plugin) |
Without consistent naming, a GTM container becomes unmanageable within weeks. Every tag, trigger, and variable must follow this format:
Tags: [Platform] - [Action] - [Detail]
GA4 - Event - generate_lead
GAds - Conversion - phone_call
HubSpot - Tracking Code
ClickCease - Script
Triggers: [Type] - [Condition]
Form Submit - Sewer Contact Form
Click - Phone Number Link
Page View - Service Pages
Timer - 30 Second Engagement
Scroll - 50 Percent Depth
Variables: [Type] - [Name]
DLV - service_type (Data Layer Variable)
DOM - hero_cta_text (DOM Element Variable)
URL - page_path (URL Variable)
CONST - ga4_measurement_id (Constant)
LOOKUP - service_value (Lookup Table)
| Variable Name | Type | Value / Configuration |
|---|---|---|
CONST - GA4 Measurement ID | Constant | G-XXXXXXXXXX (your GA4 Measurement ID) |
CONST - GAds Conversion ID | Constant | Google Ads account conversion ID |
DLV - event_name | Data Layer Variable | Reads event from data layer |
DLV - service_type | Data Layer Variable | Reads service_type (sewer_repair, water_heater, drain_cleaning, etc.) |
DLV - form_id | Data Layer Variable | Reads form_id for form-specific tracking |
DLV - form_location | Data Layer Variable | Reads form_location (hero, sidebar, footer, popup) |
DLV - lead_value | Data Layer Variable | Reads estimated lead value based on service type |
DLV - user_email | Data Layer Variable | Reads hashed email for Enhanced Conversions |
DLV - user_phone | Data Layer Variable | Reads hashed phone for Enhanced Conversions |
URL - Page Path | URL Variable | Component: Path |
URL - Page Hostname | URL Variable | Component: Hostname |
LOOKUP - Service Page Value | Lookup Table | Maps page paths to service types and proxy values (see Section 6) |
| Trigger Name | Type | Condition |
|---|---|---|
All Pages | Page View | All page views (for GA4 Config tag) |
Page View - Service Pages | Page View | Page Path matches regex /sewer|water-heater|drain|gas-line|plumbing/ |
Form Submit - Contact Forms | Form Submission | Form ID matches contact/schedule forms |
Form Submit - HubSpot Forms | Custom Event | Event equals hubspot_form_submit (from HubSpot callback) |
Click - Phone Number | Click - Just Links | Click URL contains tel:9139631029 |
Click - Email Link | Click - Just Links | Click URL contains mailto: |
Click - CTA Buttons | Click - All Elements | Click Classes contain cta-button or schedule-btn |
Click - Google Reviews Badge | Click - All Elements | Click URL contains google.com/maps or element ID matches reviews widget |
Scroll - 25/50/75/90 Percent | Scroll Depth | Vertical scroll at 25%, 50%, 75%, 90% thresholds |
Timer - 30 Second Engagement | Timer | 30,000ms interval, limit 1, fires on all pages |
Video - YouTube Engagement | YouTube Video | Start, 25%, 50%, 75%, Complete |
Custom Event - chat_opened | Custom Event | Event equals chat_opened (from live chat widget) |
This is the most important section of the playbook. Every event defined here directly maps to a business question Kalen, Stephanie, or Russ will ask. "How many sewer leads did we get?" "Which page drives the most calls?" "Is the $35K working?"
Events are organized by business impact, from highest to lowest:
| Event Name | Source | Parameters | Business Use |
|---|---|---|---|
purchase | ServiceTitan via offline import | transaction_id, value, currency, service_type, technician_name | Actual invoiced revenue tied back to the original click/visit. This is the gold standard for ROAS calculation. |
job_booked | ServiceTitan via Zapier/API | booking_id, service_type, estimated_value, booking_source | Tracks the booking before the job is completed. Faster signal than waiting for invoice. |
| Event Name | Trigger | Parameters | Proxy Value |
|---|---|---|---|
generate_lead | Contact/schedule form submission | form_id, form_location, service_type, lead_value | $100-$500 based on service type |
click_to_call | Click on tel:9139631029 link | page_path, service_type, call_location (header, hero, footer, sticky) | $150-$500 based on page context |
schedule_service | ServiceTitan online booking completion | service_type, preferred_date, booking_source | $200 (direct booking = high intent) |
chat_start | Live chat widget opened with message sent | page_path, service_type, chat_source | $75 |
| Service Type | Form Submit Value | Phone Call Value | Rationale (Avg Job Value) |
|---|---|---|---|
| Sewer Repair | $500 | $500 | Avg job: $3K-$15K. Highest revenue per lead. |
| Sewer Replacement | $500 | $500 | Avg job: $5K-$15K. Highest ticket service. |
| Water Heater | $200 | $200 | Avg job: $2K-$4K. Second-tier revenue. |
| Gas Line | $200 | $200 | Avg job: $1.5K-$5K. Specialized service. |
| Drain Cleaning | $75 | $100 | Avg job: $150-$500. Volume play, upsell potential to sewer. |
| General Plumbing | $100 | $100 | Avg job: $200-$1K. Mixed bag. |
| Emergency | $300 | $350 | Avg job: $500-$5K. Urgency = willingness to pay premium. |
These proxy values are used until the offline conversion import pipeline from ServiceTitan is live (see Section 11). Once actual revenue data flows back, Smart Bidding will learn from real invoice amounts instead of proxies.
| Event Name | Trigger | Parameters |
|---|---|---|
cta_click | Click on any CTA button ("Schedule Now," "Get a Free Estimate," "Call Us") | cta_text, cta_location, page_path, service_type |
service_page_view | Page view on any /services/* page | service_type, page_title |
review_interaction | Click on Google reviews badge, Birdeye widget, or testimonial section | review_source (google, birdeye, bbb), page_path |
coupon_view | Coupon/offer section becomes visible in viewport | coupon_name, page_path |
directions_click | Click on Google Maps / address link | page_path |
| Event Name | Trigger | Parameters |
|---|---|---|
scroll_depth | User scrolls to 25%, 50%, 75%, or 90% of page | percent_scrolled, page_path |
engaged_session | Timer fires at 30 seconds on any page | page_path, service_type |
video_engagement | YouTube video reaches start, 25%, 50%, 75%, or complete | video_title, video_percent, page_path |
file_download | Click on PDF, guide, or checklist download link | file_name, file_type, page_path |
In GA4, any event can be marked as a key event. Key events are GA4's equivalent of conversions and are what flows into Google Ads for Smart Bidding optimization. Choosing the right key events is one of the most consequential decisions in this entire setup.
Google split the terminology in March 2024:
| Term | Where It Lives | What It Means |
|---|---|---|
| Key Event | GA4 Reports | An event you marked as important for your business. Shows in GA4 reports and explorations. Does NOT automatically flow to Google Ads. |
| Conversion | Google Ads | A key event that you have explicitly linked to Google Ads for bidding optimization. This is what Smart Bidding uses. |
Translation for Bright Side: Mark generate_lead and click_to_call as key events in GA4. Then in Google Ads, import those key events as conversions. Only then will Smart Bidding optimize toward them.
| Key Event | Counting Method | Import to Google Ads? | Why |
|---|---|---|---|
generate_lead | Once per session | Yes, as primary conversion | Form submissions are the highest-intent online action. One per session prevents duplicate counting from double-submits. |
click_to_call | Once per session | Yes, as primary conversion | Phone calls from the website. One per session prevents counting obsessive re-clickers. |
schedule_service | Once per session | Yes, as primary conversion | Direct online booking through ServiceTitan scheduler. |
purchase | Once per event | Yes, as primary conversion (offline import) | Actual completed job revenue from ServiceTitan. The true source of truth. |
cta_click | Once per session | Yes, as secondary/observation conversion | Signals intent but is not a completed lead action. Use as observation conversion so Smart Bidding can see the signal without optimizing directly toward it. |
chat_start | Once per session | Yes, as secondary conversion | Lower volume but still a lead source. |
generate_lead, click_to_call, schedule_service, and purchase should be primary. Everything else is secondary. If you make cta_click a primary conversion, Smart Bidding will optimize for CTA clicks instead of actual leads, and your CPL data will be meaningless.
Custom dimensions let you attach business-specific attributes to GA4 events and users. They are what transform GA4 from a generic analytics tool into Bright Side's revenue intelligence system.
These attach to individual events and describe what happened:
| Parameter Name | Display Name in GA4 | Description | Example Values |
|---|---|---|---|
service_type | Service Type | Which plumbing service this event relates to | sewer_repair, sewer_replacement, water_heater, drain_cleaning, gas_line, general_plumbing, emergency |
form_id | Form ID | Which form was submitted | sewer-contact, hero-schedule, sidebar-estimate, footer-contact |
form_location | Form Location | Where on the page the form sits | hero, sidebar, footer, popup, inline, sticky |
cta_text | CTA Text | The label text of the CTA button clicked | Schedule Now, Get Free Estimate, Call Us Today |
cta_location | CTA Location | Where on the page the CTA sits | header, hero, mid-page, footer, sticky-mobile |
call_location | Call Click Location | Which phone number link was clicked | header, hero, footer, sticky-bar, sidebar |
lead_value | Lead Value | Estimated dollar value of the lead based on service type | 75, 100, 200, 300, 500 |
review_source | Review Source | Which review platform the user interacted with | google, birdeye, bbb, yelp, angi |
content_group | Content Group | Logical grouping of pages by purpose | service_page, blog, about, contact, landing_page, homepage |
video_title | Video Title | Title of the video being watched | Sewer Camera Inspection Explained, Meet the Barkers |
These attach to the user and persist across sessions:
| Parameter Name | Display Name in GA4 | Description | Example Values |
|---|---|---|---|
customer_type | Customer Type | Whether the visitor is new or returning (from ServiceTitan data or cookie) | new, returning, past_customer |
lead_status | Lead Status | Current stage in the funnel (updated via Measurement Protocol from ServiceTitan) | website_visitor, form_submitted, called, booked, completed, invoiced |
service_interest | Primary Service Interest | The highest-value service page the user has visited | sewer_repair, water_heater, drain_cleaning |
Custom dimensions must be registered in GA4 Admin before they appear in reports:
Important: GA4 allows up to 50 event-scoped and 25 user-scoped custom dimensions. Bright Side needs approximately 10 event-scoped and 3 user-scoped, leaving plenty of room for future expansion.
Timing: After registering a custom dimension, allow up to 24 hours for data to populate in standard reports and up to 48 hours in explorations.
| Parameter Name | Display Name | Unit | Description |
|---|---|---|---|
lead_value | Lead Value | Currency (USD) | The proxy or actual dollar value assigned to each lead event. Enables "total lead value" and "average lead value" calculations in reports. |
scroll_depth_max | Max Scroll Depth | Standard (number) | The maximum scroll depth percentage reached in a session. Shows how deep users read service pages. |
GA4 audiences are dynamic user segments based on behavior, demographics, and custom dimensions. Audiences serve two critical functions for Bright Side: (1) targeted reporting in GA4 and (2) export to Google Ads for remarketing and lookalike targeting.
Build audiences in layers, from broadest to most specific:
| Audience Name | Conditions | Membership Duration | Google Ads Use |
|---|---|---|---|
| Sewer Leads - Not Converted | Viewed /sewer-repair or /sewer-replacement AND did NOT trigger generate_lead or click_to_call | 30 days | Remarketing with sewer-specific messaging. Highest-value retargeting audience. |
| Water Heater Leads - Not Converted | Viewed /water-heater AND did NOT trigger generate_lead or click_to_call | 30 days | Remarketing with water heater messaging and seasonal urgency. |
| Emergency Visitors - Not Converted | Viewed /emergency-plumber AND did NOT trigger lead event within session | 7 days | Short-window remarketing. Emergency intent fades fast; 7-day membership is optimal. |
| All Converters - 90 Days | Triggered generate_lead OR click_to_call OR schedule_service in last 90 days | 90 days | Exclusion audience. Do NOT show ads to people who already converted. Saves budget. |
| High-Value Converters | Triggered purchase event with value > $3,000 (from ServiceTitan/Housecall Pro import) | 540 days | Similar/lookalike audience seed. Google Ads finds users who look like your best customers. |
| Form Abandoners | Triggered form_start but NOT form_submit | 14 days | Retarget with simplified CTA or click-to-call messaging. These visitors showed intent. |
| Past Customers (Customer Match) | Email/phone list exported from ServiceTitan + Housecall Pro | Refreshed monthly | Upsell, cross-sell, seasonal campaigns. Also use as exclusion for prospecting. Upload as Customer Match list in Google Ads. |
GA4 now includes eight pre-built audience templates designed for lead funnel segmentation. These can be activated directly in GA4 Admin:
| Template Audience | Definition | Bright Side Application |
|---|---|---|
| New Leads | Users who triggered a lead generation event for the first time | First-time form submitters or callers. Measure acquisition cost per new lead. |
| Qualified Leads | Users whose lead status progressed beyond initial submission | Leads that became booked jobs in ServiceTitan. Requires Measurement Protocol integration. |
| Converted Leads | Users who completed a purchase/transaction | Leads with invoiced jobs. The "gold" segment for lookalike targeting. |
| Unconverted Leads | Users who submitted a lead but did not progress | Form submitters who never booked. Win-back remarketing targets. |
GA4 offers predictive audiences based on machine learning. These require sufficient data volume (1,000+ positive examples and 1,000+ negative examples in the last 28 days) to activate:
| Predictive Audience | Definition | Bright Side Application |
|---|---|---|
| Likely to convert in 7 days | Users predicted to trigger a key event within the next 7 days | Proactive remarketing: show ads to people GA4 predicts will convert this week |
| Likely to churn | Users predicted to not return in the next 7 days | Re-engagement: target users who visited a sewer page but are about to disappear |
GA4 has two reporting layers: Standard Reports (pre-built, always available) and Explorations (custom, flexible, built by the analyst). Robert and Russ will live in Explorations. Kalen and Stephanie will see polished summaries in Looker Studio dashboards that pull from GA4 data.
| Report | Where to Find It | Bright Side Use |
|---|---|---|
| Acquisition Overview | Reports > Acquisition > Overview | Which channels drive traffic. Compare Google Ads vs. Organic vs. Direct vs. LSA. |
| Traffic Acquisition | Reports > Acquisition > Traffic Acquisition | Session-level view of source/medium. Filter by service_type custom dimension to see sewer-specific channel performance. |
| User Acquisition | Reports > Acquisition > User Acquisition | First-touch attribution. Answers: "What channel first brought this user to us?" Critical for understanding organic SEO value. |
| Lead Generation Report | Reports > Lead Generation (new in 2025) | Pre-built funnel from lead acquisition through qualification. Requires implementing the lead generation event schema. |
| Landing Page Report | Reports > Engagement > Landing Page | Which pages people land on and how they perform. Filter by key events to see which landing pages generate the most leads. |
| Pages and Screens | Reports > Engagement > Pages and Screens | Page-level performance. Identifies high-traffic pages with low conversion (optimization opportunities) and high-conversion pages needing more traffic. |
| Tech Overview | Reports > Tech > Overview | Device category breakdown. Bright Side's emergency callers are overwhelmingly mobile; confirm with data. |
GA4 lets you customize the Reports navigation by creating report collections. Build a "Bright Side Plumbing" collection with these reports:
service_type custom dimension as secondary dimension, filtered to key events only/services/* paths, showing engagement rate, key events, and average engagement timelead_value custom metric as a columnExplorations are GA4's power tool. They let you drag and drop dimensions, metrics, segments, and filters into flexible visualizations. Key explorations for Bright Side:
Technique: Funnel Exploration
Steps:
session_start (all website visitors)service_page_view (viewed a service page)cta_click (clicked a CTA button)generate_lead OR click_to_call (converted to lead)Segmented by: service_type and source/medium
Business insight: "32% of sewer page visitors click a CTA, but only 8% actually submit a form. Where are the other 24% dropping off? Is the form too long? Is the CTA unclear?"
Technique: Path Exploration
Starting point: page_view on /sewer-repair
Business insight: "After viewing the sewer repair page, 40% of users go to /about (trust-building), 25% go to /reviews (social proof), and 15% go to /contact (conversion). Users who visit /about before /contact convert at 2.3x the rate of those who go directly to /contact."
Technique: Free-form Exploration
Rows: Source/Medium
Columns: Key events, Lead value (sum), Engagement rate, Sessions
Business insight: "Google Ads drives 120 leads/month at $200 CPL, but organic drives 18 leads at $0 CPL. Organic leads also have a 12% higher booking rate per ServiceTitan data. Investing in SEO will reduce blended CPL."
Technique: Free-form Exploration
Rows: City (or Region)
Columns: Sessions, Key events, Key event rate, Lead value (sum)
Filter: Only KC metro cities
Business insight: "Leawood generates 3x the lead value of Independence per session. Increase Google Ads bid adjustments for 66209, 66211, 66213 zip codes." Directly feeds Conversion Value Rules in Google Ads (covered in the AI Ads Playbook).
Kalen and Stephanie do not need to log into GA4. Build a Looker Studio dashboard that pulls from GA4 and ServiceTitan, showing:
| Dashboard Section | Data Source | Metrics |
|---|---|---|
| Weekly Lead Summary | GA4 | Total leads by channel, CPL by channel, lead value by service type |
| Revenue Attribution | ServiceTitan + GA4 | Invoiced revenue tied to marketing channel via GCLID/UTM |
| Funnel Health | GA4 | Visitors to leads conversion rate, week-over-week trend |
| Page Performance | GA4 | Top 10 landing pages by lead generation, engagement rate, bounce rate |
| Geographic Heatmap | GA4 | Leads and revenue by KC metro zip code |
This is the most technically complex and most financially impactful section. Linking GA4 to Google Ads and importing offline conversions is what transforms Google Ads from "we think it is working" to "we know this click generated $8,200 in invoiced revenue."
GTM-M3L9374 | GA4: G-R9K15PMWPR | Google Ads: AW-404985988 + AW-242993149 (two accounts). Use these in all configurations.
Homeowner clicks Google Ad | +--> Lands on callbrightside.com (GCLID captured by GTM, stored in cookie + data layer) | +--> Submits form or calls (GCLID passed to HubSpot/ServiceTitan with lead data) | +--> Job booked in ServiceTitan (GCLID attached to customer record) | +--> Job completed, invoice sent ($8,200 sewer repair) | +--> Offline conversion import: GCLID + $8,200 + "purchase" sent to Google Ads | +--> Smart Bidding learns: "clicks like this one produce $8,200 jobs" | +--> Future bids automatically favor similar click patterns
What this enables:
generate_lead (Primary, $100-$500 value by service type)click_to_call (Primary, $100-$500 value by service type)schedule_service (Primary, $200 value)cta_click (Secondary/Observation only)The GCLID (Google Click Identifier) is a unique string appended to every Google Ads click URL. It is the key that connects an ad click to a revenue outcome. Here is the capture pipeline:
| Step | Action | Tool |
|---|---|---|
| 1. Capture | GTM reads GCLID from URL parameter on landing page | GTM URL Variable |
| 2. Store | GTM writes GCLID to a first-party cookie (90-day expiry) | GTM Custom HTML tag with cookie-setting JavaScript |
| 3. Pass | On form submission, GCLID is included as a hidden form field | GTM DOM manipulation or form plugin configuration |
| 4. Receive | HubSpot receives GCLID in the form submission | HubSpot hidden field |
| 5. Sync | HubSpot syncs lead data (including GCLID) to CRM | Zapier or native integration |
| 6a. Associate (ServiceTitan) | ServiceTitan attaches GCLID to the customer/job record | ServiceTitan custom field |
| 6b. Associate (Housecall Pro) | Housecall Pro booking captures GCLID via hidden field or Zapier webhook | Housecall Pro custom field or Zapier data pass-through |
| 7. Export | When job is invoiced in EITHER system, GCLID + invoice amount sent to Google Ads + GA4 | Zapier automation, Google Ads API, GA4 Measurement Protocol, or manual CSV upload |
| Method | Difficulty | Latency | Best For |
|---|---|---|---|
| Manual CSV Upload | Low | Weekly | Getting started. Export ServiceTitan data, format CSV with GCLID + value + timestamp, upload to Google Ads. |
| Zapier Automation | Medium | Near real-time | Automated pipeline. When a job is invoiced in ServiceTitan, Zapier sends GCLID + value to Google Ads Offline Conversions API. |
| Google Ads API (Direct) | High | Real-time | Enterprise-grade. Requires developer resources. Most accurate but most complex. |
| GA4 Measurement Protocol | Medium | Near real-time | Send offline events directly to GA4, which then flows to Google Ads via the GA4-Ads link. Good for updating lead status. |
Recommended path for Bright Side: Start with manual CSV upload (Week 1-4) to prove the concept and validate data quality. Migrate to Zapier automation (Week 5+) once the data format is confirmed clean.
This is a separate but equally important link:
Why it matters: When Kalen asks "is the SEO working?" you can show organic keyword performance alongside conversion data in a single GA4 report, instead of switching between Search Console and GA4.
Enhanced Conversions improve conversion tracking accuracy by supplementing standard conversion tags with hashed first-party customer data (email, phone, name, address). As browser privacy restrictions tighten and third-party cookies disappear, Enhanced Conversions become essential for maintaining accurate CPL and ROAS measurement.
| Scenario | Without Enhanced Conversions | With Enhanced Conversions |
|---|---|---|
| User clicks ad on phone, calls from desktop later | Conversion lost. Different devices, no cookie match. | Google matches hashed phone number across devices. Conversion attributed. |
| User clicks ad, cookie expires before booking | Conversion lost. 7-day ITP cookie limit on Safari. | Hashed email from form submission matches Google account. Conversion attributed. |
| User uses private browsing | Conversion lost. No cookies stored. | If user is signed into Google, hashed data matches. Partial recovery. |
| User clears cookies between ad click and conversion | Conversion lost. | Hashed first-party data provides the match. Conversion attributed. |
Industry data: Enhanced Conversions recover 5-15% of conversions that would otherwise be lost to cookie restrictions. At 175 leads/month, that is 9-26 additional tracked conversions per month. At $200 CPL, that is $1,800-$5,200/month in conversions Smart Bidding can now optimize toward.
Two approaches, from simplest to most complete:
GTM can automatically detect email and phone fields on the page and hash them. Enable this in the Google Ads Conversion Tracking tag settings. Works when form fields use standard HTML attributes (type="email", type="tel", autocomplete="email").
Push hashed user data to the data layer on form submission:
window.dataLayer.push({
'event': 'form_submission',
'enhanced_conversion_data': {
'email': 'customer@example.com', // Will be auto-hashed by GTM
'phone_number': '+19139631029', // E.164 format
'first_name': 'John',
'last_name': 'Smith',
'street': '123 Main St',
'city': 'Overland Park',
'region': 'KS',
'postal_code': '66213',
'country': 'US'
}
});
Recommended for Bright Side: Start with Option A (automatic). If match rates are below 50%, implement Option B for forms that capture email and phone. Most Bright Side forms already capture phone number and email, making this straightforward.
This is the advanced version specifically designed for lead generation businesses like Bright Side:
This is an alternative to the GCLID pipeline that works even when GCLID capture fails. The two methods are complementary; use both for maximum coverage.
Google Consent Mode V2 is a framework that adjusts how Google tags behave based on a user's cookie consent choice. While GDPR and CCPA requirements differ by region, implementing Consent Mode demonstrates privacy maturity and unlocks Google's behavioral modeling for users who decline cookies.
| Consent Type | What It Controls | Default State (Recommended) |
|---|---|---|
ad_storage | Whether Google Ads cookies can be stored (used for remarketing and conversion tracking) | Denied (until user consents) |
analytics_storage | Whether GA4 cookies can be stored (used for session and user identification) | Denied (until user consents) |
ad_user_data | Whether user data can be sent to Google for advertising purposes | Denied (until user consents) |
ad_personalization | Whether personalized advertising features can be used | Denied (until user consents) |
| Mode | Behavior When User Declines | Data Impact | Recommendation |
|---|---|---|---|
| Basic Consent Mode | All Google tags are completely blocked. Zero data collected. | Significant data loss for users who decline. No behavioral modeling. | Not recommended. Too much data loss. |
| Advanced Consent Mode | Google tags fire but in a restricted "cookieless" mode. Pings are sent without cookies. Google uses behavioral modeling to estimate conversions from non-consenting users. | Minimal data loss. Google models fill the gap. | Recommended for Bright Side. Maintains data completeness while respecting user choice. |
gtag('consent', 'default', {
'ad_storage': 'denied',
'analytics_storage': 'denied',
'ad_user_data': 'denied',
'ad_personalization': 'denied',
'wait_for_update': 500 // Wait 500ms for CMP to load
});
gtag('consent', 'update', {
'ad_storage': 'granted',
'analytics_storage': 'granted',
'ad_user_data': 'granted',
'ad_personalization': 'granted'
});
Server-side Google Tag Manager (sGTM) moves tag processing from the user's browser to a server you control. This is the most advanced tracking upgrade in this playbook and represents the direction enterprise-grade analytics is moving in 2026.
| Aspect | Client-Side GTM (Current) | Server-Side GTM (Upgrade) |
|---|---|---|
| Where tags run | In the user's browser | On a server (Google Cloud Run or similar) |
| Ad blocker impact | Blocked by ad blockers and privacy extensions | Bypasses most ad blockers (tags fire server-to-server) |
| Cookie lifespan | 7 days on Safari (ITP), varies on other browsers | Up to 2 years (first-party server-set cookies) |
| Page speed impact | Each tag adds JavaScript and HTTP requests to the page | Minimal browser load. Heavy processing happens server-side. |
| Data control | Data goes directly from browser to Google, Facebook, etc. | Data goes to YOUR server first. You decide what to forward. |
| Cost | Free | ~$50-$150/month for Cloud Run hosting |
data.callbrightside.com), which ad blockers cannot distinguish from normal first-party requests.data.callbrightside.com or gtm.callbrightside.com. This makes all tracking requests appear as first-party.| Tag | Priority | Why |
|---|---|---|
| GA4 | High | Extend cookie life, bypass ad blockers, improve page speed |
| Google Ads Conversion | High | Recover lost conversions from Safari ITP and ad blockers |
| Google Ads Remarketing | Medium | Build larger remarketing audiences from previously blocked users |
| HubSpot | Low | HubSpot has its own first-party cookie strategy; less benefit from sGTM |
| ClickCease | Low | Keep client-side; needs browser-level fraud detection signals |
Bright Side's tech stack has multiple tools that must communicate. This section maps every integration point and identifies potential gaps.
callbrightside.com (WordPress + Oxygen Builder)
|
+--[GTM Web Container]
| |
| +--> GA4 (page views, events, key events)
| +--> Google Ads (conversion tracking, remarketing)
| +--> HubSpot (tracking code, form tracking)
| +--> ClickCease (click fraud detection)
| +--> Consent Mode (CMP integration)
| |
| +--> [Future: Server-Side GTM Container]
| |
| +--> GA4 (server-side)
| +--> Google Ads (server-side conversions)
|
+--[Rank Math SEO Plugin]
| |
| +--> Schema markup (LocalBusiness, FAQPage, Service)
| +--> XML Sitemap --> Google Search Console
|
+--[HubSpot CRM]
|
+--> Lead capture (forms, chat)
+--> GCLID/UTM storage on contact record
+--> Zapier --> ServiceTitan (lead sync)
|
+--[ServiceTitan]
|
+--> Job booking, dispatch, invoicing
+--> Revenue data (source of truth)
+--> Zapier --> Google Ads Offline Conversions
+--> Zapier --> GA4 Measurement Protocol
| Integration | Status | Priority | Action Required |
|---|---|---|---|
| GTM installed on callbrightside.com | Verify | Day 1 | Confirm GTM snippet is in <head> of all pages via Oxygen or WPCode |
| GA4 data stream active | Verify | Day 1 | Confirm Measurement ID is correct and data is flowing |
| GA4 linked to Google Ads | Configure | Day 1 | Link in GA4 Admin, enable auto-tagging in Google Ads |
| GA4 linked to Search Console | Configure | Day 1 | Link verified Search Console property |
| HubSpot tracking code via GTM | Verify/Migrate | Day 3 | If HubSpot code is hardcoded, move it to GTM for centralized management |
| ClickCease via GTM | Verify/Migrate | Day 3 | Same as HubSpot; move to GTM if hardcoded |
| GCLID capture on forms | Build | Day 7 | Add hidden GCLID field to all contact forms; GTM populates from cookie |
| HubSpot to ServiceTitan sync | Build/Verify | Day 14 | Zapier workflow: new HubSpot contact creates ServiceTitan lead with GCLID |
| ServiceTitan to Google Ads offline import | Build | Day 30 | Zapier workflow or manual CSV: invoiced job sends GCLID + revenue to Google Ads |
| Consent Mode V2 | Build | Day 14 | Install CMP plugin, configure GTM consent settings |
| Enhanced Conversions | Build | Day 14 | Enable in Google Ads, configure GTM to send hashed data |
| Server-side GTM | Plan | Day 60 | After client-side is proven, deploy sGTM on Cloud Run |
ClickCease blocks fraudulent clicks from consuming ad budget. It needs to work with, not against, GA4 tracking:
The Google Analytics Certification and Google Tag Manager training on Skillshop validate the concepts in this playbook. This section maps every Skillshop topic to Bright Side's implementation.
| Detail | Value |
|---|---|
| Questions | 50 |
| Time limit | 75 minutes |
| Passing score | 80% (40/50 correct) |
| Cost | Free |
| Validity | 12 months (annual recertification) |
| Platform | skillshop.google.com |
| Skillshop Topic | Covered in This Playbook | Bright Side Application |
|---|---|---|
| GA4 property setup and data streams | Section 3 | callbrightside.com web data stream, Measurement ID, timezone, currency |
| Event-based data model | Section 2 | Four event types, parameters, user properties |
| Automatically collected events | Section 2 | page_view, session_start, first_visit |
| Enhanced Measurement events | Section 3 | Scroll, outbound click, site search, video, form interaction, file download |
| Recommended and custom events | Section 6 | generate_lead, purchase, click_to_call, schedule_service |
| Key events (conversions) | Section 7 | Which events to mark as key events, primary vs. secondary conversions |
| Dimensions and metrics | Section 2 | Source/Medium, Page path, Sessions, Key events, Engagement rate |
| Custom dimensions and metrics | Section 8 | service_type, form_id, lead_value, customer_type |
| User properties | Section 8 | customer_type, lead_status, service_interest |
| Audiences and segments | Section 9 | Sewer Leads Not Converted, High-Value Converters, All Converters exclusion |
| Predictive audiences | Section 9 | Likely to convert, Likely to churn (requires volume threshold) |
| Standard reports | Section 10 | Acquisition, Engagement, Landing Page reports |
| Explorations (Funnel, Path, Free-form) | Section 10 | Lead Conversion Funnel, Service Page Path, Lead Source Quality Matrix |
| Attribution models | Section 2 | Data-driven attribution, cross-channel credit distribution |
| Google Ads integration | Section 11 | Linking, key event import, offline conversions, GCLID pipeline |
| Search Console integration | Section 11 | Organic search query data in GA4 reports |
| Data retention and privacy | Sections 3 and 13 | 14-month retention, Consent Mode V2, data filters |
| Data filters (internal traffic) | Section 3 | Office IP filter, developer traffic filter |
| BigQuery export | Section 14 (referenced) | Future state: raw event export for advanced SQL analysis |
| User identification methods | Section 12 | User-ID, Google Signals, Device-ID hierarchy |
| Skillshop Topic | Covered in This Playbook | Bright Side Application |
|---|---|---|
| Tags, triggers, and variables | Section 4 | GA4 tags, form submission triggers, data layer variables |
| The data layer | Section 4 | window.dataLayer pushes for form submissions, phone clicks, service detection |
| Container setup and structure | Section 5 | callbrightside.com container, naming conventions, version control |
| Tag types (GA4, Ads, Custom HTML) | Section 5 | GA4 Config, GA4 Event, Google Ads Conversion, HubSpot, ClickCease |
| Trigger types | Section 5 | Page View, Form Submit, Click, Timer, Scroll Depth, Custom Event |
| Variable types | Section 5 | Data Layer, URL, Constant, Lookup Table, DOM Element |
| Preview and debug mode | Section 4 | Test every change before publishing, verify in GA4 DebugView |
| Version control and publishing | Section 4 | Named versions, changelog, workspace management |
| Built-in variables | Section 5 | Page URL, Click URL, Form ID, Scroll Depth |
| Tag sequencing | Section 5 | Consent tag fires before all other tags (Consent Initialization trigger) |
| Cross-domain tracking | Section 3 | Only needed if HubSpot forms redirect to external domain |
| Event tracking implementation | Section 6 | Complete event specification with parameters and business context |
| Week | Activity | Time |
|---|---|---|
| Week 1 | Complete all GA4 Skillshop lessons (Google Analytics section). Take notes on anything not covered in this playbook. | 4-6 hours |
| Week 1 | Complete GTM Fundamentals Skillshop course. Focus on the Preview Mode and data layer sections. | 2-3 hours |
| Week 2 | Hands-on practice: implement Sections 3-7 of this playbook on callbrightside.com's GA4 property and GTM container. | 8-10 hours |
| Week 2 | Take the GA4 practice exam. Review any missed topics against this playbook's topic map. | 2 hours |
| Week 3 | Take the official GA4 Certification exam on Skillshop. 50 questions, 75 minutes. | 1.5 hours |
Key exam tip: The GA4 exam emphasizes report interpretation and feature location over implementation details. Know WHERE to find things in the GA4 interface, not just what they do conceptually. For example: "Where would you go to see which organic search queries drive traffic?" Answer: Reports > Search Console > Queries (if linked).
This maps directly to Stephanie and Kalen's 30-60-90 day evaluation framework: Days 1-30 diagnose and build the foundation, Days 31-60 activate and measure, Days 61-90 optimize and scale.
generate_lead, click_to_call, schedule_servicecta_click, service_page_view, review_interactiongenerate_lead, click_to_call, schedule_servicebooked, completed, invoiced) to GA4 for user-scoped lead_status dimensiondata.callbrightside.com subdomain to server-side endpointComplete Stack
Every layer serves one purpose: connecting marketing dollars to revenue dollars.
GA4 measures the journey. GTM captures the signals. ServiceTitan confirms the revenue.
At $35K/month, measurement accuracy is not optional. It is the difference between $3M and $6M.