Google Analytics 4 + HubSpot Pipeline Velocity: Weekly Acquisition-to-Close Digest to Slack via Make
Every Monday, automatically correlate top traffic sources from GA4 with deal progression in HubSpot to surface which acquisition channels are actually closing — not just converting.
The stack in the order it runs — data flows from the source through to where it lands.
Most B2B SaaS marketing budgets get wasted in the gap between 'traffic converts to leads' and 'leads convert to revenue.' GA4 shows you sessions and events. HubSpot shows you deal stages. Neither talks to the other by default. So your marketing team celebrates organic traffic spikes while sales works leads that never close — and nobody connects the dots until the quarter is over.
Make (formerly Integromat) handles this cleanly because GA4's Data API requires OAuth 2.0 with specific dimension/metric combinations, and HubSpot's deals API requires multi-step filtering. Make's HTTP modules with built-in iterator and aggregator flow cover both without custom code. For a weekly scheduled job under 500 deals, Make's execution model is perfectly adequate.
Google Sheets is the join layer. You write both datasets to a single Sheet, then use a formula column to match UTM sources to deal sources and compute velocity — days from first touch to current stage. It doubles as a historical log your team can audit without touching the automation.
When NOT to use this: if your HubSpot deal volume exceeds 1,000 per week, Make's data operations will be slow and expensive — move to n8n or a Pipedream workflow with a proper SQL join instead. This also only works if you're consistently setting deal source properties in HubSpot that match your GA4 UTM parameters. Bad CRM hygiene means garbage correlation. Fix that first.
The stack (5)
Web analytics most teams already run.
The Data API makes traffic a free input for weekly ops digests.
The universal data scratchpad.
Still the fastest place to land tabular data everyone can read.
How it runs
- 1
Set up the Google Sheets log with the right schema
Create a Google Sheet called 'Acquisition-to-Close Tracker'. Sheet 1 is 'GA4 Weekly' — columns: Week, Source, Medium, Sessions, Goal Completions, Conversion Rate. Sheet 2 is 'HubSpot Weekly' — columns: Week, Deal Source, Stage, Count, Avg Days in Stage, Total Deal Value. Sheet 3 is 'Digest Summary' — this is where Make writes the joined output row before Slack delivery. Get the schema right before touching Make. Fixing column mapping mid-build wastes an hour.
- 2
Connect GA4 via the Google Analytics Data API in Make
In Make, create a new scenario. Add an HTTP module (Method: POST) hitting `https://analyticsdata.googleapis.com/v1beta/properties/YOUR_PROPERTY_ID:runReport`. Auth: OAuth 2.0 using your Google service account. Request body: `{ dimensions: [{name:'sessionSource'},{name:'sessionMedium'}], metrics: [{name:'sessions'},{name:'conversions'}], dateRanges:[{startDate:'7daysAgo', endDate:'yesterday'}] }`. This returns rows per source/medium with session and conversion counts for the past 7 days. Don't swap `conversions` for a custom event metric here unless you've verified it's firing — the default `conversions` metric pulls whatever goal you've marked in GA4.
- 3
Write GA4 rows to Google Sheets
Add an Iterator module after the HTTP module to loop over the GA4 response rows array. For each row, add a Google Sheets 'Add a Row' module pointing to Sheet 1 ('GA4 Weekly'). Map: Week to `{{formatDate(now; 'YYYY-[W]WW')}}`, Source to `dimensionValues[0].value`, Medium to `dimensionValues[1].value`, Sessions to `metricValues[0].value`, Goal Completions to `metricValues[1].value`. Compute Conversion Rate inline as `metricValues[1].value / metricValues[0].value`. Do not pre-format the rate as a percentage — keep it decimal so the Sheets formula in step 6 doesn't break.
- 4
Fetch HubSpot deals updated in the past 7 days
Add an HTTP module. Method: POST. URL: `https://api.hubapi.com/crm/v3/objects/deals/search`. Auth: Private App token in the Header as `Authorization: Bearer YOUR_TOKEN`. Body: `{ filterGroups:[{filters:[{propertyName:'hs_lastmodifieddate', operator:'GTE', value: EPOCH_7_DAYS_AGO}]}], properties:['dealname','dealstage','amount','hs_deal_stage_probability','deal_source','hs_time_in_[stage]'], limit:100 }`. Paginate using `paging.next.after` if `total > 100`. Calculate `EPOCH_7_DAYS_AGO` with Make's date functions — don't hardcode it or your Monday run pulls stale data by Tuesday.
- 5
Write HubSpot deal data to Sheets and compute velocity
Use another Iterator plus Google Sheets 'Add a Row' to write each deal to Sheet 2 ('HubSpot Weekly'). Map Deal Source from the custom `deal_source` property — this must match your UTM source values exactly. Enforce this with a HubSpot workflow that copies `original_source` to `deal_source` on deal creation. If that workflow isn't live before you run this, the join in step 6 produces zeros. For Avg Days in Stage, use a Google Sheets formula in that column: `=AVERAGEIF(B:B, B2, F:F)` where column F is `hs_time_in_current_stage` divided by 86400000 to convert milliseconds to days.
- 6
Join the two datasets and write the digest summary row
Add a Google Sheets 'Search Rows' module reading from both sheets filtered by this week's identifier. Add a Tools 'Set Variable' module to compute: for each source appearing in both datasets, calculate `conversion_to_deal_rate = HubSpot deal count / GA4 goal completions`, `avg_deal_value`, and `avg_velocity_days`. Write one summary row per source to Sheet 3 with these four metrics. Flag any source where velocity has increased by more than 20% week-over-week. That flag is the thing your team will actually act on — don't skip it.
- 7
Format and post the Slack digest
Add a Slack 'Create a Message' module. Channel: `#growth-ops`. Use Slack block kit with a Section block per top-5 source sorted by deal value. Format each line as: `[Source/Medium] → [Sessions] sessions → [Goal CVR]% → [Deal Count] deals → Avg $[value] — [velocity] days to current stage`. Append a footer: `Full data: [link to Google Sheet]`. Schedule the scenario trigger to run every Monday at 07:30 using Make's built-in scheduler. Don't set it to run at 09:00 — you want this waiting in Slack before standup, not during it.
Want me to build this for you instead?
Product Audit and CTO Mode run out of this same thinking. If you’re reading this thinking “I want this, but in my product” — let’s talk.
See servicesMore like this
Gmail Thread Aging + Stripe Invoice Overdue: Unified AR Follow-Up Digest to Slack via Zapier
Surface overdue Stripe invoices and the exact age of your last Gmail thread with that customer — every morning at 8:30, automatically — so AR follow-up stops living in someone's head.
Intercom Ticket Volume + Razorpay Failed Payments: Daily Support-Cost-per-Revenue Alert to Slack via Zapier
Catch the support cost blowout from Razorpay failed payments before your agents are already buried.
Outlook Calendar Load + HubSpot Deal Velocity: Weekly Ops Digest to Microsoft Teams
Every Monday at 07:30, your revenue team gets one Teams card: last week's deal pipeline movement next to each rep's actual meeting load — so you stop guessing whether low close rates are a pipeline problem or a capacity problem.