90 day trends vs snapshots
28 Aug 2026
Snapshots lie: why 90-day trends change decisions
Every Microsoft 365 review starts with a number that is true and useless. Storage at 68% of quota. 412 of 450 licences assigned. Last month's Azure bill, €4,180. Each one is correct on the day it was read, and none of them says whether you are looking at a steady state or the middle of a slope. Below are four metrics where we went back and read the same tenant twice — once as a point, once as a line — and the line changed what we would have done.
Storage: 68% of quota, and the wrong remedy
A SharePoint tenant at 68% of quota is a tenant nobody schedules a meeting about. Read as a line instead, the same tenant had added roughly four points a month for five months — which turns "we're fine" into "we buy storage or we clean up before the winter, and the decision is due now, not in Q2."
The trend is not something you have to build. Graph has a dedicated
function for it: getSharePointSiteUsageStorage
returns "the trend of storage allocated and consumed during the reporting
period", and the CSV it redirects to carries a Report Date column
— one row per day, up to D180. The per-site and per-mailbox
reports are the opposite shape: getMailboxUsageDetail
also takes a period, but every row is that mailbox as of the Report
Refresh Date. Passing D180 does not give you six months of
mailbox sizes. It gives you today's sizes, filtered by six months of activity.
The slope also names the remedy, which the snapshot can't. In the tenants we've measured, files are a minority of the bytes: 33% to 51% of a SharePoint site's storage was version history, recycle bins and preservation hold, and 42% to 65% of a OneDrive's. A point-in-time number invites "ask people to delete things", which recovers none of that. Two months of slope tells you whether the growth is documents arriving or versions accumulating — a different problem with a different fix.
Sign-ins: a trend you are not allowed to have
Ask for a quarterly view of sign-in anomalies and the platform simply says no. Microsoft Entra keeps sign-in and audit logs for seven days on Free and 30 days on both P1 and P2. Paying more does not buy more history: 30 days is the ceiling. Risky sign-ins are the one exception, at 7 / 30 / 90 days by tier.
Two consequences people discover late. First, the 90-day question can only be answered by something that copied the data out before it aged — Azure Monitor, a storage account, or a tool that keeps its own snapshots. Second, retention changes are not retroactive: upgrading a Free tenant to P1 today surfaces the seven days that still exist, not last month's. The upgrade you make during an incident buys you nothing about the incident.
Licences: the number with no yesterday
"412 of 450 assigned" is the most-quoted figure in any tenant review, and it
is the one with the least information in it. Look at the
subscribedSku
resource: consumedUnits, prepaidUnits,
servicePlans, capabilityStatus — eleven properties,
not one of them a date. There is no "as of", no history, no change event. The
API is physically incapable of telling you whether 412 was 380 six weeks ago or
430 last quarter, and those two tenants need opposite decisions at renewal.
A metric with no date property is not a slow-moving metric. It is a metric whose history exists only if somebody wrote it down. Whoever snapshots it first owns the trend — and if nobody does, the answer to "when did this start?" is permanently unavailable.
The same blind spot sits under licence waste. Thirty-eight spare seats reads as healthy headroom or as a stalled rollout depending entirely on the direction, and the direction is not in the payload.
Cost: the snapshot moves after you take it
Azure spend is the one place where two people can read the same month and both be right. Cost Management data is estimated until an invoice is generated, estimated charges for the open period are updated six times a day, and the current period's charges can be rerated until the invoice closes — which itself happens up to 72 hours after the billing period ends. Latency compounds it: 8 to 24 hours for EA and MCA subscriptions, up to 72 hours for pay-as-you-go.
So a screenshot taken on day 2 of the month and one taken on day 30 are not the same kind of object, and "last month spiked" is a claim that can quietly stop being true. A trend built from daily reads is not just more information than a snapshot here — it is the only version that survives contact with the final invoice, because you can see the same day restated instead of remembering it wrong.
Three kinds of metric, three amounts of work
After doing this across a handful of domains, everything sorts into three buckets, and the bucket decides how much effort a trend costs you.
| The platform gives you | Example | What you have to do |
|---|---|---|
| The trend itself | Storage and activity counts, up to D180; Azure cost, 13 months | Ask for the right period, and plot it. Most teams never leave D7. |
| A short window that expires | Sign-in and audit logs, 7 or 30 days | Copy it out on a schedule, starting before you need it. Nothing recovers an expired window. |
| A bare number | Licence counts, policy and configuration state | Snapshot it yourself and keep the snapshots. The trend has no other source. |
One trap worth knowing before you trust a long window: history can be rewritten underneath you. When a user account is deleted, Microsoft removes that user's usage data within 30 days — the chart totals keep them for the periods they were active, but they vanish from the detail table. A per-user report you pulled in March and pull again in June will not agree, and neither pull is wrong. The same page is where the "Last Activity Date" gotcha lives too: it is the most recent intentional activity in that app regardless of the period you asked for. It is not a value from inside your window.
None of this needs a data warehouse. It needs the same handful of endpoints read on a schedule and kept, which is what GraphPaaS does per tenant: the periods the Reports API already offers, plus its own dated snapshots for the numbers Microsoft hands over without a date. The value isn't the chart. It's that the question "when did this start?" has an answer at all.
- reportRoot: getSharePointSiteUsageStorage — the D7/D30/D90/D180 parameter and the Report Date column that makes this endpoint a daily series rather than a snapshot.
- reportRoot: getMailboxUsageDetail — the per-row columns, showing that a detail report is state as of the Report Refresh Date even when a long period is passed.
- Microsoft Entra data retention — seven days on Free, 30 days on P1 and P2 for sign-in and audit logs, 7/30/90 for risky sign-ins, and that retention changes aren't retroactive.
- subscribedSku resource type — the full property list, with no date, timestamp or history property anywhere in it.
- Understand Cost Management data — 13 months in Cost Analysis, six updates a day for the open period, rerating until the invoice closes, and the 8–24h / 72h latencies.
- Microsoft 365 usage reports overview — the 7/30/90/180-day availability, the 24–72 hour publish delay, deletion of a removed user's usage data within 30 days, and how Last Activity Date ignores the selected period.
Every tenant metric read on a schedule and kept — so the number comes with a direction, not just a value.
See your trends →