6 min read

How to Set Up JQL Queries in Mixpanel

You need custom event data that Mixpanel's UI doesn't surface. JQL (Jelly Query Language) lets you query your event stream and user profiles directly with filters and aggregations. Here's how to set it up and start extracting data.

Get Credentials and Authenticate

JQL queries run against Mixpanel's Data Export API, which requires your project token and API secret.

Copy your project credentials

In the Mixpanel dashboard, go to Settings > Project Details. Copy your Project Token and API Secret—you'll need both for authentication.

javascript
// Store credentials in environment variables
const projectToken = process.env.MIXPANEL_PROJECT_TOKEN;
const apiSecret = process.env.MIXPANEL_API_SECRET;
Never hardcode credentials. Use environment variables or a secrets manager.

Set up HTTP Basic Auth

JQL requests use HTTP Basic Auth where the username is your Project Token and password is your API Secret. Configure this in your HTTP client.

javascript
const axios = require('axios');

const httpAuth = {
  username: projectToken,
  password: apiSecret
};

// Use this auth object in all API requests
const headers = {
  'Content-Type': 'application/json'
};
Basic auth configuration for Mixpanel API requests
Watch out: Your API Secret is sensitive. Never expose it in client-side code or commit it to version control.

Write and Execute Your First Query

JQL queries select columns in a data block and filter with optional where clauses.

Structure a basic event query

Start with a simple query that selects specific event properties. The data block defines which columns to return; the where clause filters by event name.

javascript
const jqlQuery = `
  data {
    event_name,
    properties.$distinct_id,
    properties.$browser,
    time
  }
  where event == "Purchase"
  limit 100
`;

console.log(jqlQuery);
Basic JQL: select properties from Purchase events

POST the query to the API

Send your JQL query to https://data.mixpanel.com/api/2.0/jql with the query string in the data property of the request body.

javascript
const response = await axios.post(
  'https://data.mixpanel.com/api/2.0/jql',
  { data: jqlQuery },
  { 
    auth: { 
      username: projectToken, 
      password: apiSecret 
    }
  }
);

const events = response.data;
console.log(`Fetched ${events.length} events`);
Execute the JQL query via the Data Export API

Process the results

The API returns a JSON array of event objects. Each object contains the properties you specified in your data block.

javascript
events.forEach(event => {
  console.log(`User: ${event.properties.$distinct_id}`);
  console.log(`Browser: ${event.properties.$browser}`);
  console.log(`Time: ${event.time}`);
});

// Filter results in memory if needed
const highValueUsers = events.filter(e => e.properties.amount > 100);
Iterate through and filter query results
Tip: Start with a small limit to test. JQL can return large datasets fast—test before querying millions of rows.

Filter and Aggregate Data

Use where clauses with conditions and group by for summary statistics.

Add multiple filter conditions

Combine conditions with and / or. Filter by property values, date ranges, or specific user segments.

javascript
const jqlQuery = `
  data {
    event_name,
    properties.$distinct_id,
    properties.amount,
    properties.plan_type,
    time
  }
  where event == "Purchase"
  and properties.amount > 50
  and properties.plan_type in ["pro", "enterprise"]
  and time >= "2026-01-01"
  limit 500
`;

const response = await axios.post(
  'https://data.mixpanel.com/api/2.0/jql',
  { data: jqlQuery },
  { auth: { username: projectToken, password: apiSecret } }
);
Query with multiple conditions and date filtering

Use aggregation functions for summaries

Return aggregated metrics (count, sum, average) by using functions in your data block. Pair with group by to segment results.

javascript
const jqlQuery = `
  data {
    plan = properties.plan_type,
    event_count = count(),
    total_revenue = sum(properties.amount),
    avg_order_value = avg(properties.amount)
  }
  where event == "Purchase"
  group by properties.plan_type
`;

const response = await axios.post(
  'https://data.mixpanel.com/api/2.0/jql',
  { data: jqlQuery },
  { auth: { username: projectToken, password: apiSecret } }
);

response.data.forEach(row => {
  console.log(`${row.plan}: ${row.event_count} purchases, $${row.total_revenue} revenue`);
});
Aggregate revenue and count by plan type
Tip: JQL supports relative dates: time >= now() - 30d for the last 30 days or time >= now() - 1h for the last hour.

Common Pitfalls

  • Forgetting that event and property names are case-sensitive. event == "Purchase" and event == "purchase" return different results.
  • Confusing event properties (properties.amount) with user profile properties. Use the correct syntax for each context.
  • Running queries with no limit or a very high limit on large datasets. Start with limit 100 and increase incrementally.
  • Not checking your actual event schema before writing queries. Non-existent properties return null, not errors.

Wrapping Up

You now have a working setup for querying Mixpanel events directly via JQL. Use this for custom reports, data exports, and analysis beyond the dashboard. If you want to track this automatically across tools, Product Analyst can help.

Track these metrics automatically

Product Analyst connects to your stack and surfaces the insights that matter.

Try Product Analyst — Free