Mixpanel Activation Funnel + HubSpot Deal Stage Reconciliation: Weekly Ops Digest to Microsoft Teams

Your product says a user activated. Your CRM says the deal is still in 'Demo Scheduled'. Nobody follows up. The account goes cold. This workflow catches that every Monday before anyone notices.

The flow
Mixpanel logo
Source
Mixpanel
HubSpot logo
Process
HubSpot
n8n logo
Process
n8n
Google Sheets logo
Process
Google Sheets
Microsoft Teams logo
Destination
Microsoft Teams

The stack in the order it runs — data flows from the source through to where it lands.

Why this stack

The gap between product activation and CRM deal stage is one of the most expensive blind spots in B2B SaaS. A user completes onboarding but their HubSpot deal hasn't moved — no one follows up, the account goes cold. Flip it: a deal is 'Closed Won' and the user never hit a single activation event. Churn risk is already baked in at the point of sale, before your CS team even knows the account exists.

Mixpanel's Engage API lets you pull every user who fired a specific event — `feature_activated`, `report_created`, whatever your activation definition is — inside a rolling 7-day window. HubSpot's Contacts and Deals API gives you deal stage by associated email. The reconciliation is a join on email. Embarrassingly simple. Almost nobody automates it.

Use n8n over Zapier here. You need a programmatic join across two live data sources, which means a Code node in JavaScript. Zapier's code step is constrained, and its multi-step logic gets expensive fast at this volume. n8n self-hosted runs this free. The cloud starter plan is $20/month and handles weekly runs without breaking a sweat.

Teams is the right delivery channel if your ops and sales team live there — which most B2B SaaS teams do. The setup is minimal: create an Incoming Webhook connector in Teams, paste the URL into an n8n HTTP Request node. You do not need the Microsoft Graph API for this. Skip this playbook if your sales team doesn't actively maintain HubSpot deal stages — if deals sit in 'New' for months, the output is noise. Also skip if you're under 10 new signups per week; the value only surfaces at meaningful activation volume.

The stack (5)

  1. Mixpanel logo

    Product analytics for events and funnels.

    The export/query API turns product metrics into scheduled reports you push to chat.

  2. HubSpot logo

    CRM + marketing for go-to-market.

    Pipeline data becomes an automatable input for revenue reports.

  3. n8n logo

    Self-hostable workflow automation.

    Own your data and run unlimited steps without per-task pricing.

  4. Google Sheets logo

    The universal data scratchpad.

    Still the fastest place to land tabular data everyone can read.

  5. Microsoft Teams logo

    Chat + channels for Microsoft-365 shops.

    If the company is on Outlook/365, Teams is where reports get read — push there, not a separate tool.

How it runs

  1. 1

    Define activation events and deal stages

    Before touching any tool, write down the specific Mixpanel events that mean 'activated' for your product — for example, `project_created` AND `teammate_invited` both fired within 7 days of signup. Then write down the HubSpot deal stages that SHOULD correspond to an activated user, like 'Trial Active' or 'Closed Won'. These become your reconciliation rules. Misalignment almost always traces back to teams skipping this step and reconciling against vague criteria.

  2. 2

    Pull activated users from Mixpanel

    In n8n, create a workflow triggered by a weekly cron at Monday 7 AM local time. Add an HTTP Request node calling `POST https://mixpanel.com/api/2.0/engage` with your project token and secret as Basic Auth. Set the `where` parameter to filter users who fired your activation events in the last 7 days — for example, `properties['last_event_date'] > '2024-01-01'`. The response is paginated. Loop through pages using n8n's loop node until the `page` field returns fewer than 1,000 results.

  3. 3

    Pull matching deal stages from HubSpot

    Add a second HTTP Request node calling `GET https://api.hubapi.com/crm/v3/objects/contacts/search` with a Bearer token from your HubSpot private app. Pass the Mixpanel email addresses as filter values using the `IN` filter operator on the `email` property, batched at 100 emails per request. Set `associations: ['deals']` in the response fields to get associated deal IDs back. Then call the Deals API to fetch the `dealstage` property for each deal ID. Store the joined result as an array of objects: `{email, mixpanel_activated: true/false, hubspot_dealstage: '...', deal_id: '...'}`. Pull `deal amount` here too — you'll need it in step 6.

  4. 4

    Run reconciliation logic in a Code node

    Add a Code node in JavaScript. Iterate the joined array and classify every record into one of four buckets: (1) Activated + correct deal stage — healthy; (2) Activated + stale deal stage, e.g., still 'Demo Scheduled' — needs sales follow-up; (3) Not activated + deal stage 'Closed Won' — churn risk, flag immediately; (4) Not activated + early deal stage — normal, ignore. Output two things: a `mismatches` array containing buckets 2 and 3, and a summary object with counts per bucket.

  5. 5

    Write mismatches to Google Sheets

    Add a Google Sheets node to append the `mismatches` array to a sheet named 'Reconciliation Log'. Columns: `week_start`, `email`, `deal_id`, `hubspot_dealstage`, `activation_status`, `mismatch_type`. Keep at least 12 weeks of history. The sheet does two jobs: audit trail for ops reviews, and raw data for anyone who wants to build a Looker Studio dashboard later. Always append. Never overwrite.

  6. 6

    Format and post the Teams digest

    Add an HTTP Request node targeting your Teams Incoming Webhook URL. POST a JSON payload using the Adaptive Card schema. Structure it as: a header reading '📊 Weekly Activation ↔ CRM Reconciliation — [date range]', a summary table with counts for all 4 buckets, then a bulleted list of mismatches showing partially masked email, deal stage, and mismatch type. Cap the list at the top 10 mismatches sorted by deal value — the `deal amount` you pulled in step 3. Do not dump 50 rows into Teams.

  7. 7

    Add a threshold alert for critical mismatches

    Before the Teams formatting step, insert an IF node. If the count of bucket-3 records — 'Closed Won but never activated' — exceeds 3 in a single week, fire a separate urgent Teams message to the #revenue-ops channel. Subject line: '🔴 Churn Risk: [N] Closed Won accounts not activated this week.' This is a separate Adaptive Card from the digest. It should feel like a page, not a report. Include a direct link to the Google Sheets log so the ops team can triage immediately.

  8. 8

    Auto-flag HubSpot deals for clear bucket-2 cases

    For bucket-2 mismatches where the user IS activated but the deal stage hasn't moved in 14 or more days, add a HubSpot update step. Call `PATCH https://api.hubapi.com/crm/v3/objects/deals/{deal_id}` to set a custom property `activation_reconciliation_flag: true`, and log a note in the deal timeline using the Engagements API. The sales rep sees the flag in HubSpot and knows to move the deal forward — no manual triage queue needed. One rule: auto-flag only. Never auto-advance the deal stage.

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 services

More like this