> ## 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.

# Events

> Track user events and behaviors

# Track Events

Events represent user actions in your application. Use the Ingestion API to send events to Mixpanel for analysis.

## Import Events

The Import API provides server-side event tracking with full validation and detailed error reporting.

<ParamField query="project_id" type="string" required>
  Your Mixpanel project ID (required when using service account authentication)
</ParamField>

<ParamField query="strict" type="string" default="1">
  When set to `1` (recommended), Mixpanel validates the batch and returns errors per event that failed.

  Options: `0` or `1`
</ParamField>

<ParamField header="Content-Type" type="string" default="application/json">
  The content type of the request body.

  Options:

  * `application/json`: Standard JSON array
  * `application/x-ndjson`: Newline-delimited JSON
</ParamField>

<ParamField header="Content-Encoding" type="string">
  Compression method for the request body.

  Options: `gzip`
</ParamField>

### Request Body

<ParamField body="event" type="string" required>
  The name of the event (e.g., "Signed Up", "Purchase Complete")
</ParamField>

<ParamField body="properties" type="object" required>
  Event properties object

  <Expandable title="properties">
    <ParamField body="time" type="integer" required>
      Event timestamp in seconds or milliseconds since UTC epoch. If set in the future, it will be overwritten with the current time at ingestion.
    </ParamField>

    <ParamField body="distinct_id" type="string" required>
      The unique identifier of the user who performed the event
    </ParamField>

    <ParamField body="$insert_id" type="string" required>
      A unique identifier for the event, used for deduplication. Events with identical (event, time, distinct\_id, \$insert\_id) are considered duplicates.
    </ParamField>

    <ParamField body="[custom properties]" type="any">
      Any additional custom properties for the event
    </ParamField>
  </Expandable>
</ParamField>

### Example Request

<CodeGroup>
  ```bash cURL theme={null}
  curl https://api.mixpanel.com/import?strict=1&project_id=YOUR_PROJECT_ID \
    -u SERVICE_ACCOUNT_USERNAME:SERVICE_ACCOUNT_SECRET \
    -H "Content-Type: application/json" \
    -d '[
      {
        "event": "Signed Up",
        "properties": {
          "time": 1609459200,
          "distinct_id": "user123",
          "$insert_id": "28a0f0a8-4e8c-4c4e-b8c1-832e9e5c5e5e",
          "signup_method": "email",
          "plan": "premium"
        }
      },
      {
        "event": "Purchase",
        "properties": {
          "time": 1609459260,
          "distinct_id": "user123",
          "$insert_id": "3f9a2c5b-7d1e-4b2a-9c3d-4e5f6a7b8c9d",
          "amount": 29.99,
          "currency": "USD",
          "item_name": "Premium Plan"
        }
      }
    ]'
  ```

  ```python Python theme={null}
  import requests
  import time
  import uuid
  from requests.auth import HTTPBasicAuth

  events = [
      {
          "event": "Signed Up",
          "properties": {
              "time": int(time.time()),
              "distinct_id": "user123",
              "$insert_id": str(uuid.uuid4()),
              "signup_method": "email",
              "plan": "premium"
          }
      },
      {
          "event": "Purchase",
          "properties": {
              "time": int(time.time()),
              "distinct_id": "user123",
              "$insert_id": str(uuid.uuid4()),
              "amount": 29.99,
              "currency": "USD"
          }
      }
  ]

  response = requests.post(
      'https://api.mixpanel.com/import',
      auth=HTTPBasicAuth('SERVICE_ACCOUNT_USERNAME', 'SERVICE_ACCOUNT_SECRET'),
      params={
          'project_id': 'YOUR_PROJECT_ID',
          'strict': '1'
      },
      json=events
  )

  print(response.json())
  ```

  ```javascript JavaScript theme={null}
  const events = [
    {
      event: 'Signed Up',
      properties: {
        time: Math.floor(Date.now() / 1000),
        distinct_id: 'user123',
        $insert_id: crypto.randomUUID(),
        signup_method: 'email',
        plan: 'premium'
      }
    },
    {
      event: 'Purchase',
      properties: {
        time: Math.floor(Date.now() / 1000),
        distinct_id: 'user123',
        $insert_id: crypto.randomUUID(),
        amount: 29.99,
        currency: 'USD'
      }
    }
  ];

  const username = 'SERVICE_ACCOUNT_USERNAME';
  const password = 'SERVICE_ACCOUNT_SECRET';
  const auth = 'Basic ' + btoa(username + ':' + password);

  fetch('https://api.mixpanel.com/import?strict=1&project_id=YOUR_PROJECT_ID', {
    method: 'POST',
    headers: {
      'Authorization': auth,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(events)
  })
  .then(response => response.json())
  .then(data => console.log(data));
  ```
</CodeGroup>

### Response

<ResponseField name="code" type="integer">
  HTTP status code (200 for success)
</ResponseField>

<ResponseField name="num_records_imported" type="integer">
  Number of events successfully imported
</ResponseField>

<ResponseField name="status" type="string">
  Status message ("OK" for success)
</ResponseField>

<ResponseField name="failed_records" type="array">
  Array of failed events (only present when strict=1 and some events failed)

  <Expandable title="failed_records[]">
    <ResponseField name="index" type="integer">
      Index of the failed event in the request array
    </ResponseField>

    <ResponseField name="insert_id" type="string">
      The \$insert\_id of the failed event
    </ResponseField>

    <ResponseField name="field" type="string">
      The field that caused the validation error
    </ResponseField>

    <ResponseField name="message" type="string">
      Description of the validation error
    </ResponseField>
  </Expandable>
</ResponseField>

<CodeGroup>
  ```json 200 Success theme={null}
  {
    "code": 200,
    "num_records_imported": 2,
    "status": "OK"
  }
  ```

  ```json 400 Validation Error theme={null}
  {
    "code": 400,
    "error": "Some data points in the request failed validation.",
    "status": "Bad Request",
    "num_records_imported": 1,
    "failed_records": [
      {
        "index": 0,
        "insert_id": "28a0f0a8-4e8c-4c4e-b8c1-832e9e5c5e5e",
        "field": "properties.time",
        "message": "'properties.time' is invalid: must be specified as seconds since epoch"
      }
    ]
  }
  ```

  ```json 401 Unauthorized theme={null}
  {
    "code": 401,
    "error": "Invalid credentials",
    "status": "Unauthorized"
  }
  ```

  ```json 413 Payload Too Large theme={null}
  {
    "code": 413,
    "error": "request exceeds max limit of 2097152 bytes",
    "status": "Request Entity Too Large"
  }
  ```

  ```json 429 Rate Limited theme={null}
  {
    "code": 429,
    "error": "Project exceeded rate limits. Please retry the request with exponential backoff.",
    "status": "Too Many Requests"
  }
  ```
</CodeGroup>

***

## Track Events (Client-Side)

The Track API is designed for client-side event tracking using your project token.

<ParamField query="ip" type="string">
  If set to `1`, uses the IP address of the request to determine geolocation
</ParamField>

<ParamField query="verbose" type="string">
  If set to `1`, returns a verbose JSON response instead of simple `1` or `0`
</ParamField>

### Request Body

<ParamField body="event" type="string" required>
  The name of the event
</ParamField>

<ParamField body="properties" type="object" required>
  Event properties

  <Expandable title="properties">
    <ParamField body="token" type="string" required>
      Your project token
    </ParamField>

    <ParamField body="distinct_id" type="string" required>
      Unique identifier for the user
    </ParamField>

    <ParamField body="time" type="integer">
      Event timestamp in seconds or milliseconds since UTC epoch
    </ParamField>

    <ParamField body="$insert_id" type="string">
      Unique identifier for deduplication
    </ParamField>
  </Expandable>
</ParamField>

### Example Request

<CodeGroup>
  ```bash cURL theme={null}
  curl https://api.mixpanel.com/track \
    --data-urlencode data='[
      {
        "event": "Page View",
        "properties": {
          "token": "YOUR_PROJECT_TOKEN",
          "distinct_id": "user123",
          "time": 1609459200,
          "page_name": "Homepage",
          "referrer": "google.com"
        }
      }
    ]'
  ```

  ```javascript JavaScript theme={null}
  const event = {
    event: 'Page View',
    properties: {
      token: 'YOUR_PROJECT_TOKEN',
      distinct_id: 'user123',
      time: Math.floor(Date.now() / 1000),
      page_name: 'Homepage'
    }
  };

  fetch('https://api.mixpanel.com/track', {
    method: 'POST',
    body: 'data=' + encodeURIComponent(JSON.stringify([event]))
  });
  ```
</CodeGroup>

### Response

Returns `1` for success, `0` for failure.

***

## Best Practices

<AccordionGroup>
  <Accordion title="Always use $insert_id for deduplication">
    This ensures events aren't duplicated if a request is retried:

    ```python theme={null}
    import uuid

    properties = {
        "$insert_id": str(uuid.uuid4()),
        "distinct_id": "user123",
        "time": int(time.time())
    }
    ```
  </Accordion>

  <Accordion title="Use server-side tracking when possible">
    The Import API provides:

    * Better validation and error reporting
    * More secure (credentials not exposed to clients)
    * Support for historical data imports
  </Accordion>

  <Accordion title="Batch events for better performance">
    Send up to 2000 events per request:

    ```python theme={null}
    batch = []
    for i in range(2000):
        batch.append(create_event(...))

    response = requests.post(url, json=batch)
    ```
  </Accordion>

  <Accordion title="Use meaningful event names">
    Use clear, consistent naming:

    * Good: "Signed Up", "Purchase Completed", "Video Played"
    * Bad: "event1", "action", "e"
  </Accordion>

  <Accordion title="Include relevant context in properties">
    Add properties that help analyze the event:

    ```json theme={null}
    {
      "event": "Purchase Completed",
      "properties": {
        "amount": 29.99,
        "currency": "USD",
        "item_name": "Premium Plan",
        "payment_method": "credit_card",
        "coupon_code": "SAVE10"
      }
    }
    ```
  </Accordion>
</AccordionGroup>

## Common Errors

<AccordionGroup>
  <Accordion title="Invalid timestamp">
    **Error:** `'properties.time' is invalid: must be specified as seconds since epoch`

    **Solution:** Ensure timestamps are in seconds (not milliseconds) or milliseconds (with 13 digits)

    ```python theme={null}
    # Correct: seconds
    "time": int(time.time())

    # Correct: milliseconds
    "time": int(time.time() * 1000)
    ```
  </Accordion>

  <Accordion title="Missing required fields">
    **Error:** Various validation errors

    **Solution:** Ensure all required fields are present:

    * `event` name
    * `properties.distinct_id`
    * `properties.time`
    * `properties.$insert_id` (for /import)
  </Accordion>

  <Accordion title="Payload too large">
    **Error:** `request exceeds max limit of 2097152 bytes`

    **Solution:**

    * Reduce batch size (max 2000 events)
    * Use gzip compression
    * Split into multiple requests
  </Accordion>
</AccordionGroup>
