Skip to main content
The RUM API takes the events of browser and mobile clients and reads them back. All endpoints use the /api/v1/rum prefix and require a bearer token.
Writing events and replay segments requires rum.write; an application-bound client token holds exactly this permission for one application. Reading requires streams.query. A platform caller can use sys.telemetry.read in the protected _sys scope. Creating, changing, and deleting an application requires api_tokens.manage, and setting the state, the team, or the person of an issue requires rum.manage. A type names the kind of row an endpoint works on: sessions, views, actions, errors, resources, long_tasks, or vitals. Each type is the stream of the same name with the rum_ prefix removed.

Endpoints

GET /api/v1/auth/tokens/rum returns the client token of an application.

Send a replay segment

session_id, seq, and events are required. env, service, and version may be sent too, as the SDK was set up with them: they tell the retention filters of the application what the session is like, so that a segment of a session that is not kept is not stored. No other field is accepted. events are rrweb events. A client token writes to its own application: application can be left out, and a different value answers 403. Any other credential names the application. An application that does not exist answers 404. The answer describes the stored segment: its id, seq, event_count, and has_full_snapshot. GET /api/v1/rum/replay/{session_id} returns session_id, segment_count, and events, the events of all the segments of the session in order.

Manage applications

An application has an id, a name, a platform, and settings:
POST answers the new application. An identifier or a name that exists answers 409. PATCH takes any of name, platform, and settings. DELETE answers { "deleted": true }. The events the application already sent stay in the streams until their retention ends them.

Search rows

POST takes the same names in a JSON body and suits queries too long for an address. In an address, filters, free_text, and columns are JSON-encoded lists. A filter has a field, an op, and a value. At most 32 filters, and a value of at most 512 characters. A field that the type does not have, or an operator the field cannot answer, fails the request with 400. The answer holds the rows of one page, newest first:
A row has timestamp_micros and the columns asked for. A JSON column holds the document. Views and sessions appear once, in their latest version.

Count and describe rows

facets takes the parameters of search without paging and adds field (required) and limit (from 1 to 100, default 10). It answers the most common values of the field across the matching rows:
A count that takes too long or finds the system busy answers an empty list with unavailable set to time_budget or busy. A field that holds a JSON document answers 400. histogram takes the same selection and the bars to count into: bucket_micros (at least 1000) and origin_micros, the start of the first bar, which is from when left out and cannot be after it. A range holds at most 512 bars. Each bucket is { start_micros, total, errors }. errors counts the rows that went wrong: sessions and views with errors, actions with frustration, and requests with a status of 400 or more, or 0. split is false for the types that have no such rows. GET /api/v1/rum/schema/{type} lists the columns the other endpoints take and answer with:
data_type is bool, int64, float64, utf8, or json. unit is ns, ms, bytes, count, score, percent, per_second, px, or none: durations are stored in the nanoseconds the SDK sent, and a client formats them. A facetable field can be counted by value, an indexed field filters without reading every row, and id_field names the column that tells one row from another.

Measure rows

aggregate takes the selection of search and measures across every matching row. It answers the numbers behind charts, tables, and maps: how many sessions, the 75th percentile of a vital, per page or per hour.
A measure has an fn and a field, and may have a name, a where, and a fallback. where is a list of filters, as in search, and the measure takes only the rows that meet them: {"fn":"count","where":[{"field":"session.error.count","op":"=","value":"0"}]} counts the sessions without errors. A measure is called by its name, else fn(field), else fn when it has no field, and two measures cannot have the same name. A field that the type does not have, or a number asked of a field that is not one, fails the request with 400.
A row has the group it is of, in the order of group_by, and the values of the measures, in their order. Over time it also has start_micros, where its bar begins. A group whose rows have no value is null, and so is a percentile of no values. unit is count, or the unit of the field as schema gives it. Views and sessions are counted once, in their latest version. Where no row matches, an answer with groups or bars has no rows, and one with neither has one row: counts are 0 and the other measures null. A value the reader may not see comes back as the text it is masked to. A count that takes too long or finds the system busy answers no rows, with unavailable set to time_budget or busy.

Funnels, paths, and retention

The three endpoints under /api/v1/rum/analytics answer the questions of RUM analytics. Each takes the selection of search that applies to sessions, views, and actions: from and to in microseconds, and filters, what every row has to meet, usually the application (application.id) and the environment (env). With GET, the lists are JSON in their parameters, so a question is a link; POST takes the same names in a JSON body. They need streams.query, or sys.telemetry.read in the protected _sys scope. A count that takes too long or finds the system busy answers no figures, with unavailable set to time_budget or busy. The answers carry the from and to they are of.

Funnel

A session counts for the first step by its first row that meets it, and for each step after by its first row that meets it later than the row of the step before, in the same session.
A group is the funnel of the sessions that have one value of the breakdown, in the order of their sessions at the first step, and value is null for all of them together, or for the sessions whose row has no value. conversion is the share of the sessions of the first step, from_previous the share of the sessions of the step before, and median_ms the middle of the times since the step before; each is null where it has no meaning. A field of a type that is not text, or that the type does not have, fails the request with 400.

Paths

The pages are in columns, one more than depth, the page the paths are of being column 0 (the last column going back). A node is a page of a column with the sessions that were there and the ends that went no further (that began there, going back). A link goes from a page of column to a page of the next column (the one after in time, also going back) with the sessions that went that way. Pages are taken in the order they were opened, one page opened again at once counting once. A column names the 8 pages with the most sessions, and the rest are __other__. sessions is the number of sessions that have the page the paths are of.

Retention

A cohort is the people first seen in the period that begins at start_micros, in the time range asked for. A person is the usr.id of a session, or where it has none its usr.anonymous_id. returned has, for each period after, how many of the cohort were seen then; it is null for a period that has not ended by to.

Playlists

A playlist is a named list of the sessions of one application, each with the moment worth opening it at.
GET /api/v1/rum/playlists answers the playlists without sessions, the one changed last first, and takes application to narrow to one. Reading requires streams.query, and a platform caller can use sys.telemetry.read. The others change a playlist and require rum.manage; every one of them answers the playlist with its sessions, except DELETE, which answers { "deleted": true }. A session in a request is { "session_id": "...", "at_micros": 1790000005000000 }: the id is 1 to 128 characters, and at_micros, when given, is a moment after the epoch in microseconds that the session opens at; without it, the session opens at its beginning. The playlist holds ids, not sessions: it does not check that a session exists, and a session whose rows have been deleted by retention stays in the list. GET /api/v1/rum/sessions/{id}/playlists answers the playlists, without their sessions, that hold a session.

Read one row, one session

GET /api/v1/rum/{type}/{id} answers one row with all its columns, or 404. from and to narrow where to look; without them the lookup covers the last 30 days. {id} is the value of the id_field of the type. GET /api/v1/rum/sessions/{id}/timeline answers: GET /api/v1/rum/sessions/{id}/related-traces lists the backend traces of a session. It names the traces whose ID a request of the session carried (relation: direct), and when there are none, the traces that ran while the session did (relation: time-correlated). Each trace has its trace_id, service, span_count, duration_ms, and started_at_micros, and the answer has the primary_service. GET /api/v1/rum/traces/{trace_id}/session goes the other way and answers the session, or null.

Issues

Errors that are alike are grouped into issues, and every error row carries the id of its issue in error.issue_id. The numbers of an issue are counted from its errors in the range asked for. Its state and its history are kept apart. Times are microseconds since the Unix epoch.
regressed_environment is the environment of the error that brought the issue back, and null when that error names none. An issue belongs to the whole application, whatever environment its errors are in. The server also keeps the first time each environment saw it, which is what alert rules count to tell the new issues of an environment. The list reads the 250 issues with the most sessions (or users, or occurrences, by sort) and narrows them by status, assignee, team, search, and fresh. total is how many issues the filters leave, before limit cuts the list. trend holds the occurrences in each of up to 12 equal parts of the range, oldest first. overflow marks the issue that counts the errors of an application past the issues it may open in an hour. A count that takes too long or finds the system busy answers no issues, with unavailable set to time_budget or busy. GET /api/v1/rum/issues/{id} answers the issue as the list has it, without trend, with sessions, users, and occurrences counted over from and to, and two more fields: An issue that does not exist answers 404. PATCH /api/v1/rum/issues/{id} takes any of status, assignee_id, and team_id, and answers the issue after the change.
status is open, investigating, resolved, or ignored. regressed is set by the rules when a resolved issue is seen again in a newer version, and answers 400. assignee_id has to be a member of the organization and team_id a team of it; null or an empty text takes the person or the team off. A field left out stays. Resolving records resolved_at, resolved_by, and the newest version of the application as resolved_version, and any new state ends the record of an earlier resolving or regression. A request that names no field to change answers 400; one that sets what is already set answers 200 and changes nothing. Each change is written to the audit log as rum.issue.update.

Preview an alert rule

Reads what an alert rule on a RUM figure would have seen over the last stretch of time, one window at a time, by the code that evaluates the rule. It requires streams.query.
unit is count, percent, milliseconds, or score. A point has the start of its window in at, the figure in value, and the rows the figure is made of in samples; a window that holds fewer rows than min_samples has neither. current is the last point, the window that ends at to. A count that takes too long or finds the system busy answers no points, with unavailable set to time_budget or busy. An application that does not exist answers 404, and a rule that does not fit its figure answers 400.

Errors

Last modified on October 26, 2026