Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/mixpanel/docs/llms.txt

Use this file to discover all available pages before exploring further.

HTTP API Ingestion

Mixpanel’s HTTP API provides direct access to ingest events and user profile data. Use the API when:
  • You need to send data from a language without an SDK
  • You want full control over the data being sent
  • You’re building a custom integration
  • You need to import historical data

API Endpoints

Mixpanel provides different API endpoints based on your project’s data residency:
Data ResidencyBase URL
US (default)https://api.mixpanel.com
EUhttps://api-eu.mixpanel.com
Indiahttps://api-in.mixpanel.com
Projects with India Data Residency must use api-in.mixpanel.com or events will be rejected.

Track Events: /track

The /track endpoint ingests events in real-time. Use this for events that occurred within the last 5 days.

Endpoint

POST https://api.mixpanel.com/track

Request Format

Headers:
Content-Type: application/json
accept: text/plain
Body:
[
  {
    "event": "Sign Up",
    "properties": {
      "token": "YOUR_PROJECT_TOKEN",
      "distinct_id": "user_123",
      "time": 1618716477000,
      "$insert_id": "unique_event_id_123",
      "plan": "premium",
      "source": "landing_page"
    }
  }
]

Required Properties

PropertyTypeDescription
eventStringThe name of the event
properties.tokenStringYour Mixpanel project token
properties.distinct_idStringUnique identifier for the user

Common Optional Properties

PropertyTypeDescription
properties.timeNumberUnix timestamp (milliseconds) when event occurred
properties.$insert_idStringUnique ID to deduplicate events
properties.ipStringIP address for geolocation (use 0 to skip)
properties.$device_idStringDevice identifier for anonymous tracking

Example: Track Event with cURL

curl --request POST \
  --url https://api.mixpanel.com/track \
  --header 'Content-Type: application/json' \
  --header 'accept: text/plain' \
  --data '[
    {
      "event": "Video Watched",
      "properties": {
        "token": "YOUR_PROJECT_TOKEN",
        "distinct_id": "user_456",
        "time": 1698023982000,
        "video_title": "Getting Started",
        "duration": 120,
        "completion_rate": 0.85
      }
    }
  ]'

Example: Track Event with Python

import requests
import json
import time

url = "https://api.mixpanel.com/track"

payload = [{
    "event": "Purchase Completed",
    "properties": {
        "token": "YOUR_PROJECT_TOKEN",
        "distinct_id": "user_789",
        "time": int(time.time() * 1000),
        "$insert_id": "purchase_xyz_123",
        "product_name": "Premium Subscription",
        "price": 29.99,
        "currency": "USD"
    }
}]

headers = {
    "Content-Type": "application/json",
    "accept": "text/plain"
}

response = requests.post(url, json=payload, headers=headers)
print(f"Status: {response.status_code}")
print(f"Response: {response.text}")

Batch Tracking

You can send multiple events in a single request:
[
  {
    "event": "Page Viewed",
    "properties": {
      "token": "YOUR_PROJECT_TOKEN",
      "distinct_id": "user_123",
      "page": "Home"
    }
  },
  {
    "event": "Button Clicked",
    "properties": {
      "token": "YOUR_PROJECT_TOKEN",
      "distinct_id": "user_123",
      "button_name": "Sign Up"
    }
  }
]
Maximum batch size is 2000 events per request.

Import Historical Events: /import

The /import endpoint is designed for importing events older than 5 days. It requires authentication with your API secret.

Endpoint

POST https://api.mixpanel.com/import

Authentication

Use HTTP Basic Auth with your API secret:
curl --request POST \
  --url https://api.mixpanel.com/import \
  --user "YOUR_API_SECRET:" \
  --header 'Content-Type: application/json' \
  --data '[
    {
      "event": "Historical Event",
      "properties": {
        "token": "YOUR_PROJECT_TOKEN",
        "distinct_id": "user_123",
        "time": 1609459200000
      }
    }
  ]'

Find Your API Secret

  1. Navigate to Project Settings
  2. Under Access Keys, find your Project Secret
Keep your API secret confidential. Never expose it in client-side code or public repositories.

Example: Import with Python

import requests
import base64

url = "https://api.mixpanel.com/import"
api_secret = "YOUR_API_SECRET"

payload = [{
    "event": "Historical Purchase",
    "properties": {
        "token": "YOUR_PROJECT_TOKEN",
        "distinct_id": "user_456",
        "time": 1609459200000,  # Jan 1, 2021
        "product": "Annual Plan",
        "amount": 299.00
    }
}]

# Create Basic Auth header
auth_string = f"{api_secret}:"
auth_bytes = auth_string.encode('ascii')
auth_b64 = base64.b64encode(auth_bytes).decode('ascii')

headers = {
    "Content-Type": "application/json",
    "Authorization": f"Basic {auth_b64}"
}

response = requests.post(url, json=payload, headers=headers)
print(f"Status: {response.status_code}")
print(f"Response: {response.text}")

User Profile Updates: /engage

The /engage endpoint updates user profile properties.

Endpoint

POST https://api.mixpanel.com/engage

Set Profile Properties

curl --request POST \
  --url https://api.mixpanel.com/engage \
  --header 'Content-Type: application/json' \
  --data '[
    {
      "$token": "YOUR_PROJECT_TOKEN",
      "$distinct_id": "user_123",
      "$set": {
        "$name": "Jane Doe",
        "$email": "jane@example.com",
        "plan": "premium",
        "signup_date": "2024-01-15"
      }
    }
  ]'

Profile Operations

OperationDescription
$setSet properties (overwrites existing)
$set_onceSet properties only if they don’t exist
$addIncrement numeric properties
$appendAppend to list properties
$unionAdd to list only if not present
$removeRemove from list properties
$unsetDelete properties
$deleteDelete the entire profile

Example: Multiple Operations

import requests

url = "https://api.mixpanel.com/engage"

payload = [{
    "$token": "YOUR_PROJECT_TOKEN",
    "$distinct_id": "user_789",
    "$set": {
        "$name": "John Smith",
        "$email": "john@example.com"
    },
    "$set_once": {
        "first_seen": "2024-01-15"
    },
    "$add": {
        "login_count": 1,
        "total_revenue": 29.99
    },
    "$append": {
        "recent_purchases": "Premium Plan"
    }
}]

headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)

Identity Management

Simplified ID Merge

Link an anonymous user to a known user ID:
curl --request POST \
  --url https://api.mixpanel.com/track \
  --header 'Content-Type: application/json' \
  --data '[
    {
      "event": "$identify",
      "properties": {
        "token": "YOUR_PROJECT_TOKEN",
        "distinct_id": "user_123",
        "$anon_id": "device_xyz"
      }
    }
  ]'
This merges all events from device_xyz into the user_123 profile.

Best Practices

Include a unique $insert_id for each event to prevent duplicates:
{
  "event": "Purchase",
  "properties": {
    "token": "YOUR_PROJECT_TOKEN",
    "distinct_id": "user_123",
    "$insert_id": "purchase_abc_123",
    "amount": 99.99
  }
}
Mixpanel will reject duplicate events with the same $insert_id within 24 hours.
By default, Mixpanel uses the request IP for geolocation. For server-side tracking:Pass the client IP:
{
  "properties": {
    "token": "YOUR_PROJECT_TOKEN",
    "distinct_id": "user_123",
    "ip": "192.168.1.1"
  }
}
Skip geolocation:
{
  "properties": {
    "token": "YOUR_PROJECT_TOKEN",
    "distinct_id": "user_123",
    "ip": "0"
  }
}
Send multiple events in a single request to improve performance:
  • Maximum 2000 events per batch
  • Reduces network overhead
  • Improves throughput
# Batch multiple events
events = []
for user_action in user_actions:
    events.append({
        "event": user_action["event_name"],
        "properties": {
            "token": "YOUR_PROJECT_TOKEN",
            "distinct_id": user_action["user_id"],
            # ... other properties
        }
    })

# Send in batches of 500
batch_size = 500
for i in range(0, len(events), batch_size):
    batch = events[i:i+batch_size]
    requests.post("https://api.mixpanel.com/track", json=batch)
Mixpanel has rate limits to ensure service reliability:
  • 60 requests per hour for the /import endpoint per project
  • 2000 events per request maximum batch size
Implement exponential backoff for retries:
import time
import requests

def send_with_retry(url, payload, max_retries=3):
    for attempt in range(max_retries):
        response = requests.post(url, json=payload)
        
        if response.status_code == 200:
            return response
        
        if response.status_code == 429:  # Rate limited
            wait_time = (2 ** attempt) * 1  # Exponential backoff
            print(f"Rate limited. Waiting {wait_time}s...")
            time.sleep(wait_time)
        else:
            print(f"Error: {response.status_code} - {response.text}")
            break
    
    return None
Always check the API response:Success Response:
{
  "status": 1,
  "error": null
}
Error Response:
{
  "status": 0,
  "error": "Invalid token"
}
response = requests.post(url, json=payload)

if response.status_code == 200:
    result = response.json()
    if result.get("status") == 1:
        print("Success!")
    else:
        print(f"Error: {result.get('error')}")
else:
    print(f"HTTP Error: {response.status_code}")

Common Issues & Troubleshooting

  1. Check project token: Verify you’re using the correct token
  2. Verify data residency: Ensure you’re using the correct API endpoint
  3. Check timestamp: Events older than 5 days won’t be accepted by /track
  4. Look for errors: Check the API response for error messages
  5. View Events page: Check the Events view in Mixpanel
  • For /import endpoint: Verify your API secret is correct
  • Check that you’re using Basic Auth with the API secret
  • Ensure the API secret hasn’t been regenerated
  • Your batch is too large (>2000 events)
  • Split into smaller batches
  • Individual events might be too large (>2MB)
  • If tracking from a server, pass the client’s IP in the ip property
  • Set ip to "0" to skip geolocation
  • See geolocation best practices

API Reference

For complete API documentation, see:

Next Steps

Best Practices

Learn implementation best practices

View SDKs

Use our SDKs for easier implementation

Build docs developers (and LLMs) love