Analytics Setup
GA4 Setup Checklist
Initial Configuration
Conversion Configuration
Event Taxonomy
Naming Convention
[object]_[action] (snake_case, all lowercase)
Examples:
signup_started
signup_completed
trial_activated
plan_upgraded
feature_used
report_exported
invite_sent
invite_accepted
Standard Events to Track (SaaS)
| Event |
Parameters |
Trigger |
page_view |
page_path, page_title |
Every page load |
signup_started |
source, plan |
Signup form opened |
signup_completed |
plan, method |
Account created |
trial_activated |
plan |
Trial period begins |
onboarding_step_completed |
step_name, step_number |
Each onboarding step |
feature_used |
feature_name, context |
Feature first use |
invite_sent |
count |
Invite submitted |
plan_upgraded |
from_plan, to_plan, revenue |
Upgrade completed |
subscription_cancelled |
plan, reason |
Cancellation confirmed |
report_generated |
report_type |
Report created |
Data Layer Implementation (GTM)
// Push event to data layer
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: 'signup_completed',
user_id: '{{user_id}}',
plan: 'pro',
method: 'google_oauth',
signup_date: '{{ISO_date}}'
});
GTM Tag Template for GA4 Events
Tag Type: Google Analytics GA4 Event
Configuration Tag: [your GA4 config tag]
Event Name: {{DL - event}}
Parameters:
- plan: {{DL - plan}}
- method: {{DL - method}}
Trigger: Custom Event — matches RegEx: signup_.*
Conversion Tracking
Conversion Hierarchy
Macro conversions (primary): Trial, Demo, Purchase
Micro conversions (secondary): Newsletter, Content Download, Webinar Registration
Engagement conversions: Video play, Scroll 75%, Time on site > 3min
Revenue Tracking (ecommerce)
gtag('event', 'purchase', {
transaction_id: 'T_12345',
value: 99.00,
tax: 0,
currency: 'USD',
items: [{
item_id: 'plan_pro_monthly',
item_name: 'Pro Plan Monthly',
price: 99.00,
quantity: 1
}]
});
UTM Strategy
UTM Governance Rules
- Always use UTMs on paid links, email links, partner links
- Never use UTMs on internal links (breaks attribution)
- Standardize via a shared UTM builder spreadsheet
- Use lowercase only; spaces become
%20 — use underscores instead
UTM Taxonomy by Channel
| Channel |
utm_source |
utm_medium |
utm_campaign |
| Google Search |
google |
cpc |
[campaign-name] |
| Google Display |
google |
display |
[campaign-name] |
| Meta Ads |
facebook / instagram |
paid-social |
[campaign-name] |
| LinkedIn Ads |
linkedin |
paid-social |
[campaign-name] |
| Newsletter |
[newsletter-name] |
email |
[issue-name-or-date] |
| Partner |
[partner-name] |
referral |
[partnership-name] |
| Affiliate |
[affiliate-name] |
affiliate |
[program-name] |
| Podcast |
[podcast-name] |
audio |
[episode-name] |
UTM Builder (Python snippet)
from urllib.parse import urlencode, urlparse, urlunparse, parse_qs
def build_utm_url(base_url, source, medium, campaign, content=None, term=None):
params = {
'utm_source': source.lower().replace(' ', '_'),
'utm_medium': medium.lower().replace(' ', '_'),
'utm_campaign': campaign.lower().replace(' ', '_'),
}
if content:
params['utm_content'] = content.lower().replace(' ', '_')
if term:
params['utm_term'] = term.lower().replace(' ', '_')
separator = '&' if '?' in base_url else '?'
return f"{base_url}{separator}{urlencode(params)}"
Dashboard Design
Executive Dashboard (weekly)
Metrics to show:
- Total conversions (trials/demos) vs target
- Traffic by channel (trend, not just total)
- Conversion rate by channel
- Revenue / pipeline generated
- MoM growth rate
Channel Performance Dashboard
| Metric |
Google |
Meta |
LinkedIn |
Organic |
Email |
| Sessions |
|
|
|
|
|
| Leads |
|
|
|
|
|
| Lead CR% |
|
|
|
|
|
| CAC |
|
|
|
|
|
| ROAS |
|
|
|
|
|
Funnel Dashboard
Build a Looker Studio (free) funnel with:
- Visitors → Leads → MQLs → SQLs → Customers
- Conversion rate at each step
- Time-to-convert distribution
- Cohort comparison (this month vs last month)
Attribution Models
Choosing the Right Model
| Sales Cycle |
Recommended Model |
| < 7 days |
Last touch or time decay |
| 7–30 days |
Linear or U-shaped |
| 30–90 days |
U-shaped or W-shaped |
| 90+ days / Enterprise |
Data-driven or custom |
Revenue Attribution Report (SQL)
-- First-touch attribution
SELECT
first_touch_source,
COUNT(DISTINCT customer_id) AS customers,
SUM(arr) AS attributed_arr,
AVG(days_to_close) AS avg_sales_cycle
FROM customers
JOIN attribution ON customers.id = attribution.customer_id
WHERE attribution.touch_type = 'first'
GROUP BY 1
ORDER BY 3 DESC;
Reporting Cadence
| Report |
Frequency |
Audience |
Key Questions |
| Traffic & leads |
Daily |
Marketing team |
Any anomalies? |
| Channel performance |
Weekly |
Marketing lead |
What's working / not? |
| Funnel report |
Weekly |
Marketing + Sales |
Where's the bottleneck? |
| Revenue attribution |
Monthly |
Leadership |
Which channels drive revenue? |
| Cohort analysis |
Monthly |
Product + Marketing |
Are retained users from better channels? |
| Attribution audit |
Quarterly |
Marketing lead |
Are models still valid? |