> ## Documentation Index
> Fetch the complete documentation index at: https://help.the-meridian.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Views

A view is a saved way to read one of your [usage events](/introduction-6). The event records what happened; a view decides what number to get out of it.

Every event already has one reading built in: the quantity you pass to `track()`, summed over each store's [billing period](/events). That is what `usedThisPeriod` reports and what a plan bills. A view is for the other questions:

* How many times did this fire, ignoring quantity?
* What is the total of `properties.total_price` this month?
* How much has this store used in the last 7 days?

Views are **computed over your whole history**. One you add today reports correct numbers for events you tracked months ago, which is why the [tracking docs](/events) push you to send real properties. A property you never sent cannot be recovered afterwards.

## Adding one

Open the event under **Usage → Events**, then **Add a view**.

| Field | What it does |
| - | - |
| **Name** | What you'll recognize it by in Meridian |
| **Key** | What your app passes to `getUsage()`. Fixed after creation |
| **Reads** | Number of events, or a total |
| **Total of** | For a total: the tracked quantity, or one numeric event property |
| **Window** | What `getUsage()` reports for a store |

As you fill it in, Meridian previews the definition against events you have already stored: the value it would give, how many events counted, how many were skipped, and across how many stores. Get the number you expect there before you create the view.

### The preview period

The preview reads **Last 90 days** by default, and the subtitle says so. That is a bound on the preview, never on what Meridian kept: your events are all still there, and the view reads every one of them when you create it.

Switch the period to **Last 12 months** or **All time** to see the figure over more of your history. A developer who imported two years of events sees the lifetime count in the dialog, before the view exists.

| Reads | Last 90 days | Last 12 months | All time |
| - | - | - | - |
| **Number of events** | Yes | Yes | Yes |
| **A total** of the tracked quantity | Yes | Yes | Yes |
| **A total** of an event property | Yes | No | No |

Counts and quantity totals come from the daily totals Meridian already keeps per event key, so any period is instant and none of them is capped. That is also the same place the created view reads from, so the number in the dialog and the number on the view afterwards agree.

A total of an **event property** is the exception. Those daily totals hold a value and never the properties it came from, so previewing one means reading your raw events, which Meridian bounds to the last 90 days and to **20,000 rows**, newest first. Over a longer period it says it cannot give you the number rather than answering with a 90-day figure under an "All time" label. Check the property is there over 90 days, create the view, and Meridian computes it across your whole history.

If your app tracks enough events to pass 20,000 inside 90 days, the preview says how many rows it read out of how many are in the window. Only the preview is capped. The view itself has no cap.

### Keys are shared with your events

A view's key lives in the same namespace as your event keys, one namespace per app. You cannot give a view a key an event already uses, or the reverse. Meridian refuses both with a 422.

That is what makes `getUsage("anything")` work: your app holds one string and does not have to know whether it names an event or a view.

## What a view can read

Two aggregations, on purpose.

**Number of events** counts every `track()` call, whatever quantity it carried. Use it when the call is the thing you care about: API requests, runs, exports.

**A total** adds up either the `quantity` you passed to `track()`, or one numeric property you sent with it. `properties.total_price`, `properties.characters`, `properties.bytes`: a dot path, so a nested property is `order.total_price`.

The property picker offers the numeric properties your recent events actually carry, with how many of them carry each one. Pick from that list rather than typing a name, and a typo can't cost you a month of data.

### Properties that aren't there are skipped

A total over an event property can only add up events that carry it as a number. An event whose property is missing, `null`, or not numeric (`"free"`, `true`, an object) is **skipped**: it stays stored, it still counts for the event itself and for billing, it just contributes nothing to that view.

Meridian counts those skips and shows them on the view, so a total that reads lower than you expect has an answer rather than a mystery. The create-time preview shows the same count over the last 90 days, before you commit to a definition. If it says every event was skipped, the property name is wrong or your app isn't sending it yet.

## Its history

The views list states one figure per view: its all-time total across every store, with a 30-day sparkline beside it. **History**, in the row's menu or by clicking that sparkline, opens the same figure as a chart, over the period you pick: last 7, 30 or 90 days, the last 12 months, or all time. Coarse periods are drawn one bar per month, so two years of a metric is 24 bars rather than 730.

This is the only place a **total of an event property** has a shape. The create-time preview of one is bounded to the last 90 days, because the daily totals hold a value and never the property it came from. The view has already reduced every one of those properties to a value, so `properties.total_price` per month over two years is one read here, on a view that already exists.

The bars are every store together, for the same reason the total is. The per-store, windowed figure is the one your app reads through `getUsage()`.

## Windows

Five presets. No custom ranges.

| Window | What it covers |
| - | - |
| **Billing period** | The store's current billing cycle, the same window `usedThisPeriod` uses |
| **Month to date** | The current UTC calendar month, from the 1st |
| **Last 7 days** | Today and the six UTC days before it |
| **Last 30 days** | Today and the twenty-nine UTC days before it |
| **All time** | Everything ever reported |

The window is **per store**, and it is the window `getUsage()` reports over. A store on Billing period gets its own cycle: 30 days from when its subscription activated when it is subscribed, the UTC calendar month when it is not. It is the same rule the rest of usage follows.

That is also why the numbers on the event's page are all-time totals across every store rather than "this period": with a Billing period view there are as many current windows as you have subscribed stores, so no single figure could mean it. The per-store, windowed number is the one your app reads.

## Reading a view from your app

`getUsage(key)` takes an event key or a view key:

```ts theme={null}
const { getUsage, getView } = useMeridian()

getUsage("orders_created")?.usedThisPeriod   // the event, current billing period
getUsage("gmv_this_month")?.usedThisPeriod   // the view, over the view's window
```

When you need the window itself (to tell a merchant what "this month" means, or when it resets), `getView(key)` carries it:

```ts theme={null}
const gmv = getView("gmv_this_month")

gmv?.value        // 1284.5
gmv?.window       // "calendar_month"
gmv?.windowStart  // "2026-08-01T00:00:00.000Z"
gmv?.windowEnd    // "2026-09-01T00:00:00.000Z", exclusive
```

`windowStart` and `windowEnd` are absent on an **All time** view, which is unbounded. Both are also on the raw snapshot as `entitlements.views[key]`, and the same pair exists on the [server client](/sdk-use-meridian) as `getUsage` / `getView`.

## Reacting to a view

A view is also something an [automation](/automations) can watch: [Usage view crosses a threshold](/usage-view-threshold-crossed) runs a flow the first time a store's value for a view reaches a number you set, once per store, per window. The threshold is evaluated as your app tracks events, so a recompute or a backfill never sends anything.

## Editing and deleting

Right after you create a view it is **Computing**: it is reading your history, and the event page says so. Its numbers fill in as that runs. It becomes **Ready** when it has read everything.

You can change what a view reads (its aggregation, its property, its window) at any time, **until a plan prices it**. Changing the aggregation or the property recomputes the view from your history and puts it back to Computing; changing only the window needs no recompute, because a window is applied when the value is read, not when it is stored.

Two things never change: the **key**, because your app calls it, and the **event** it reads, because everything the view has computed came from that event's rows.

Deleting a view removes it and the daily totals it computed. Your stored events are untouched: a view is an interpretation of them, and dropping it changes nothing about what happened. Any code calling `getUsage()` with its key stops resolving, so remove the call too.

Deleting the event a view reads deletes the view with it, the same way, and the event's delete confirmation lists its views first. A view a plan prices blocks that delete too (see [A priced view is locked](#a-priced-view-is-locked)).

## Billing on a view

A plan can meter a view instead of an event key. That is how **percentage-of-value pricing** works: a view that totals `properties.total_price` over the billing period, priced at `0.02` per `1` unit, is 2% of GMV.

Set it in the [Plan Builder](/create-a-plan) alongside your events: same section, same four terms:

| Term | For a view |
| - | - |
| **Included quantity** | Free allowance per billing cycle. Fractional, because a view can total money: "the first \$1,000 of GMV" |
| **Overage rate** | What one unit over the allowance costs. `0.02` per `1` unit is 2% |
| **Units the rate covers** | `1` for a percentage. Higher only when you price in batches |
| **Monthly cap** | The ceiling the merchant approves, exactly as on an event |

Once it is priced, the view behaves like a metered event everywhere: `getUsage(key)` carries `includedQuantity` and `cappedAmount`, the account page renders a usage meter for it, and `updateUsageCap` takes its key.

### Two rules, both from Shopify

**Only a Billing period view can be priced.** Shopify bills app usage per 30-day cycle, so "the overage of a rolling 7-day metric" is not a question with an answer. A Month-to-date or Last 7 days view stays perfectly useful for what you display and gate on. It just cannot carry a price, and Meridian refuses the plan term rather than inventing a meaning.

**A plan meters one subject in total**, an event or a view, never both. A subscription carries a single usage line item.

A view that is still **Computing** cannot be priced either: it has read only part of your history, and the first charge would be a figure nobody could explain.

### A priced view is locked

The moment any plan, draft or active, references a view, its definition freezes. Its aggregation, property, window and key can no longer be changed, it cannot be recomputed, and it cannot be deleted, and neither can the event it reads. Meridian answers a `422` naming the plans holding it.

That is deliberate, and it is about money: redefining a metric merchants are billed on changes what they are charged for, and recomputing one rewrites the history a past invoice was computed against. Renaming it is still fine, because a name is not a definition. Removing it from every plan unlocks it again.

To meter something different, **create a second view**. That is the honest model anyway: the old one keeps its charge history, and nothing about a past invoice becomes unexplainable.

### Nothing is billed retroactively

A view reads your whole history, which is the point, but it starts *billing* only from the moment it exists. When you create one, Meridian records everything it has already read as accounted for, so attaching it to a plan afterwards charges nothing for the orders that came before. From there on it bills like any other metered subject.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.