Skip to content
datasquares.aiSign inStart free

Metrics & Governance

Governed metrics

A governed metric binds a SquareX expression to a data model, or one aggregate to a saved query, with a grain, an optional target and an owner: one agreed definition of a number your team reports, such as monthly revenue. Where a measure lives inside one model, a metric is a workspace-level object: certifiable, versioned, and read by KPI cards, alerts, digests, exports, the Slack command and the AI chat.

The Metrics page: each metric with its number for its latest whole period, the change from the period before, a small trend and whether it meets its target, with search and filters above the list.

A metric has one number, and every place that shows the metric shows that one: its latest whole period at its grain that has settled, in the workspace’s time zone. It is named by its period (13 Oct, Week of 5 Oct, September 2026, Q3 2026, 2025) and compared with the period before (+3% vs previous month); a target, if set, is compared with it.

  • Whole. A period counts once it has ended. The period in progress is never the number, and rows dated after today never count in it.
  • Settled. The latest whole period counts once the period after it has data or has ended: a daily metric shows yesterday once today’s first rows arrive, and the day before until then, so a source synced every few hours never shows a part-loaded yesterday as a drop. The data in the period after is the source’s, whatever the metric’s own bounds on its time dimension, so a monthly metric filtered to Last month shows last month.
  • Stopped data. A metric whose data has stopped shows its last period once the period after it has ended: a monthly metric whose data stopped in July shows June through August, and July from 1 September.
  • The workspace’s time zone. Today, and the days every period starts and ends on, are the workspace’s: Admin → Settings → Default Timezone (UTC until one is set). At 02:00 on 1 December in a workspace set to Asia/Kolkata, November has ended and is a whole month, although in UTC it is still running. On a date-and-time field, some sources can’t cut a period there: see A date-and-time field’s periods.
  • No time dimension. A metric without one has no periods: its number is all of its data so far, named All data.
  • No whole period yet. A new metric whose first whole period has not settled shows that period, saying it may still change (not all of its data has arrived), since there is no earlier period to compare it with. One with no whole period of data at all names the latest whole period of its grain and shows no value (a dash). When the period before has no data or is zero, no change is shown.

Why it may still move. A whole period’s figure can still change, and then it says May still change: and why:

It says Because
the books are still open the metric’s Books close on day has not come yet
late figures can still arrive its Settlement lag (days) has not passed
not all of its data has arrived its source’s data is not in through the period’s end, or the period is a new metric’s first, waiting on the period after it
it isn’t known whether all of its data has arrived its source has never loaded: a Warehouse dataset never refreshed, or a staged source never synced

Data through says when its data is complete to: a Warehouse dataset’s last refresh, a staged source’s last sync, or, on a live database, the moment the number was read. See When a period is complete.

Where it is the number. The Metrics page and a metric’s drawer, a KPI card bound to the metric (on a dashboard, a shared link and an embed), an export’s KPI tile, the Slack command, digests, metric alerts that compare its latest whole period (every new one), the anomaly sweep, what moved, and the AI chat. A deck’s or a story’s figure shows the period its binding names (Bind numbers). All of a timed metric’s data is read only when it is asked for: by an alert set to compare All of its data, by the API’s include: ["allTime"], or by a question to the AI for an all-time total.

The Metrics page (Your team’s agreed numbers. Every dashboard, deck and alert uses the same definition.) lists the workspace’s metrics, 25 at a time (Show more). Each row has:

  • Name: a star to Follow the metric, its name, which opens its drawer, ✓ Certified (its tooltip says who certified it), its domain, and its description.
  • Latest value: its number in the metric’s own format, / target when it has one, a small trend up to that period and a refresh control. Under it: the period, the change (green or red only once Better when says which way is good), and Meets target or Misses target, in words with an icon, never by colour alone; and, when they apply, May still change: … and Data through ….
  • Owner: its owner, No owner, or A former member.
  • Definition: its formula (a ratio as its two parts) and what it reads, such as Data model · Sales or Saved query · Orders by day; a saved query’s name is shown only to people who can read saved queries.

The numbers come with the page, read for all of its rows in one request, as you: a metric on a data model through the governed query pipeline, with your row-level security applied; one on a saved query from its query (see A metric on a saved query). A number that can’t be read says why in its place (Couldn’t read this metric right now., or the refusal’s own words), with a control to read it again. A metric that reads neither a data model nor a saved query shows a dash.

Above the list are Search metrics (Search by name or description), Certified or not (Certified, Not certified), All domains (once a metric has a domain), Any owner, All data models, and the order: Name (A to Z), Last changed or Certified first. Clear filters shows them all again. A search that matches nothing says No metrics match. Clear the search and filters to see them all before you add one, so a number isn’t defined twice.

Hover or focus a row for Explain this change (on a metric with a data model and a time dimension), Certify or Uncertify (for those who may certify, see Certification), Export, Edit and Delete (see Deleting and restoring a metric). New metric opens its start page, and Import brings in a definition from another workspace (Lifecycle): it is part of Enterprise and shows to roles that may create metrics.

Follow, the star, adds a metric to the ones you follow, kept with your favorites. They come first in what moved (on the Android app’s Home, Since you last looked) and in the metrics the AI chat starts from, and the anomaly sweep tells you when a certified one you follow moves unusually.

The list tells a failure from an empty workspace. If metrics cannot be loaded, it says We couldn’t load your metrics. Try again. with Try again, and never shows the first-metric prompt, so a failed load does not lead to a duplicate. A workspace with none says No metrics yet. A metric is a number your team agrees on, such as monthly revenue: defined once, then every dashboard, deck and alert shows the same figure., with Create your first metric. When the list of domains can’t be read, the domain filter is hidden, and the page says so.

A metric’s name opens its drawer, and so does every link to it (/metrics?metric=<id>): a search hit (Ctrl+K), the Catalog, a glossary term, a notification, what a dataset feeds. It shows:

  • Its number, large, with target …, the period, the change, Meets target or Misses target, and May still change: … and Data through … when they apply.
  • Its trend, period by period up to its latest whole period, the one in progress left out so it never ends on a drop: the last 30 days of a daily metric, the last 13 weeks of a weekly one, this year’s months or quarters; a yearly metric has none. The pointer or the arrow keys pick a period, and Show the values lists them all.
  • Follow (Following once you do), Explain this change, and Ask about this metric, which opens the AI chat with the metric named in the message box, for you to finish and send (Asking opens the AI chat with this metric named. Answers use AI credits.). It shows to roles that may use AI chat.
  • What it is: its Formula, what it Reads, its Periods (By month, on orders.order_date, or No time dimension: its number is all of its data.), how it Adds up over time, its Filters and When a period is final.
  • Who stands behind it: its Owner, Domain, Certification (✓ Certified with by whom and when, or Not certified) and Version (Each change to what it computes is a new version.).
  • Delete, Export, Certify or Uncertify, and Edit, as on its row.

A link to a metric that was deleted, or that you may not open, says This metric isn’t available. It may have been deleted, or you may not have access to it.

An example: monthly revenue with a target.

  1. Open Metrics. A metric is one governed definition of a number, such as revenue, that every dashboard can reuse. Choose New metric.

    Open Metrics. A metric is one governed definition of a number, such as revenue, that every dashboard can reuse. Choose New metric.
  2. Give the metric a name, choose the data model it reads from, and set its grain (the time step it is reported at). You can also set a target, the owner, and whether higher or lower is better.

    Give the metric a name, choose the data model it reads from, and set its grain (the time step it is reported at). You can also set a target, the owner, and whether higher or lower is better.
  3. Write the expression in SquareX. DataSquares checks it against the model as you type and shows the result type when it is valid.

    Write the expression in SquareX. DataSquares checks it against the model as you type and shows the result type when it is valid.
  4. The metric appears in the list. Evaluate shows its value for its latest whole month, its grain, with the change from the month before. Use the row actions to edit it, certify it, or ask why it moved.

    The metric appears in the list. Evaluate shows its value for its latest whole month, its grain, with the change from the month before. Use the row actions to edit it, certify it, or ask why it moved.

The Metrics page shows each metric’s number for its latest whole period, named, with the change from the period before and its trend; a metric’s name opens it.

  1. Choose Metrics in the sidebar. Each metric is defined once, so every dashboard, digest and export reports the same number. The list shows each metric with its expression and grain.

    Choose Metrics in the sidebar. Each metric is defined once, so every dashboard, digest and export reports the same number. The list shows each metric with its expression and grain.
  2. Choose Evaluate on a metric to see its value for its latest whole period, such as last week or last month, named, with the change from the period before; a target is compared with that value. Explain this change shows which members drove its latest change, by statistics that use no AI credits; Explain with AI adds a one-line summary and uses AI credits.

    Choose Evaluate on a metric to see its value for its latest whole period, such as last week or last month, named, with the change from the period before; a target is compared with that value. Explain this change shows which members drove its latest change, by statistics that use no AI credits; Explain with AI adds a one-line summary and uses AI credits.

New metric opens a page of ways to start (A metric is a number your team agrees on, defined once: every dashboard, deck and alert then shows the same figure.):

Way What it does
Write the formula A SquareX formula on a data model, checked as you type. The blank way, first.
Describe it You say what it counts, and on your click the AI drafts the formula for you to check. Uses AI credits; for roles that may create measures on a data model.
From a model measure Makes a measure your data model already has into a governed metric: Start from a measure fills the formula ([Net revenue]), and the name, description and format when you have not set them.
From a saved query One total over a column of a saved query you can read: see A metric on a saved query.
Import a definition A metric exported from another workspace, on Enterprise: see Lifecycle.

Each of the first four opens the editor, and Create metric saves the new metric and opens it on the Metrics page with its number, the first check of what you made. A role that can read metrics but not make them sees Your role can read metrics here but not make them. A workspace admin can change that. Edit opens the same editor (Edit “…”), saved with Save changes. It has five sections.

What it computes

  • Name: how the metric appears everywhere, up to 160 characters.
  • Reads from: A data model (a SquareX formula) or A saved query (one aggregate over one of its columns). A metric keeps what it reads from: to read from the other, create a new metric.
  • Data model, then Formula (SquareX), checked against the model after a short pause (Checking the formula…, ✓ The formula is valid., or the error with its code) and again when you save, so an old result cannot approve text that has since changed.
  • Describe it, and let AI draft the formula opens Describe it: say what it counts (revenue from paid orders, without refunds) and choose Draft with AI. The draft is checked like a typed formula and waits beside yours until you replace your formula with it, insert it or discard it; nothing is saved until you create the metric. It uses AI credits.
  • Filters on the rows it counts (None: it reads every row its readers may see.). Add a filter takes a Field (on a saved query, a Column), how it Compares (is, is not, is one of, is none of, is more than, is at least, is less than, is at most, is between, contains, is empty, is not empty) and its Value, several separated by commas. Each reader’s own row-level security still applies on top. A filter set outside the editor that it can’t show (a relative date, one on a total) is kept as it is, and counted.

Its periods (How its number is read period by period: the card shows its latest whole period.)

  • Grain: Day, Week, Month (the default), Quarter or Year.
  • How it adds up: its Time dimension (the date field, or on a saved query the date column, its periods are read on), Adds up over time (see How a metric adds up), and This metric is a ratio, with its Numerator and Denominator.
  • When a period is final: Settlement lag (days) and Books close on day (see When a period is complete).

Its target

  • Target (optional): the goal its latest period is compared with. Emptied, the metric has no target.
  • Better when: Higher is better (revenue, signups) or Lower is better (cost, churn, incidents), when the target is a limit. Set it and the number shows as meeting or missing its target, and pace insights read the right way; left Not set, nothing is coloured.

How its number is written: Written as Automatic (as it comes, with up to two decimals), Number, Money (with its Currency, a three-letter code) or Percentage (a fraction: 0.312 is 31.2%); Decimals; Shorten large numbers (Automatic (1.2M), or in thousands, millions, billions, lakhs or crores); Digit grouping (1,234,567 or 12,34,567 (lakh and crore)); and, for a number, Text before and Text after. Shows as … previews it. The format writes the metric’s number on the Metrics page and in its drawer, on KPI cards, in Explain this change, in digests, in Slack, in the anomaly sweep’s notices and in the AI’s answers.

Who stands behind it: its Owner, one of the workspace’s active members (a new metric is yours unless you choose someone else, or No owner); its Domain, a grouping label such as Finance, up to 80 characters (both Business); and a Description of up to 2,000 characters. A saved metric with no description offers Describe with AI under it (see Describe with AI).

Editing a saved metric, Test its latest value reads its latest whole period past the cache, in the format and against the target in the editor; while what it computes has unsaved changes, it says This is the saved definition. Save to see your change. The editor lists its versions below.

Duplicates. While you define a metric, the editor names any other that already computes exactly the same, on the same data model or saved query with the same formula, grain and filters (Another metric already computes exactly this: … Use it rather than defining the number twice.), and those with names close to it (Similar names: … Check it isn’t one of these.). It warns, and never blocks: you may mean a second one.

Who may. Creating, editing and deleting a metric need the role’s Metrics create, edit and delete permissions, and the app shows New metric, Import, Edit and Delete only with them. Reading metrics needs the Metrics view permission: the Metrics page, a metric’s definition and versions, its number read on its own, digests and the AI chat’s metric tools. A KPI card’s number is read without it, by anyone who may open the card’s dashboard. A certified metric is changed only by its owner or a workspace admin (This metric is certified, so only its owner or a workspace admin can change it. Ask one of them to make the change.), and deleted only by them too. An API key also needs dashboard:read to read metrics and dashboard:write to create, edit, delete, import, write digests or set an owner, and its owner’s role must allow the same. Ownership can only be assigned to a current, active member of the workspace.

Metric names are unique within a workspace, whatever their case, and are kept trimmed with one space between words, so a name typed with a space before it is the same name as without one: a duplicate create or rename returns 409 Conflict. A name or description that hides text in invisible characters is refused.

A certified metric carries ✓ Certified wherever it is listed. The AI lists certified metrics first, the Slack command answers only certified ones, and the anomaly sweep watches only certified ones.

  • Who may certify: workspace admins, and people whose role holds the Certify metrics permission (Certify and un-certify governed metrics), which an admin can give a steward’s custom role in the role editor, under Administration (Users & roles). The workspace’s Admin role holds it. On the web, Certify and Uncertify show to all of them, on a metric’s row and in its drawer, and to no one else; through the API, PUT /api/certification/metric/{id} with { "certified": true }. Anyone else is refused: Only workspace admins, or people whose role may certify metrics, can certify a metric. Ask a workspace admin. An API key never certifies.
  • What it certifies: the metric’s current version. Through the API, a certification can carry a note of up to 500 characters (for board reporting), kept with it, and the metric records the version certified (certified_version).
  • When it clears: a new version clears it, and its note, except the version a measure’s rename writes, which changes no number. The audit log records why (definition changed, with both versions, or a change in what the metric reads), and the new version is certified again by someone who may. The editor says so before you save a certified metric (This metric is certified. Changing what it computes … makes a new version and clears its certification; an admin certifies the new version again.).

See also Catalog: certification.

What a metric computes is its definition: its data model or saved query, expression, time dimension, grain, filters, how it adds up, its ratio parts, its settlement lag and close day, and what it reads underneath (a saved query’s SQL and source, or the measures and calculated fields of its model that it names, and theirs in turn, and the column each field it reads is read from). Every save that changes the definition makes a new version of the metric, in the same save. A change to its name, description, owner, domain, target, thresholds, format or Better when makes no version, and neither does a save that sends the definition back as it is, in whatever spelling (SUM for Sum).

When what it reads changes. Editing a saved query’s SQL or source, or a measure or calculated field that a metric names, makes the next version of each metric that reads it, in the same save, though nobody edited the metric: its Versions list says What it reads changed (its saved query or a measure), its certification is cleared, and its owner is told in the app (Revenue changed: the saved query it reads was edited, It is now version 4, and its numbers may differ from before.). Pointing a field it reads at another column, and restoring its data model to an earlier version, do the same for each metric whose reads they change (Revenue changed: the field orders.amount it reads now reads another column, Revenue changed: its data model was restored to version 3); the model’s other metrics make no version. A certified number never changes under its badge.

Renaming a measure renames it in the metrics that name it: their formula and a ratio’s parts read [Net revenue] where they read [Revenue], in a new version made by the person who renamed it. A rename changes no number, so a certified metric stays certified, now of that version; changing the measure’s formula in the same save is a change like any other. A measure that a metric’s formula or a ratio’s part names can’t be deleted (This measure is used by the metric “Revenue”: change their expressions first.).

A field that a metric’s formula names can’t be renamed while it does (Renaming this field would break the metric that read it by its name (“Revenue”). Change their expressions first.), and a field a metric reads, in its formula, a ratio’s part, a filter or its time dimension, can’t be deleted.

The editor’s Versions list shows each version with who made it and when, what changed against the version before (Changed: expression, filters), and Certification cleared when it cleared one. Metrics that existed before versions began start at version 1, Recorded when versions began.

Every value the API returns names the version it was computed from and the SHA-256 of that definition, and a figure can be pinned to an earlier version, so it says exactly which definition it shows. A pinned version is computed with what it reads now: when its saved query, a measure or a field’s column has changed since that version was made, the figure is not shown as certified, its SHA-256 is of what was computed rather than of the version, and the API says dependenciesChanged: true.

Delete asks first, Delete “Revenue”?: It leaves the Metrics page, and a dashboard, deck, alert or digest that uses it can no longer show it. A metric that nothing uses is then deleted. A certified metric is deleted only by its owner or a workspace admin; anyone else is told This metric is certified, so only its owner or a workspace admin can delete it. Ask one of them to delete it.

While anything uses it, nothing is deleted. The dialog says “Revenue” is in use and lists what uses it: each thing you may open by its name, with a link, and the rest counted (2 dashboards). A dashboard card, a report, a story, a deck, a deck or story template, an alert, a digest, a verified answer, an activation and a glossary term each count; the anomaly sweep’s own record of a metric’s firings does not. To delete it anyway, type its name as it is written and choose Delete anyway (Keep it leaves it). Deleting a metric in use:

  • turns its alerts and activations off, each with the reason Its metric “Revenue” was deleted, so it was turned off. Restore the metric, then turn it back on.;
  • takes it out of its digests;
  • leaves what showed it without it: a KPI card on it says This card’s data can’t be found until it is restored.

Restore. After a delete in use, the toast offers Restore (“Revenue” deleted. You can restore it for 30 days.), and the Recovery Center lists a deleted metric too. Through the API, POST /api/metrics/{id}/restore restores a deleted metric within the workspace’s recovery window (30 days unless an admin changed it). It comes back with its own id, so its definition, versions, owner and certification return, and the cards, decks and stories that showed it read it again (“Revenue” is back, and everything that used it shows it again.).

  • What it reads is read again. Nothing watches a deleted metric, so when its saved query, a measure or a field under it changed while it was deleted, it comes back as its next version, uncertified, and its owner is told (Revenue changed: what it reads changed while it was deleted), as for any change under it.
  • What its delete turned off stays off. Its alerts and activations stay off for their owners to turn on again, and the digests it was taken out of don’t list it again. The Recovery Center names each one under Stays disabled, and the API’s answer names them in restored (staysOff, and notes in words: Its delete turned off alert “Revenue under plan”: they stay off until their owners turn them on.).

The toast that says it is back lists those notes under it, one per line, and stays up long enough to read them: what stays off and, when it came back as a new version, a line that says so (What it reads changed while it was deleted, so it came back as version 4 and is no longer certified: an admin certifies the new version again.). In the Recovery Center, the restore dialog names what stays off first, under Before you restore, and its toast carries the same notes.

A restore is refused when a live metric has taken its name (A live metric is named “Revenue” now: rename it, then restore this one.), when what it read was deleted since, or once the window has passed.

Deleting, and restoring from the toast or through the API, need the Metrics delete permission, which the built-in Editor role does not have; restoring in the Recovery Center needs the recovery restore permission. The audit log keeps what the metric was, and what its delete turned off.

A metric can read a saved query instead of a data model: one aggregate over one of the query’s output columns, under the metric’s own grain, target and declarations.

Define one. On New metric, choose From a saved query (or, in the editor, Reads from: A saved query). Pick the Saved query (search it by name), the Aggregate — Sum, Average, Minimum or Maximum of a number column, Count of values or Count of distinct values of any column, or Count of rows — and the Column it reads. The editor shows the expression it saves, such as SUM(amount), and offers the query’s date columns as the Time dimension. It reads the query’s columns without running it whole, as you, and never shows a row. You need to be able to read saved queries (the SQL editor’s view permission) to define a metric on one, and the query must be one of the workspace’s; when row-level security applies to you on the query’s source, or its SQL reads a column with a sensitivity label your role may not read, the editor says so and the metric is not saved. A ratio’s Numerator and Denominator are aggregates over the query’s columns too, such as SUM(profit) and SUM(revenue).

Where it is read. Everywhere a metric is read: the Metrics page and its drawer, with its latest whole period when it has a time dimension; KPI cards, on shared links and embeds too, decks and stories; metric-bound alerts; digests; the Slack command (certified metrics only); a report export’s KPI tile; activations; what moved; the automatic anomaly sweep; the API’s value, series and analysis; and the AI chat. Each reads it as the person it reads for: an alert as its owner (and each person it tells as themselves, where row-level security binds the query’s source), a scheduled digest as its creator (Send now as you), Slack as the admin who connected it, an export as you or the schedule’s creator, an activation as the user it runs as, the anomaly sweep as the metric’s creator (and each owner or follower it tells as themselves), a shared link’s card on behalf of the person who made the link, and everything else as you. It is computed from the query when it is read: on the Metrics page and on cards, a read you made of the same query in the last minute may answer again, for you only, never from before its source’s last load, and never when you refresh.

Each of those people is read with their role in the workspace’s own company, and a scheduled read stops when its person leaves (removed from the workspace or its company, or their account turned off): a digest whose creator left sends nothing (Send now still sends, as you), the anomaly sweep skips a metric whose creator left, an alert is skipped and says why, and Slack refuses its command until an admin connects it again. The metric’s owner, or else the workspace’s admins, are told once in the app.

What is refused, and said. A saved query runs as its SQL, which cannot be filtered to a person’s rows. So, as on a story, a person whom row-level security restricts on the query’s source gets no value, and a query whose SQL reads a column with a sensitivity label their role may not read is refused for them. On a shared link that limits its rows, or in an embed whose row rules filter a customer’s rows, such a metric’s card is not shown. A link’s visitor and a customer in an embed hold no role, so a policy on the query’s source aimed at a role withholds it from them too. An activation sends what it reads out of DataSquares, so it refuses such a column whatever the role, as it does for a dataset, and so do a Slack answer, a digest its creator sends and an alert’s email, push and webhook. A refusal says why wherever it happens: an activation’s run and an export’s block show its words; an alert’s last check, a digest’s entry, the Slack answer and a mover’s reason, whose words can leave DataSquares, show only a short sentence of their own for row-level security, a labelled field (never naming it) or the metric’s definition, and otherwise say the metric could not be read. In chat, the AI scope holds for the tables and fields the query reads, as for a metric on a data model. A metric on a saved query has no breakdown by a model’s fields: Explain this change and the AI’s governed queries read metrics on a data model only, and a dashboard’s filters do not narrow it.

A figure for a quarter, a year or any span longer than a metric’s grain is only right when DataSquares knows how the metric’s values over time combine. Adds up over time says so:

Choice What a longer period shows For example
Not declared the expression evaluated over the period’s rows, as before
Sum the values add up: a quarter is the sum of its months revenue, orders
Last value its value on the period’s last day that has data, never its days added together; the figure says which day it is from (at 30 Sep), so its data should hold one value a day or less often customers, balances, pipeline
Average the average of its values at its grain over the period headcount, average balance
Does not add up computed afresh over each period’s rows, never by adding periods together unique visitors, medians

Last value and Average need a Time dimension: the editor offers them once one is chosen, and the API refuses them without one.

Ratios. A metric that is a ratio (margin, conversion rate, average order value) declares its numerator and denominator. The ratio is recomputed from their sums for every period and every breakdown, never by averaging ratios: three months at 50%, 60% and 70% margin are not a quarter at 60% unless their revenues are equal. For a model-bound metric each part is SquareX, validated against the model like the expression (Sum(orders.profit) over Sum(orders.revenue)). A ratio’s value comes back with both summed parts, and when the denominator is zero or missing there is no value, rather than a guess. The Metrics page, the AI and the field checks read a ratio by its two parts.

Trends follow the same rules: a last-value metric’s quarterly series shows its value on each quarter’s last day with data (its weeks start where the source’s weeks start), an average metric’s the average of its months, and a ratio its parts’ ratio in each bucket. Weekly buckets are not made from an average metric’s daily values. Every surface reads the metric’s number the same way, so declaring how a metric adds up changes what they all read; a metric that declares nothing reads as before.

Explain this change, the AI agent’s own queries and analyses, and activations read a metric the same way: a ratio is its parts’ ratio for each member and each row. A metric that adds up as its last value or as an average over time has no single total for each member or row, so where a total is what they read, they say why they can’t read it rather than show a wrong number. Explain this change reads one period of the metric’s grain, so it explains an average metric, and a last-value metric whose grain is a day; it does not break a ratio down by members, because a ratio’s change does not add up from its members’ changes.

A figure for a period is provisional until the period is complete. It is complete when all four hold:

  • It has ended, in the period’s time zone.
  • Its books have closed. Books close on day is the day of the next month on which a month’s books close: with the 5th, September is provisional until 5 October. A day past a short month’s end means that month’s last day.
  • Its settlement lag has passed. Settlement lag (days) is how long after a period ends its figures can still change (late invoices, refunds).
  • Its data is in through its end. How current the data is depends on the source: a Warehouse dataset’s data is in to its last refresh, a staged source’s (a file, a sheet, a synced copy) to its last sync, and a live database’s to the moment the query ran, since it declares nothing else. A Warehouse dataset that has never loaded, or a staged source never synced, has no such moment: its figures say their completeness is unknown, and are never final.

A value served from the result cache says when it was computed, and any read of a figure (its value, latest period, trend or comparison) cached before its source’s last load is computed again. The last complete week, month, quarter or year is the latest one for which all four hold. Periods are read on the Gregorian calendar in a time zone: the workspace’s (Admin → Settings → Default Timezone; UTC until one is set) unless a request names another. That holds for every read of a metric: its number, its trend, pace, Explain this change, what moved, the anomaly sweep, digests, alerts and the AI’s periods. A row counts in a period by its date; on a date-and-time field, by the moment it holds, read in the period’s time zone, so a day in Kolkata starts at midnight in Kolkata.

A date-and-time field’s periods start and end at the workspace’s midnights. PostgreSQL and the sources that run its date arithmetic (its managed services, Redshift, TimescaleDB, Greenplum, YugabyteDB, ParadeDB, and staged sources: a file, a sheet, a synced copy), ClickHouse, Tinybird and Warehouse datasets cut every period there, except in a formula with Calculate, Fixed, LastNonEmpty, YTD, QTD, MTD, RollingSum or PeriodEndSnapshot, which SquareX works out in steps of its own. Other sources’ SQL can’t cut a period in a time zone (MySQL and MariaDB, SQL Server, Oracle, Snowflake, BigQuery, Databricks, Trino and Athena, DuckDB and CockroachDB among them).

Where a metric’s periods aren’t cut in the workspace’s time zone, the latest whole period its number shows and the period before it are read again as spans between the workspace’s midnights, as a deck’s figure is, and its trend’s periods are cut in the database’s own time zone. That holds for a metric on a saved query, a metric made from a model measure ([Revenue], read as the measure’s own formula), and formulas with Calculate (its filters, RemoveFilters, DateShift), Include, Exclude of a field other than the time dimension, LastNonEmpty or an iterator such as SumX. A formula that reads across periods, or that a single span can’t read, keeps the database’s periods for its number too: YTD, QTD, MTD, RollingSum, PeriodEndSnapshot, Fixed, Exclude of the time dimension, IgnoreFilters, or a field read outside an aggregate.

Explain this change, on a metric’s row or in its drawer (one with a data model and a time dimension), explains a change: choose the Periods, a Table and the dimension to Split by (region, product, channel), and DataSquares compares the two periods on the metric’s own definition and filters, and shows which members drove the change and by how much.

Periods offers two comparisons, named by the metric’s grain:

  • Latest whole month (the default): the latest whole period, the one its card shows, against the period before it.
  • This month so far (Today so far for a daily metric): the period running now, counted up to now, against the same days of the period before it (for a day, the day before up to the same time), never a part of a period against a whole one.

The dialog says which it compares, and the result names both periods (October 2026 vs September 2026, November 2026 to date vs 1–7 Oct), with the two values and the change in the metric’s own format. Explain is statistics only: no AI runs and no AI credits are spent. Explain with AI adds a one-line summary marked AI-written with its date, and uses AI credits, as the dialog says. It adds none, and says why, when the metric or the field it is split by is outside the AI scope an admin set for the model: the numbers still come. Opened for an alert (as the Android app opens it), it reads both periods as of the moment the alert fired. It runs under your data permissions, like every metric read. Through the API (POST /api/ai/explain-metric), period is latest (the default) or current, and the answer’s period.partial and previousPeriod.cut say when a period was cut. The summary comes only with ai: true, which, like every AI feature, is the app’s alone: an API key that asks for it is refused, and one that doesn’t gets the numbers.

A KPI card can bind directly to a metric: in the card’s settings, Bind to metric replaces the field wells, and the settings say what the card then shows (Shows the latest whole month of Revenue, as the Metrics page does, named on the card.). Every dashboard that shows “Monthly revenue” shows the same number: the metric’s number, in its own format, with its period and change on the card’s subtitle line (October 2026 · +3% vs previous month), or All data for a metric without a time dimension.

  • Dashboard filters. The page’s filters, a cross-filter click and the card’s own controls narrow the metric when their field is on the metric’s data model; they add to the metric’s own filters, never replace them. The card names those that don’t: Not filtered by Region, or Not filtered by Region or 2 other filters. A metric on a saved query is narrowed by none of them, since they name a model’s fields and not the query’s columns. When a filter makes the read fail, the card reads the metric again without it, and says it is not filtered by it.
  • Who sees it. Anyone who may open the dashboard reads its metric cards, with or without the Metrics permission.
  • Alerts. Create alert rule on the card makes an alert on the metric itself, which the page’s filters don’t narrow; on a filtered card the dialog says so (see Metric-bound alerts).
  • Exports. A dashboard’s or report’s export prints the tile’s number, its latest whole period, with that period beside it in a Period column (October 2026); see Metric tiles in exports. The page’s filters narrow it as they narrow the card, and a Note column beside it names those that don’t (Not filtered by Channel).

A metric’s KPI card shows on a public link and in an embed too, read through the link rather than a signed-in session: its latest whole period, narrowed by the page’s filters the viewer sets on the metric’s model, and the card names the rest (Not filtered by Region), as it does signed in.

  • A link’s visitor reads it as a guest of the link. A metric on a data model with row-level security is not shown (the card says You don’t have access to this card’s data); a link that limits its rows applies that limit after every other filter; sensitivity-labelled fields stay masked; and a metric on a saved query runs on behalf of the person who made the link, never on a link that limits its rows, nor where a policy on the query’s source is aimed at a role: a visitor holds none.
  • In an embed, a person of your company reads it as themselves, with their role, row-level security and masking. One of your customers reads it as the embedded user, with the embed app’s row rules applied after every other filter, and a metric on a saved query is not shown while those rules filter their rows, nor where a policy on the query’s source is aimed at a role. See Embed dashboards for each person.

The AI chat agent knows your governed metrics and answers with them rather than improvising SQL, through its list_metrics and evaluate_metric tools:

  • The card’s number. A metric’s number in an answer is the one its cards show: its latest whole period, named, with the period before and the change, whether it may still change and why, its target and how that period stood against it, and its pace over the period running now. It reads all of a metric’s data only for an all-time total.
  • Any other period. Asked about another period, the agent reads that one: the last complete week, month, quarter or year, one of them to date, one whole period (2026-Q3), or a range of days, in the workspace’s time zone. It compares it with the period before or the same period last year, like for like while a period is running (this month so far against the same days of last month), and narrows it by filters on the metric’s own fields, each one checked and never dropped.
  • Finding the metric. list_metrics finds a metric by its name, its description and the glossary terms and synonyms linked to it, certified and most-used first, and gives its formula (a ratio as its two parts), time dimension, how it adds up, which way is better, and its owner. A conversation starts from up to twenty metrics: the ones you follow, then the most used.
  • Its trend, anomalies and forecast (analyze_metric_series) leave out the period in progress, and say so. A metric on a saved query answers the same way, read from its query.
  • A metric built on a table or field outside the AI scope, a ratio’s parts included, is not read for the AI.
  • Only for those who may open Metrics. The agent’s metric reads need the Metrics view permission. For a role without it, the agent reads no metric and names none: the conversation starts from none, a search of the data model lists none, a quick answer never comes from one, and a chart kept from earlier in the conversation that reads one is not drawn again. The data model’s own fields and measures still answer.

Ask about this metric in a metric’s drawer opens the chat with the metric named. A question for one number from a metric is often answered at once (Questions answered at once).

The Slack command answers questions about certified metrics in a channel (see Integrations). Its answer is the metric’s number as its cards show it, with its period, its target and its change on the period before (Revenue · October 2026: 1,180,000 / 1,200,000 · -1.7% vs previous month), all in the metric’s format. Under it, a metric that adds up (Sum, or nothing declared) with a target gets its pace over the period running now (November 2026 to date: Revenue is on pace for its 1,200,000 target this month …); any other metric with a target says how its latest whole period stood against it.

Metric digests bundle up to 20 metrics, each once, on a daily or weekly schedule at the hour you choose. Each metric’s entry is its number, its latest whole period named (October 2026), in the metric’s format, with its target, and one failing metric produces an error entry rather than dropping the digest (Couldn’t read this metric right now., or the refusal’s own sentence when its read was refused).

Metrics with targets carry a pace narrative. Pace is read over the period running now, to date (November 2026 to date), and only for a metric that adds up as a Sum or declares nothing: “Monthly Revenue is pacing 18% ahead of target — projected $1.4M against the $1.2M goal by month end”, with statuses from achieved through critical. For a metric where lower is better, the target is a limit and the narrative reads that way: “Cloud spend is on track to stay 40% under its $100,000 limit”, or “…is already over its $100,000 limit” — never “reached”. A metric that adds up as its last value or an average, a ratio, or one that does not add up has no pace: its entry says how its latest whole period stood against the target (“Active customers was 1,150 in October 2026, at or above its 1,000 target.”, or “…12% under its 1,000 target.”; for a limit, “…within its 100 limit.” or “…12% over its 100 limit.”).

These sentences are written by rules and use no AI credits. A digest’s creator can turn on AI sentences for it: aiSentences: true when creating or updating the digest, signed in with a session token, because an API key can’t turn it on. When AI is set up, the AI then rewords each pace sentence to read more naturally, given only that sentence’s numbers and verdict, on every send, and that uses AI credits for every metric with a target; a metric outside the AI scope keeps its sentence written by rules. It is off for every digest until its creator turns it on, digests made before this option existed included, and a digest sent now with an API key keeps the standard wording.

Its hour. A digest is sent at its hour of the day (sendHour, 0 to 23) in the workspace’s time zone (Admin → Settings; UTC when none is set): daily at that hour, or weekly on the day of its first send. A new digest that names no hour is sent at 08:00. The hour holds across daylight saving: 08:00 is 08:00 before and after the clocks change. Its first send is the next time its hour comes round, and a change of its schedule or hour moves the next send the same way. A digest made before digests had an hour keeps the time of day it was made, in UTC, until its hour is set. A scheduled send reads its metrics for at most two minutes: one not read by then is sent as Couldn’t read this metric right now., so the digest still goes out at its hour.

Who may. There is no web screen for digests yet: they are managed through the Metrics API, which lists, creates, updates, deletes and sends a digest now. Reading the workspace’s digests needs the Metrics view permission, and making one the Metrics create permission. Changing one (PUT /api/metrics/digests/{id}: its name, metrics, cadence, hour, on/off or AI sentences), deleting it and Send now are for its creator or a workspace admin (Only the person who made this digest, or a workspace admin, can change it, delete it or send it now.), and a delete is recorded in the audit log (digest.deleted). Its metrics must be live metrics of the workspace (400 with details.missing names any that are not). Once its AI sentences are on, an API key can’t change it at all, not even to turn them off, since more metrics, a daily cadence or turning it back on would each use AI credits on sends no one signed in for: change it signed in, or have its AI sentences turned off in the app first.

Where it goes. A digest posts to the workspace’s digest.sent webhooks (a Slack channel, say; Slack-format hooks get readable channel lines) only when a workspace admin made it. Anyone else’s comes to its creator alone, in the app and on their phone, and its notice says It came to you only: digests post to the workspace’s channels only when a workspace admin made them. So one person’s numbers never reach a channel others read unless an admin chose to post them. A send by its creator, on its schedule or with Send now, leaves DataSquares, so a metric that reads a sensitivity-labelled field is sent as It reads a sensitivity-labelled field that can’t be shown here, so its value is withheld. in place of its number, whatever the creator’s role.

Scheduled sends read the metrics as the digest’s creator. Send now reads them as the person who sends it, because the values are returned in that response: its creator’s Send now then delivers it as a scheduled send does, and anyone else’s (an admin’s) returns the summary only and delivers nothing (delivered: false; postedToChannels says whether a send reached the channels). A digest’s AI sentences are charged the same way: as its creator on a schedule, and as the person who sends it on Send now, since that send is their click. A delivered send creates a notification for the creator (Digest “…” sent (3 metrics)), and a digest of one metric opens that metric.

An alert can watch a governed metric directly: one rule on the definition, whatever card shows it. Create alert rule on a KPI card bound to a metric makes one (Alert on Revenue, a governed metric, checked every 15 minutes.), and so can the AI chat and the Alerts API ({ metricId, operator, threshold, period }). What it compares is its Compares:

Choice period What it compares
Its latest whole period headline The number its card shows: its latest whole day, week, month, quarter or year, once that period is complete. Every new alert compares this unless another is chosen.
The period so far period_to_date The period running now, counted up to now. It starts again at the start of each period.
All of its data all_data Everything so far, as alerts made before compared. A total only grows, so a “below” alert on it may never fire.

An alert made before alerts compared a period keeps comparing all of the metric’s data until its owner switches it, and its owner is told once in the app (Alert “…” still compares all of Revenue’s data). Edit rule on Alert rules shows the same Compares, and for such an alert says This alert was made before alerts compared a period, so it compares all of the metric’s data. Choose its latest whole period to compare the number its card shows. The rules list names what each alert on a metric compares (Revenue (metric), latest whole period < 1,000,000).

An alert reads the metric without the page’s filters. On a card that some of them narrow, the dialog says so: This alert checks the metric without the page’s filters: it won’t be filtered by Region, as this card is. When it fires, each person its email and push reach is told in their own number, the notice names the period it compared and writes the value in the metric’s format, and an alert on a period is told again for each new period while it stays past its threshold (see How evaluation works). In the bell, an alert on a metric is listed only for admins and roles with the Metrics view permission: each person it told sees the number it told them, its creator the number it read, and the others no number (Notification channels).

A metric on a saved query is watched like any other, as the alert’s owner; a check that cannot read it is skipped, and the rule’s last check says why. An alert whose metric is deleted while in use is turned off, with the reason.

DataSquares checks certified metrics for unusual changes in the background, at most once an hour per metric. To qualify, a metric must be bound to a data model or a saved query, certified, have a time dimension, and use a day, week, month, or quarter grain. Year-grain metrics and metrics without a time dimension are skipped, and uncertified metrics are not swept.

The sweep judges the period the metric’s number shows: its latest whole period that has settled, in the workspace’s time zone. It reads a daily metric over the last 30 days, a weekly one over the last 90 days, a monthly one over the last 24 months and a quarterly one over the last three years’ quarters, and needs enough history there: at least eight whole daily or weekly periods, or seven monthly or quarterly ones. When the source’s periods cannot be placed on its own calendar, it leaves out the trailing period instead. A firing is judged against the usual level, the average of the periods before it, and is told once per metric and period; it records alert history.

Who is told. The sweep reads the metric as its creator, as they are in the workspace now. It tells that person, the metric’s owner and up to 25 of the people who follow it (the star), each an active member who may open Metrics. The owner and each follower are read as themselves, and told only when their own latest whole period is unusual too, so nobody learns of rows they may not see. The notice says it in words, in the metric’s format, and opens the metric: Revenue for October 2026 is unusually low: 31% under its usual level. — October 2026: 812,000, against a usual level of 1,180,000. Each firing is also an item in the bell, Anomaly watch: Revenue, once per period: it shows each person told their own latest value and usual level, and anyone else who may open Metrics only that it fired.

Channels. A firing is posted to the workspace’s metric.anomaly_detected webhooks only when the metric’s creator administers the workspace, as a digest is. What the channels carry leaves DataSquares, so a metric that reads a sensitivity-labelled field posts why in place of its numbers, whatever the creator’s role; the notices in the app keep them.

Each check takes a fair share: a slow source holds back only its own workspace’s metrics, and a metric whose read takes more than two minutes is given up and checked again an hour later.

The metric API exposes a few things the web editor does not: warning and critical thresholds, a certification’s note, and digests. Through the API:

  • The number. POST /api/metrics/{id}/value with include computes only what it names: headline (the metric’s number), allTime (value, all of its data), latestPeriod, series (with series) and comparison (with period and comparison). headline carries basis, period, value, previous, percent, provisional, provisionalReasons and dataThrough: basis is latest_period (its period names the grain, the first and last day and the time zone) or all_data for a metric without a time dimension. A request without include keeps the earlier answer for one release: value, the metric over all of its data under its filters, and latestPeriod, with headline beside them. A caller without the Metrics permission reads a card’s metric by sending the card’s cardId. A request that sends filters gets appliedFilters, the positions of those that narrowed the value: on a metric on a data model, those whose field is on its model; on one on a saved query, all of them, read as its columns.
  • Many at once. POST /api/metrics/values reads up to 50 metrics in one request, each one’s headline and, with include: ["series"], its series; one metric that cannot be read costs only its own item, which says why.
  • The list. GET /api/metrics takes q (name or description), certified, domain, ownerId, modelId, savedQueryId, sort (name, updated or certified), cursor and limit, and answers a page with items, total and nextCursor. Without them it answers every metric in an array, for one release.
  • Writing. target, thresholds, format and ownerId sent as null clear them; domain is set on create and update, in the spelling the workspace already uses. A metric reads one binding (both at once is 400), a data model of the workspace (another workspace’s is not found, 404), and a metric moved to another model has its expression and ratio parts checked against it.
  • Deleting. DELETE /api/metrics/{id} answers 403 for a certified metric to anyone but its owner or a workspace admin, and 409 METRIC_IN_USE with details.uses while anything uses the metric; ?force=true with confirmName, its name as typed, deletes it anyway, and POST /api/metrics/{id}/restore brings it back. Its answer’s restored says what came back changed (readsChanged: the version it came back at, the one before and whether its certification was cleared, or null when nothing it reads changed) and what stays off (staysOff: alerts, activations and digests, each by id and name), with notes in words.

latestPeriod is the latest whole period at the metric’s grain that has data, once the period after it has data (the source’s, whatever the date bounds the metric or the request puts on its time dimension) or has ended, and until then the latest earlier whole period that has data: its start and end days, its value, the previous period (whose value is null when it has no data) and the percent change between them. latestPeriod is null for a metric with no time dimension, when no whole period with data has settled, or when the source’s periods cannot be placed on its own calendar (the server logs why). The route accepts ad-hoc filters, refresh: true, and an optional series window of 30d, 90d, or ytd with an optional grain, ending on the workspace’s today. Series require a time dimension and return at most 500 buckets through the same RLS-aware governed query pipeline; a series’ own change compares its settled periods only. Add compare: "previous" to the series to get the period before as well — the 30 or 90 days before, or the same stretch of last year for ytd — in previous, with each series’ own date bounds so a chart can draw the two aligned.

The same route evaluates a single figure, as a report, an embed or an integration shows one. Its period and its comparison are named as a number binding names them:

  • period: a range of days, both days counted: { "kind": "range", "from": "2026-09-01", "to": "2026-09-30" }; one whole period of a grain, where a year is written 2026, a quarter 2026-Q3, a month 2026-09, an ISO week from Monday 2026-W43 and a day 2026-10-24: { "kind": "grain", "grain": "quarter", "at": "2026-Q3" }; or a relative period, last_complete_week, last_complete_month, last_complete_quarter, last_complete_year, week_to_date, month_to_date, quarter_to_date or year_to_date: { "kind": "relative", "relative": "last_complete_month" }. It is read in zone, an IANA time zone as the time zone database spells it (Asia/Kolkata, UTC; never an offset such as +05:30 or an abbreviation such as EST), the workspace’s when absent, on the Gregorian calendar. value is then the metric over that period, and the response’s period names its days and when it ends, closes and settles.
  • comparison: { "kind": "previous_period" } or { "kind": "same_period_last_year" } adds comparison, the same over the earlier period, like for like: the whole period before (or the whole month, quarter or year a year before, 29 February included), the same days of the one before for a period to date, a week or a day 52 weeks before (so a Monday meets a Monday), and as many days just before a range.
  • version: the metric as an earlier version defined it.

A figure counts its period’s rows through its end, or up to now (to the minute) while the period runs, so rows dated after today never count; its source’s last load says how complete the figure is, never which rows it counts. countedTo names the last day counted and, on a date-and-time field, countedUntil the moment. While the period runs, the comparison is cut to the same span, as many days into the earlier period and, on a date-and-time field, to the same time of day, and comparison.cut says so: this month so far is compared with the same days of last month, never all of it. A date field’s rows carry no time of day, so on a date field today so far is compared with all of yesterday, and cut is false.

Every response, with or without these, names the version evaluated, the currentVersion, the definitionHash and dependenciesChanged (see Versions); additivity, with a ratio’s summed parts, a last value’s valueAt day or an average’s buckets; computedAt, loadedAt and dataThrough with how it is known (dataThroughBasis: dataset_refresh, source_sync or query_time; dataThrough is null when the source has never loaded), and sourceState (whether a dataset’s or staged source’s load is fresh, overdue or failed); and whether the value is provisional, with provisionalReasons (not_started, in_progress, books_open, settling, data_incomplete, completeness_unknown when the source has never loaded, or to_date for all of the metric’s data). GET /api/metrics/{id}/versions lists the versions, newest first, 20 a page; each says how it came (origin: created, edited, backfilled, or dependency_changed when what it reads changed) and what it read (dependencies).

GET /api/metrics/movers answers what moved for the metrics you follow in one call — your favorite metrics first, then the metrics behind your active alerts, then the workspace’s other metrics, certified ones first (25 in all unless you ask for fewer). Each is read at its own grain over enough of its periods (30 or 90 days of a daily metric, 13 weeks, 13 months, 8 quarters or 9 years), in the workspace’s time zone, and shows its latest settled period’s value, the change against the period before it, and how unusual the move is against up to eight periods before, largest move first. The period in progress never counts, nor the latest whole period until the data has moved past it. A metric that cannot show a move says why: it is bound to neither a data model nor a saved query, has no time dimension, or has too little history; when its read failed, reason gives the refusal’s words when there is one (row-level security on a saved query’s source, say).

The create and update APIs accept savedQueryId for a metric on a saved query: a query of the workspace (another workspace’s is not found, 404) that the person making the change may read (403 otherwise). Its expression, and a ratio’s parts, are each one aggregate over a column of the query (SUM(column), AVG(column), MIN(column), MAX(column), COUNT(column), COUNT(DISTINCT column) or COUNT(*)), and anything else is refused with what to write instead when it is evaluated. POST /api/metrics/{id}/value evaluates it with its headline and a series, as you; a person whom row-level security restricts on the query’s source gets 403. GET /api/metrics/saved-queries/{id}/columns gives a saved query’s output columns and their types, read as you by a statement that reads no row, for an editor to offer a column to aggregate and a date column.