Cohort Sync to Webhooks

Mixpanel supports syncing cohorts to a custom webhook URL that you provide via our Integrations UI. When a sync is established, we will sync the full contents of the cohort to the URL and subsequently sync diffs (ie: the users who entered or exited the cohort since the last sync).


  • A paid Mixpanel plan
  • A Mixpanel project
  • A webhook server. You can create a dummy webhook for testing purposes using

Setting up the webhook via our UI

To create a new Custom Webhook destination, navigate to our Integrations UI and add a new Webhook connection. All you need to provide is a name for the connection and the URL of your webhook server.

Optional: Basic Authentication when calling the webhook URL provided

Setting up custom webhook integration.Setting up custom webhook integration.

Setting up custom webhook integration.

From this point onward, you can sync any cohort to this connection from our cohorts page.

Webhook Format

Our webhook format has the following structure in the body of a POST request:

  • action: The action defines the type of message we are sending. It will be one of:
    • members: All members of the cohort, sent the first time the cohort is being synced or to refresh the cohort if there are any intermediate errors. When you get this message, replace the users you have in the cohort with the copy provided by us.
    • add_members: A diff consisting of users that have entered the cohort since the last sync.
    • remove_members: A diff consisting of users who have exited the cohort since the last sync.
  • parameters
    • mixpanel_project_id: the ID for Mixpanel project that produced this cohort.
    • mixpanel_cohort_id: unique identifier of the cohort.
    • mixpanel_cohort_name: The cohort name, editable via the Mixpanel UI.
    • mixpanel_cohort_description: The cohort description, editable via the Mixpanel UI.
    • mixpanel_session_id: An identifier for this export. Mixpanel sends large cohorts over multiple messages; mixpanel_session_id uniquely identifies a set of requests that correspond to the same export.
    • page_info: An object containing “total_pages”, i.e. the number of total messages for the given session ID, and “page_count”, the index of which page this message is (e.g. message 6 of 10, in the example below). You may use this value to know if/when you’ve collected the full set of messages for an export.
    • members: The list of users being added or removed from the cohort. We include email, mixpanel_distinct_id, first_name, and last_name to help identify the user.

You can download the Swagger spec here.

  "action": "members",
  "parameters": {
    "mixpanel_project_id": "{mixpanel_project_id}",
    "mixpanel_cohort_name": "{mixpanel_cohort_name}",
    "mixpanel_cohort_id": "{mixpanel_cohort_id}",
    "mixpanel_cohort_description": "description",
    "mixpanel_session_id": "mixpanel_session_id",
    "page_info": {
      "total_pages": 10,
      "page_count": 6
    "members": [
        "email": "string",
        "mixpanel_distinct_id": "string",
        "first_name": "string",
        "last_name": "string",
        "phone_number": "xxx-xxx-xxxxx"
        "email": "string",
        "mixpanel_distinct_id": "string",
        "first_name": "string",
        "last_name": "string",
        "phone_number": "xxx-xxx-xxxxx"

Expected Response Format

We expect a JSON response of the following shape.

  • action: Must match the action we sent.
  • status: Must be either success or failure
  • error: Only expected on failure.
    • message: details about the error
    • code: an HTTP status code
  "action": "add_members",
  "status": "success", // or failure
  "error": {
    "message": "some error message; this will be displayed in our UI",
    "code": 400  // an HTTP status code

Simple Sync Scenario

Consider A, B, C, D, E, F as users. Sync interval is 30 minutes. T is when the sync is created in our UI.

add_members(...) indicates a call to the webhook to add members. remove_members(...) indicates a call to remove members.

  • T: add_members(A, B, C, D) | remove_members()
  • T+0.1h: B, D leave the cohort
  • T+0.2h: E, F join the cohort
  • T+0.5h: add_members(E, F) | remove_members(B, D)
  • <...No cohort changes...>
  • T+1h: add_members() | remove_members() calls are made to the customer webhook


What is the frequency of the syncs?
We sync cohorts once every 30 minutes.

How many users are in each batch?
The batch size is set at 1000 users per call to add_members or remove_members.

How does diffing work?
Every time we perform a successful sync to your webhook, we store a snapshot of the cohort as of that time. This snapshot is valid for 3 days. Subsequent syncs use the last successful snapshot of the cohort to compute the number of users added and removed (the diff). We send this diff to your webhook via the add_members and remove_members calls.

When is a full sync of all members in the cohort performed?
Full syncs are only performed when:

  • We sync the cohort for the first time.
  • We store the snapshot of the cohort state for the last successful sync for 3 days. If your webhook server is down (returns a 429 or 5XX error) for more than 3 days, the snapshot expires and we do a full sync.

How are diffs computed when a sync fails?
When a sync fails, we do not update the cohort snapshot. The next sync performed will recompute the diff based on the last successful snapshot (until 3 days have passed, at which point we will attempt to sync the full cohort). This ensures that the state of the cohort will converge to what Mixpanel has.

When are syncs paused?
We pause syncs on when your server returns a non-transient error (400, 401, 403, 404). Please use the appropriate HTTP status code to indicate a non-transient error; this helps avoid added load.

We record failed syncs in our UI and display the error message returned in the response from your webhook server (see the error.message field in the sample response above).

Do we get notified when the sync is paused?
Yes, an email is sent to all users who have set up cohort syncs when the syncs pause due to an error.

Do you retry on webhook call failures?
Yes, we retry 5 times over 60 secs with exponential backoff in response to 5xx and 429 status codes. After this point, we will wait until the next scheduled sync to retry.

Did this page help you?