Analytics
Nine support and cost numbers over one date range, and the explorer for any other question.
Every role can open Analytics, cost tiles included. The explorer’s Activity log dataset needs an owner or admin. See Roles.
Pick a range
The menu at the top right sets one range for every tile and chart on the page.
| Option | Covers |
|---|---|
| Last 7 days | Today and the 6 days before it |
| Last 30 days | Today and the 29 days before it. The page opens on this range. |
| Last 90 days | Today and the 89 days before it |
- The range starts at midnight on your device’s clock. Each day ends at your midnight.
- Today counts while it is still going. Chart tooltips call it Today so far.
- The header spells out the dates, like “Aug 28 to Sep 26”.
The tiles
Nine tiles sit in a grid. Press one to draw it as the large chart under the grid. The page opens on Conversations.
Resolved by agent and Satisfaction draw a row of pills filled to their share. The other seven tiles draw a sparkline of their days. Press the table icon at the top right of the chart to see the same numbers as rows, one per day.
| Tile | Number on the tile | Chart series | What counts |
|---|---|---|---|
| Conversations | Conversations started | Widget, Email, Discord | Every conversation started in the range, by the channel it came in on |
| Resolved by agent | Share finished by the agent | By agent, By team | Finished means Resolved or Closed. By agent means the agent still held the conversation when it was finished. Open conversations count toward the whole, so the share rises as they close. Each conversation sits on the day it started. |
| Handoffs | Conversations handed to the team | Handed off | The agent asked for a person, or a teammate took over. A conversation handed back to the agent still counts. |
| Satisfaction | Average stars, out of 5 | 4 or 5 stars, 3 stars, 1 or 2 stars | Ratings left in the range, on the day they were left. The rating card is on Conversations. |
| Time to resolve | Median time from the first message to the last | Median, 95th percentile | Finished conversations that started in the range. A day with nothing finished leaves a gap in the line. The tooltip shows how many finished that day. |
| Signals | Bugs and suggestions filed | Bugs, Suggestions | Signals created in the range, on the day they were filed |
| Credits used | Credits charged, in dollars | AI, Email, Page scraping | What was charged. Work that was not charged counts as zero. 1 credit is $1. |
| AI requests | Model calls | Automatic, By the team | Automatic is work nobody pressed a button for, like replies, triage and indexing. By the team is work a teammate started, like the assistant and explorer questions. The tooltip shows the day’s tokens. |
| Cost per message | Average credits charged per message the agent wrote | Average | Credits charged for the agent’s messages, divided by how many it wrote, even ones charged $0. A message counts once, however many bubbles and model calls it took. Work a conversation sets off later, like learning from it once it is resolved, is left out. A day with no messages leaves a gap in the line. The tooltip shows how many messages the day covers. |
Plans, prices and what a credit buys are on Billing.
Caps
Each tile reads a limited number of rows per range.
| Tiles | Reads at most | Named in the header as |
|---|---|---|
| Conversations, Resolved by agent, Handoffs, Time to resolve | 2,000 conversations, newest first | the latest 2,000 conversations |
| Satisfaction | 2,000 ratings, newest first | the latest 2,000 ratings |
| Signals | 1,000 signals across the organization. Planned, Open and the other live statuses are read before Done and Declined | 1,000 signals, open ones first |
| Credits used, AI requests, Cost per message | 5,000 usage events, newest first | the latest 5,000 usage events |
Past a cap, the oldest days lose rows first. The header names every cap the range hit, like “counting the latest 2,000 conversations and the latest 2,000 ratings”. The note is hidden on narrow screens.
Explore
The explorer answers one question at a time over anything the workspace records. It opens as a dialog.
| Opened from | Starts on |
|---|---|
| Explore on Analytics | Conversations counted per day, over the page’s range |
| Explore on Logs | Activity log counted per day and split by outcome, over every day the log range touches. A range longer than 366 days opens on All time. |
The range menu in the dialog offers Today, Last 7 days, Last 30 days, Last 90 days and All time. From Logs, the handed-over dates lead the menu. Each time the dialog opens it takes the page’s range again. The query stays until you leave the page.
Ask in words
Type into Ask a question about your data and press Enter or the arrow button. Three sample questions sit under the box until you ask one. Press a sample to ask it.
| Opened from | Samples |
|---|---|
| Analytics | “Handoffs by channel, per week”, “Busiest hours, by day of the week”, “Credits used by feature” |
| Logs | “Failed events by area”, “Credits used by AI feature, per day”, “Slowest tools” |
- Questions take up to 500 characters.
- While it works, the chart area reads Reading the question, Choosing the data, then Writing the query.
- The answer fills the query column, picks a chart and names it. A line under the box says what it did.
- A question that names a range, like “last week”, sets the range menu to the nearest preset.
- A follow-up changes the query on screen instead of starting over, like “now split it by channel” or “only email”.
- Edit any step afterward. The chart updates live.
- Asking needs Standard or Pro. See Plans. On the Explore plan the box is disabled and reads “Available on Standard and Pro.” Owners and admins get a View plans link. Members see “Ask an owner or admin to upgrade.” Building a query by hand works on every plan.
- Each question is charged as AI usage. It shows in Logs as an Analytics question.
| Message | Cause |
|---|---|
| Ask something first. | The box was empty |
| The model did not answer. Try again. | The model call failed |
| That did not come back as a query. Try asking another way. | The answer could not be read as a query |
Build a query
The query is a row of pills under the ask box, read left to right. A pill shows its setting’s name and value. Press it to change the value. Pills for a setting that does not apply yet, like the field to measure beside Count, stay hidden. On a phone the row scrolls sideways.
| Pill | Choices |
|---|---|
| Dataset | The dataset. Changing it resets Measure to Count, clears filters and Split by, and sets Date to the dataset’s first date. The time axis stays. |
| Measure | Count, Distinct, Total, Average, Median, the 75th, 90th, 95th and 99th percentile, Lowest, Highest, Percent where. Percent where adds a Where pill for its condition. The others except Count add an Of pill for the field to measure. |
| Split by | Plain until set, then a field to draw one series per value. Setting it adds a pill like “Top 8” whose menu holds Show (3 to 20, 8 by default), Order (Default order, Largest first, Smallest first) and The rest (Show as Other or Hide). |
| Time axis | One total, Per day, Per week, Per month, By hour of day, By day of week. With All time only the last two are offered. |
| Date | Which date places a row, for datasets with more than one, like a conversation’s Started or Last message |
| Compare | Plain until set to Previous period, the same number of days just before the range. Hidden with All time. |
| Filter | Pick a field, then a comparison and a value. Up to 8 filters. They show as chips on a row under the pills. Typed values take up to 200 characters. |
The chart takes the full width under the query and grows to fill the dialog’s height.
| Measure | Works on |
|---|---|
| Count | Rows. Needs no field. |
| Distinct | Text, choice and id fields, like Customer |
| Total, Average, Median, the percentiles, Lowest, Highest | Number and duration fields |
| Percent where | A condition, picked like a filter. The share of the matched rows that meet it, from 0 to 100%. The handoff rate is Conversations, Percent where Handed off. It starts on the dataset’s first yes-or-no field. |
Filter comparisons are is, is not, is any of, is none of, is more than, is at least, is less than, is at most, contains, does not contain, is set and is not set. Each field offers the ones that fit it.
- A field with named values, like Channel, lists them with checkboxes. Tick one or more, pick is or is not, then Apply. Two or more read as is any of or is none of.
- For typed values, is any of and is none of take a list split by commas.
- Duration filters take minutes. Over the API they take milliseconds.
- Between two filters sits and. Press it to switch every join to or, so a row needs to pass only one filter. Press or to switch back.
- Hours and weekdays follow your device’s clock.
With Largest first or Smallest first, groups rank by what they measure, and the ranking decides which keep their names. Top 5 with Largest first on Conversations split by Page shows the five busiest pages. Other takes one of the places. Hide leaves the other groups off the chart, and the headline covers only the groups shown.
Previous period puts a line beside the headline number, like “12% vs previous period”, with an arrow for the way it moved. Hover it for the earlier number. Table and Download CSV gain a Previous period column when the chart has no axis.
Datasets
Every dataset also has Hour of day and Day of week.
| Data | Rows | Dates | Reads at most |
|---|---|---|---|
| Conversations | Support threads from every channel. Fields include Channel, Status, Outcome, Handed off, Sentiment, Agent’s work, Assignee, Page, Referrer and Time open. | Started, Last message | 2,000 |
| Messages | Every message in a conversation, from the customer, the agent, the team, internal notes and system lines. Fields include From, Channel, Used tools, Failed, Attachments and Length. | Sent | 5,000 messages from up to 400 conversations active in the range, 200 per conversation |
| Ratings | Stars customers left. Fields include Stars, Rating band and Left a comment. | Rated | 2,000 |
| Signals | Bugs and suggestions. Fields include Kind, Status, Priority, Reporters, Issue tracker and Merged duplicates. | Filed, Updated | 1,000 |
| Activity log | Entries from Logs. Owners and admins only. Fields include Area, Event, Done by, Outcome, AI feature, Tool, Duration, Credits used, Tokens and HTTP status. Area and Done by use the names the Logs filters use. | Logged | 5,000 |
| Knowledge documents | Documents the agent knows. Fields include Source, Status, Public link, In a folder and Length. | Added, Updated | 1,000 |
| Knowledge suggestions | Pages the agent suggested. Fields include Status, Edits a page, Reviewed by and Time to review. | Suggested, Reviewed | 1,000 |
| Tool requests | Tools the agent asked for. Fields include Status, Risk, Reviewed by and Inputs. | Requested, Reviewed | 500 |
| Tool runs | Every custom tool call. Fields include Tool, Status, Started by, Waited on, Reviewer verdict and Time to settle. | Started, Settled | 1,000 |
| Customers | People who wrote in. Fields include Signed in, Device, Browser, Operating system, Language, Time zone, Company and Email domain. | First seen, Last seen | 2,000 |
| Tasks | Cards from the Tasks API. Fields include Status, Priority, Assigned, From a signal, Issue tracker and Time to done. | Created, Done, Updated | 1,000 |
| Usage | Metered AI, email and page scraping, with what each cost. Fields include Service, Feature, Started by, Paid from, Credits charged and token counts. | Occurred | 5,000 |
When a query stops at its cap, a note under the chart reads like “Counting the latest 5,000 usage events”. Members do not see Activity log in the menu. A query for it from a member returns “Only admins and owners can view audit logs.”
Chart kinds
The row of chart icons sits beside the headline number. A kind that does not fit the query stays dimmed and says why on hover.
| Kind | Needs |
|---|---|
| Columns | An axis or a split. The default for counts and totals over time. |
| Line, Area | An axis. Line is the default for other measures over time. |
| Bars | A split and no axis. The default for a split with no axis. |
| Donut | A split, no axis, and Count, Distinct or Total |
| Heatmap | An axis and a split |
| Number | Nothing. The default for one total. |
| Table | Nothing |
Records and CSV
Chart and Records switch the result.
- Records lists the rows the query matched. Filters, date and range apply. Measure, split and axis do not.
- The menu over the list sorts it: Newest first, Oldest first, or any number field highest or lowest first, like Duration, highest first for the slowest tool runs. Rows with no value sort last. A sorted field shows first on each row.
- It loads 50 rows. Show more adds 50, up to 200. The footer reads like “Latest 50 of 1,240 conversations”, or “First 50” when sorted another way.
- A row opens its page in the app and closes the dialog. Tasks and Usage rows have no page to open.
- Download CSV saves the numbers behind the chart, the same rows Table shows. The file is named after the chart’s title. Log entries themselves export from Logs.
Over the API, CLI and MCP
The same numbers are on the management API. The API returns more than the page draws, like conversations by hour, top pages, sentiment and the knowledge base’s shape.
| Endpoint | Returns |
|---|---|
GET /v1/analytics/overview |
The headline numbers on the Dashboard |
GET /v1/analytics/conversations, /satisfaction, /signals, /knowledge, /billing |
One day per bucket. days is 7, 30 or 90, default 30. from defaults to exactly days ago, so pass your own midnight to match the page. |
GET /v1/analytics/activity |
Log entries per day. Owners and admins. |
POST /v1/analytics/explore |
One explorer query. days is a whole number from 1 to 366, default 30, counted back from today in UTC. Anything else returns invalid_request. from moves the start. |
POST /v1/analytics/records |
The rows a query matched. days and from work as for explore. limit is 1 to 200, default 50. sort is { "by": "time" or a field id, "direction": "desc" or "asc" }. fields lists the field ids each row reads out. |
A query takes the same steps as the builder:
| Key | Takes |
|---|---|
measure |
{ "op", "field" }. op is count, distinct, sum, avg, median, p75, p90, p95, p99, min, max or percent. percent takes where, one filter, instead of field. |
filters |
{ "field", "op", "value" } each. op is is, isNot, in, notIn, gt, gte, lt, lte, contains, notContains, isSet or isNotSet. in and notIn take a list of up to 50 values. |
match |
all (default) or any |
groupBy |
A field id, or null |
top, order, other |
1 to 20 (default 8); natural (default), largest or smallest; true (default) folds the rest into __other, false leaves them off |
bucket |
day, week, month, hour, weekday, or null |
when |
{ "field", "scope" }, scope range (default) or all |
compare |
true adds previous: the same measure over the days just before the window, one value per group. Ignored with scope all. |
Money in /billing is in microcredits, 1,000,000 to the dollar.
median analytics explore --days 90 \
--query '{"dataset":"conversations","measure":{"op":"count"},"groupBy":"channel","bucket":"week"}'
# The handoff rate by channel, against the 30 days before
median analytics explore --days 30 \
--query '{"dataset":"conversations","measure":{"op":"percent","where":{"field":"handedOff","op":"is","value":true}},"groupBy":"channel","compare":true}'curl https://api.median.sh/v1/analytics/explore \
-H "Authorization: Bearer $MEDIAN_KEY" \
-H "content-type: application/json" \
-d '{"days":90,"query":{"dataset":"conversations","measure":{"op":"count"},"groupBy":"channel","bucket":"week"}}'return await median.analytics.explore({
days: 90,
query: { dataset: "conversations", measure: { op: "count" }, groupBy: "channel", bucket: "week" },
});Queries take field ids rather than labels, like channel for Channel. median_docs with topic analytics lists every dataset’s field ids. Every command and flag is in the CLI reference. The MCP server is on MCP.