Mixpanel Funnel + Stripe Trial Conversion: Daily Cohort Health Digest to Slack via n8n

Every morning, join Mixpanel's trial activation data with Stripe's conversion data for the same cohort and push one digest to Slack — so you know in 30 seconds whether activation or billing is killing your trials.

The flow
Mixpanel logo
Source
Mixpanel
Stripe logo
Process
Stripe
n8n logo
Process
n8n
Slack logo
Destination
Slack

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

Why this stack

The most common blind spot in SaaS ops: product says activation is fine, finance says conversion is down, and nobody can tell whether the problem is in-product behavior or the billing step. The data lives in two places. Nobody joins it manually more than once a quarter.

n8n is the right call here because this workflow needs conditional logic and light data transformation between API calls — specifically joining two datasets on user ID or email. n8n's Function nodes let you write real JavaScript for that join. It also self-hosts cleanly if you're cautious about sending user cohort data to a third-party SaaS automation platform.

Mixpanel's Query API (`/funnels`) returns step-by-step conversion for a defined date range. Stripe's `/v1/subscriptions` endpoint filtered by `status=trialing` and a `trial_end` date range gives you trials expiring in the next 7 days and which ones converted. You don't need a data warehouse — n8n holds the join in memory for a daily digest.

One real tradeoff: Mixpanel's API rate limits are 60 queries/hour on the free/growth plan. This workflow makes 2–3 calls per run, so you're fine there. The bigger risk is that Mixpanel user IDs and Stripe customer emails may not match. You need Mixpanel's `$email` property set during `identify()` calls for the join to work. If your Mixpanel events don't include email, the join breaks and you need a Segment intermediary. Also — skip this entire workflow if you have more than ~10,000 trial users. At that volume the in-memory join in n8n becomes unreliable. Pipe both sources into Supabase and run SQL instead.

The stack (4)

  1. Mixpanel logo

    Product analytics for events and funnels.

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

  2. Stripe logo

    Global payments with first-class APIs.

    Events + Sigma let you wire billing into any ops report or alert.

  3. n8n logo

    Self-hostable workflow automation.

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

  4. Slack logo

    Team chat where most ops alerts and reports land.

    The default place a small team already lives — pipe reports here instead of email nobody opens.

How it runs

  1. 1

    Set up the n8n workflow with a daily CRON trigger

    Create a new workflow in n8n. Add a Schedule Trigger node set to run at 8:00 AM in your local timezone every day. Name it `trial-cohort-health-digest`. Be explicit about the timezone — n8n defaults to server timezone, which is usually UTC. A digest hitting Slack at 3 AM gets ignored.

  2. 2

    Query Mixpanel funnel conversion for the last 7 days

    Add an HTTP Request node. Method: GET. URL: `https://mixpanel.com/api/2.0/funnels`. Auth: Basic auth with your Mixpanel API Secret as the username, empty password. Params: `funnel_id` (pull this from your Mixpanel funnel URL), `from_date` set to today minus 8 days, `to_date` set to today minus 1 day, `unit=day`. The response includes per-step counts and conversion rates. Wire a Function node after it to parse the `steps` array and extract step names, counts, and the overall funnel conversion rate.

  3. 3

    Query Stripe for trials ending in the next 7 days and their status

    Add a second HTTP Request node. Method: GET. URL: `https://api.stripe.com/v1/subscriptions`. Auth: Bearer with your Stripe secret key. Params: `status=trialing`, `trial_end[gte]` = today's Unix timestamp, `trial_end[lte]` = today + 7 days Unix timestamp, `limit=100`. Make a second call for `status=active` subscriptions where `metadata.converted_from_trial=true` if you tag conversions, or filter by `created` date range. This gets you trials-in-flight and recent converts.

  4. 4

    Join Mixpanel and Stripe data on email in a Function node

    Add a Function node. Build two maps: one from Stripe `customer.email → subscription status`, one from Mixpanel's user-level funnel data if you're using the Engage API — or use aggregate counts if not. For an aggregate digest, calculate: `trialsInFlight`, `trialsConvertedThisWeek`, `trialConversionRate`, `mixpanelActivationRate` (step 1 → final step). High activation rate paired with low conversion rate means billing or pricing friction — not a product problem. Document this logic in an n8n Sticky Note so whoever inherits the workflow doesn't have to reverse-engineer it.

  5. 5

    Calculate the cohort health score and flag anomalies

    In the same Function node or a chained one, compute a simple health score: `trialConversionRate < 15%` flags RED, 15–25% flags YELLOW, >25% flags GREEN. Do the same for `mixpanelActivationRate` using thresholds based on your historical baseline — hardcode them to start, refine after 30 days of data. Store both flags. If either is RED, set `alertRequired = true`.

  6. 6

    Build the Slack Block Kit message

    Add a Function node to construct the Slack payload. Structure it as: a header with the date range, a two-column section showing Mixpanel activation rate vs. Stripe trial conversion rate, a Diagnosis line (e.g., "Activation OK, Conversion Low → check pricing page or trial-end email sequence"), and a footer with raw counts. Use emoji status indicators. Keep it under 15 lines — if someone has to scroll, they won't read it.

  7. 7

    Post to Slack with conditional urgency

    Add a Slack node using n8n's built-in Slack integration with your Bot Token. Always post to `#product-ops`. Add an IF node before the Slack node: if `alertRequired = true`, route to a second Slack node that posts to `#alerts` and includes an @here or a specific user mention. The digest always hits the ops channel. It only pages people when a threshold is actually breached.

  8. 8

    Add error handling for API failures

    Add an Error Trigger node in n8n connected to a final Slack node that posts to `#ops-errors` if the workflow fails. The most common failure points are Mixpanel rate limits and Stripe API timeouts. Add a Wait node with a 2-second delay before each HTTP call to reduce burst issues. Include the error message in the Slack notification — whoever sees it needs to diagnose the problem without opening n8n.

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