---
title: "Aggregate analytics events over time"
method: POST
path: "/api/apps/{app_id}/analytics/timeseries"
---

# Aggregate analytics events over time

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

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

Aggregates the app's analytics events into time buckets, so you can chart them. Send the metrics you want per bucket, and Base44 returns them per bucket plus a total over the whole range.

The range defaults to the last 30 days. Events are kept for 60 days, so an older range returns nothing. `timestamp` bounds inside `q` override `start_time` and `end_time`.

Base44 buckets by one of a fixed set of intervals: 1, 2, 3, 4, 6, 8 and 12 hours, 1, 2 and 3 days, 1 and 2 weeks, and 30 days. One hour is the finest available. Omit `bucket_size_ms` to get the finest interval that keeps the bucket count within `max_buckets`. Pass it to choose an interval yourself: Base44 rounds it down to the nearest supported interval, and rounds it up to one hour when you ask for anything finer, so a sub-hour request comes back coarser than you asked. Read the interval it used off `bucket_interval` in the response rather than assuming your request was honored. Keep `bucket_size_ms` coarse enough that the range divides into no more than `max_buckets` buckets.

Buckets with no matching events are left out, so chart your own zero for the gaps. `count` and `count_unique` work on any field, while `sum`, `avg`, `min`, `max` and the percentiles read the field as a number and report `0` for a bucket whose values are all non-numeric.

## Path parameters

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

## Request body

- TimeseriesRequest — Request for time-bucketed event aggregation.
  - `event_name` string, nullable — Name of the event to aggregate. Omit to aggregate every event the app tracks.
  - `q` string, nullable — Filter expression, as a JSON object serialized to a string. Same syntax as [Query analytics events](/api-reference/query-analytics-events).
  - `start_time` string, date-time, nullable — Start of the time range. Defaults to 30 days ago.
  - `end_time` string, date-time, nullable — End of the time range. Defaults to now.
  - `bucket_size_ms` integer, nullable — Requested bucket size in milliseconds. Base44 rounds it down to the nearest supported interval, and up to one hour when you ask for anything finer than that. Omit to pick the finest interval that fits `max_buckets`.
  - `max_buckets` integer — Maximum number of buckets to return, between 10 and 1000. Drives the interval when `bucket_size_ms` is omitted.
  - `metrics` AggregationMetric[] — Between 1 and 10 metrics to compute per bucket. Defaults to an event count named `event_count` and a distinct-user count named `unique_users`.
    - `name` string, required — Name to report this metric under. It becomes a key in `metrics` and `totals` in the response.
    - `function` 'count' | 'count_unique' | 'sum' | 'avg' | 'min' | 'max' | 'p50' | 'p90' | 'p95' | 'p99', required — How to aggregate the field. `count` counts events, `count_unique` counts distinct values, and the rest compute over the field's numeric values.
    - `field` string, nullable — Field to aggregate. Required for every function except `count`. Top-level fields are `user_id`, `session_id`, `event_id`, `event_name`, and `page_url`. Prefix a key with `metadata.` for the device information Base44 captures itself: `metadata.device_type`, `metadata.os`, and `metadata.country`. Any other name reads as an event property, so `amount` and `properties.amount` mean the same thing.

## Response `200`

The bucketed metrics.

- TimeseriesResponse — Response for time-bucketed event aggregation.
  - `event_name` string, nullable — The event name that was aggregated, or `null` when the request covered every event.
  - `bucket_interval` integer, required — Interval Base44 bucketed by, in milliseconds.
  - `bucket_count` integer, required — Number of buckets returned.
  - `totals` object — Each metric computed over the whole range at once, keyed by metric name. Not the sum of the buckets: `count_unique` counts distinct values across the range.
  - `buckets` TimeBucket[] — The buckets, oldest first. Buckets with no matching events are omitted rather than reported as zero.
    - `bucket` string, required — Start of the bucket. A date-time for intervals under a day, and a date for intervals of a day or longer.
    - `metrics` object — The requested metrics for this bucket, keyed by the `name` you gave each one.

## Other responses

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

## Changes

- **2026-08-25** `8dfd9c46c0b9` — 1 info
  - endpoint added

[Change history](https://skmtc.dev/idealspot/apis/base44-app-management-api/changes/api/apps/:app_id/analytics/timeseries/post.md)

---

[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)
