Skip to main content

Query API

The Query API allows you to retrieve data from your Mixpanel reports programmatically. Query the same data you see in the Mixpanel UI to build custom dashboards, exports, and integrations.

Base URL

https://mixpanel.com/api/query
For EU data residency: https://eu.mixpanel.com/api/query For India data residency: https://in.mixpanel.com/api/query

Authentication

Use Service Account credentials with HTTP Basic Auth:
curl https://mixpanel.com/api/query/insights \
  -u SERVICE_ACCOUNT_USERNAME:SERVICE_ACCOUNT_SECRET \
  -d project_id=YOUR_PROJECT_ID \
  -d bookmark_id=12345

Rate Limits

The Query API has strict rate limits:
  • 60 queries per hour
  • 5 concurrent queries maximum
  • 3 queries per second
Exceeding these limits returns a 429 Too Many Requests error.

Available Endpoints

Insights

Query saved Insights reports to get event counts and trends. View Insights Documentation →

Funnels

Retrieve funnel analysis data including conversion rates and drop-off points. View Funnels Documentation →

Retention

Query retention data for cohort and frequency analysis. View Retention Documentation →

Cohorts

List cohorts and retrieve cohort membership information. View Cohorts Documentation →

Common Parameters

Most Query API endpoints accept these common parameters:
project_id
integer
required
Your Mixpanel project ID
workspace_id
integer
The workspace ID (optional, for workspace-specific queries)
from_date
string
Start date in YYYY-MM-DD format
to_date
string
End date in YYYY-MM-DD format

Response Format

All Query API responses follow a consistent structure:
{
  "computed_at": "2024-01-15T10:30:00+00:00",
  "status": "ok",
  "results": {
    // Endpoint-specific data
  }
}

Best Practices

Since the Query API has low rate limits, cache results on your side:
import time
from functools import lru_cache

@lru_cache(maxsize=100)
def get_insights_data(project_id, bookmark_id, cache_time):
    # cache_time changes every hour to refresh data
    return fetch_insights(project_id, bookmark_id)

# Call with current hour as cache key
data = get_insights_data(123, 456, int(time.time() / 3600))
Query saved reports (Insights, Funnels) rather than building queries from scratch. This ensures consistency with the UI and better performance.
For large exports or heavy queries, schedule them during off-peak hours to minimize impact on rate limits.
Track your query usage to avoid hitting rate limits:
import time
from collections import deque

class QueryTracker:
    def __init__(self):
        self.queries = deque(maxlen=60)
    
    def can_query(self):
        now = time.time()
        # Remove queries older than 1 hour
        while self.queries and now - self.queries[0] > 3600:
            self.queries.popleft()
        return len(self.queries) < 60
    
    def record_query(self):
        self.queries.append(time.time())

Error Handling

import requests
import time
from requests.auth import HTTPBasicAuth

def query_with_retry(url, params, max_retries=3):
    """Query with exponential backoff for rate limits"""
    
    for attempt in range(max_retries):
        response = requests.get(
            url,
            auth=HTTPBasicAuth('USERNAME', 'SECRET'),
            params=params
        )
        
        if response.status_code == 200:
            return response.json()
        elif response.status_code == 429:
            if attempt < max_retries - 1:
                delay = 2 ** attempt * 60  # 1min, 2min, 4min
                print(f"Rate limited. Waiting {delay}s...")
                time.sleep(delay)
            else:
                raise Exception("Rate limit exceeded")
        else:
            response.raise_for_status()
    
    raise Exception("Max retries exceeded")

# Usage
data = query_with_retry(
    'https://mixpanel.com/api/query/insights',
    {'project_id': 123, 'bookmark_id': 456}
)

Finding Report IDs

Insights Report ID (bookmark_id)

  1. Open your Insights report in Mixpanel
  2. Look at the URL:
    https://mixpanel.com/project/{PROJECT_ID}/view/{WORKSPACE_ID}/app/boards#id=12345&editor-card-id="report-{BOOKMARK_ID}"
    
  3. The BOOKMARK_ID is the number after report-

Funnel ID

  1. Open your Funnel report
  2. Use the List Funnels endpoint to get all funnel IDs:
    curl https://mixpanel.com/api/query/funnels/list \
      -u USERNAME:SECRET \
      -d project_id=YOUR_PROJECT_ID
    

Workspace ID

  1. Open any report in your workspace
  2. Check the URL for the workspace ID:
    https://mixpanel.com/project/{PROJECT_ID}/view/{WORKSPACE_ID}/...
    

Common Use Cases

Custom Dashboard

import requests
from requests.auth import HTTPBasicAuth

class MixpanelDashboard:
    def __init__(self, username, secret, project_id):
        self.auth = HTTPBasicAuth(username, secret)
        self.project_id = project_id
        self.base_url = 'https://mixpanel.com/api/query'
    
    def get_daily_signups(self):
        """Get signup counts from Insights report"""
        response = requests.get(
            f'{self.base_url}/insights',
            auth=self.auth,
            params={
                'project_id': self.project_id,
                'bookmark_id': 12345  # Your signup report ID
            }
        )
        return response.json()
    
    def get_signup_funnel(self):
        """Get conversion funnel data"""
        response = requests.get(
            f'{self.base_url}/funnels',
            auth=self.auth,
            params={
                'project_id': self.project_id,
                'funnel_id': 7890,
                'from_date': '2024-01-01',
                'to_date': '2024-01-31'
            }
        )
        return response.json()

# Usage
dashboard = MixpanelDashboard('username', 'secret', 123)
signups = dashboard.get_daily_signups()
funnel = dashboard.get_signup_funnel()

Automated Reports

import requests
import schedule
import time
from requests.auth import HTTPBasicAuth

def send_daily_report():
    """Fetch Mixpanel data and send report"""
    
    # Query Mixpanel
    response = requests.get(
        'https://mixpanel.com/api/query/insights',
        auth=HTTPBasicAuth('username', 'secret'),
        params={
            'project_id': 123,
            'bookmark_id': 456
        }
    )
    
    data = response.json()
    
    # Process and send report
    send_email_report(data)
    print(f"Report sent: {data['computed_at']}")

# Schedule daily at 9 AM
schedule.every().day.at("09:00").do(send_daily_report)

while True:
    schedule.run_pending()
    time.sleep(60)

Next Steps

Insights

Query event trends and metrics

Funnels

Analyze conversion funnels

Retention

Measure user retention

Cohorts

Work with user cohorts

Build docs developers (and LLMs) love