---
title: "Query analytics events"
method: POST
path: "/api/apps/{app_id}/analytics/query"
---

# Query analytics events

`POST /api/apps/{app_id}/analytics/query`

<Info>This API is in beta. Endpoints, fields, and behavior may still change, so avoid depending on it in production.</Info>

Returns the app's individual analytics events for one event name, newest first, with the properties the app sent on each one.

The time range defaults to the last 7 days. To use a different range, put `timestamp` bounds in the `q` filter, for example `{"timestamp": {"gte": "2026-08-01T00:00:00Z", "lt": "2026-08-08T00:00:00Z"}}`. Base44 applies the bounds as `timestamp >= start` and `timestamp < end`, so `gt` behaves like `gte` and `lte` behaves like `lt`. Events are kept for 60 days, so an older range returns nothing.

Page through the results with `limit` and `offset`. When `has_more` is `true`, send the returned `next_offset` as the next request's `offset`. `total` counts every matching event, not just the ones on this page.

`q` is a JSON object serialized to a string. Each key is a field, and its value is either a literal to match for equality or an object of operators, as in `{"user_id": "6891ab34d2f07e5c1b9a2d48", "properties.amount": {"gte": 50}}`. The comparison operators are `eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `in`, `nin`, and `regex`. Combine expressions with `and` or `or`, each taking an array, and negate one with `not`.

`event_id`, `event_name`, `timestamp`, `user_id`, `session_id`, and `page_url` are top-level fields. Every other key reads as an event property, so `plan` and `properties.plan` mean the same thing. Get the available property keys from [List analytics event properties](/api-reference/list-analytics-event-properties). Prefix a key with `metadata.` to filter on the device information Base44 captures itself: `metadata.device_type`, `metadata.os`, and `metadata.country`.

<Warning>`regex` matches a substring, not a regular expression. `{"page_url": {"regex": "/checkout"}}` matches any URL containing `/checkout`, and regular expression syntax such as `^` or `.*` matches literally. Add `"options": "i"` next to it for a case-insensitive match.</Warning>

<Warning>The response includes fields beyond the ones documented here. Don't use any undocumented fields, as they can change at any time.</Warning>

## Path parameters

- `app_id` string, required — ID of the app whose analytics to read.

## Request body

- QueryEventsRequest — Query request for analytics events with filter expression support.
  - `event_name` string, required — Name of the event to query, exactly as the app tracked it.
  - `q` string, nullable — Filter expression, as a JSON object serialized to a string. Omit to return every event with this name in the time range.
  - `offset` integer — Number of events to skip before the page starts. Pass the `next_offset` from the previous response to get the next page.
  - `limit` integer — Maximum number of events to return, between 1 and 1000.

## Response `200`

The matching events.

- AnalyticsEventPage
  - `total` integer, required — Number of events matching the query, across all pages.
  - `events` AnalyticsEvent[], required — The requested page of events, newest first.
    - `event_id` string, required — ID of the event.
    - `event_name` string, required — Name of the event.
    - `timestamp` string, date-time, required — Time the event occurred, as reported by the app.
    - `user_id` string, nullable — ID of the app user who triggered the event, or `null` if it was not attributed to one.
    - `session_id` string, nullable — Session the event belongs to, or `null` if the app sent none.
    - `page_url` string, nullable — URL of the page the event happened on, or `null` if the app sent none.
    - `properties` object, required — The custom properties the app sent with this event, or `{}` if it sent none. Keys and value types are whatever the app tracks.
    - `metadata` AnalyticsEventMetadata, required
      - `device_type` 'desktop' | 'mobile' | 'tablet', nullable — Device the event came from, derived from the request's user agent, or `null` when the app sent no user agent.
      - `os` string, nullable — Operating system the event came from, or `null` when it could not be derived.
      - `country` string, nullable — Two-letter country code the event came from. `null` when the request reached Base44 without a country header, `XX` when the country is unknown, and `T1` for traffic over Tor.
  - `has_more` boolean, required — Whether more events match beyond this page.
  - `next_offset` integer, nullable — Offset to pass as `offset` to get the next page, or `null` when `has_more` is `false`.

## Other responses

- `401` — Missing or invalid credentials.
- `403` — You don't have access to this app.
- `404` — App not found.
- `422` — Validation Error

---

[API](https://skmtc.dev/idealspot/apis/base44-app-management-api.md) · [All operations](https://skmtc.dev/idealspot/apis/base44-app-management-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/idealspot/base44-app-management-api/revisions/31ef75eb64ab/schema)
