Insights
Insights is where you see what reached your service: every request and every GraphQL operation, what the cache did with it, how long it took, and what went wrong. Open a service in the portal and choose Insights.
Plans Every plan
What you need
Section titled “What you need”Insights is part of every plan, Glider (Free) included. Plans differ in how many list columns and filters they offer, and in how far back you can look.
Request telemetry is stored on every plan. Paid plans include a monthly allowance of logged requests, and logged requests past it are billed as overage, per started million, from the first day of the billing period. Each logged request counts once against this allowance, including one that went through a shield, and Usage on the billing page shows the count (see usage). Glider (Free) has no separate allowance of logged requests: recording stops only when the billing account switches to lean mode, which happens when its request units are used up. Nothing is stored while the billing account runs in lean mode, and an upgrade does not fill that window in later: see nothing is recorded in lean mode. The allowance for each paid plan is on pricing.
A service can leave some or all of its own traffic out of Insights with
telemetry.record in its gpilot.toml.
Those requests are still served and counted. When a service records nothing, every Insights tab
says so in place of empty lists; when it records only part of its traffic, a note below the tabs
names the expression. While the billing account runs in lean mode, only the lean mode notice is
shown, since lean mode is then the reason nothing is recorded.
A request that was not stored does not appear in Insights, in the figures on the service Dashboard or in the purge history. Alerts do not depend on stored telemetry.
How far back you can look depends on your plan:
| Plan | Request telemetry is kept for |
|---|---|
| Glider (Free) | 1 day |
| Jet (Starter) | 7 days |
| Airliner (Business) | 30 days |
| Jumbo (Enterprise) | 90 days |
Older requests are deleted automatically within a day, at the retention of the plan the organization has at that moment. After a move to a lower plan, what it no longer keeps is deleted within a day, and a move to a higher plan does not bring back what was already deleted. The GraphQL errors recorded with those requests go with them. The error groups and the values the filters suggest are kept as long as they keep occurring within the plan’s retention, and are deleted within a day once they have not. If you pick a time range that reaches further back than your plan keeps, the time range picker says so, and that part of the range comes back empty.
An Admin can also delete a service’s request telemetry at any time, without waiting for retention: see reset history. The request counts billing and the quota are based on are kept.
The tabs
Section titled “The tabs”| Tab | Shows |
|---|---|
| Requests | Every HTTP request to the service, GraphQL or not. |
| Operations | Every GraphQL operation, named or anonymous. |
Requests and Operations share one layout, top to bottom:
- Key figures for the selected range: total requests (or operations), Cache hit, Latency, Error rate and Traffic (bytes in and out). Most figures have shortcuts that filter the list, for example to failed requests or to cache hits. See latency and response size and the two error rates.
- A chart over time. Requests can be grouped by Status code, Method or Cache status; Operations by Operation, Status code or Cache status. See charts.
- A top list (Jet (Starter) and above): Top paths on Requests, Top operations on Operations. Selecting an entry filters by it. On Glider (Free) the list is shown locked, with the plan that includes it.
- The list of individual requests or operations, newest first. Select a row to open its detail panel.
Hide analytics folds the figures, chart and top list away so the list gets the room.
The Cache hit figure
Section titled “The Cache hit figure”Below its rate, Cache hit breaks the requests down: Offload (requests answered without calling your origin), Stale (served from a stale entry; these also count as hits) and Masked (your origin answered with an error, 400 or higher, but the client still got a status below 400).
For a service with a shield, a Shield section follows whenever requests were routed to it: Hit (the share the shield answered from its own cache, fresh or stale), Offload (the share of all requests the shield answered, so your origin never saw them), Fallback (the share where the shield could not be used: unreachable, too slow, or unavailable for a mutation) and Shielded (how many requests went to the shield). Selecting Hit or Fallback filters the list by Shield result.
Latency and response size
Section titled “Latency and response size”The Latency figure shows one statistic of one part of the time a request took. The menu in its header picks both:
| Part | Measures |
|---|---|
| Total | Client to response. |
| Edge | Edge processing (total minus origin). |
| Origin | Edge to origin and back. |
Each part offers the average and the p50, p90, p95 and p99 percentiles, with the value of each shown in the menu. The default is Total at p50. The average and p50 are on every plan; p90, p95 and p99, and the Edge and Origin parts, need Jet (Starter) or above, the same plan as the edge and origin latency columns and filters. An entry your plan does not include is shown disabled, with the plan that includes it.
In the Traffic figure, Response size shows the size of a single response at a statistic you pick on that line: the average, p50, p90, p95 or p99. All five are on every plan.
The two error rates
Section titled “The two error rates”The Error rate figure is the share of requests that failed: the client got an HTTP status of
400 or higher, or the response carried at least one GraphQL error. A GraphQL error usually
arrives in a 200, and it counts all the same, including an error the edge removed before the
client saw it. 4xx and 5xx beneath it are the shares of requests with each status class,
so they add up to the error rate only when no GraphQL error arrived in a 200. GraphQL
errors, on the line below, is the share of GraphQL operations whose response carried at least
one GraphQL error, whatever the HTTP status: it counts over GraphQL operations only, where the
error rate counts over every request. It reads 0% when there were no GraphQL operations.
An origin error that the client never saw, because the cache answered or the edge served a stale entry, is not a failed request. The Masked figure on Cache hit counts those, and the Masked origin errors preset lists them.
Select a figure to filter the list: Error rate to failed requests (the Request failed filter), 4xx and 5xx to their status class, GraphQL errors to responses that carried a GraphQL error. Its small chart draws the error rate. The alert rule GraphQL errors in your responses watches the same failures as GraphQL errors.
Charts
Section titled “Charts”Every figure carries a small chart, and the main chart sits below them. Each chart has its own type buttons (Area, Bar, Line), and Chart type for all charts at the top of the page sets every chart at once. The legend beside the main chart names each series; selecting a series filters the list by it.
The slider under the main chart narrows the page to part of the range on screen: drag its handles and let go, and the whole page (figures, chart and list) follows. It only narrows; widen the range with the time range picker.
Time range, live and refresh
Section titled “Time range, live and refresh”The controls at the top right apply to every tab:
- The time range picker offers relative ranges and a custom range, and the time zone the page shows times in. On Requests and Operations it also offers Live: new entries are added to the top of the list as they arrive, without reloading.
- Granularity sets the chart’s buckets. The default, Auto, picks a bucket size that fits the range. Per hour and Per day are on every plan, Per minute and Per month from Airliner (Business). A granularity that would make too many buckets for the range is shown disabled.
- Auto-refresh refreshes the data on an interval you pick. Beside it, the page says when its data was last updated.
A relative range such as the last 24 hours ends shortly before the page opened; refresh and auto-refresh move its end to the current moment. A custom range is used exactly as it is.
Filters
Section titled “Filters”Type a filter into the bar above the list, for example path:/graphql -method:GET. A leading
- excludes. As you type, the bar suggests fields and the values seen on this service;
How to write a filter explains the syntax. The Filters panel offers the same filters as
form fields, grouped (Request, Response, Cache, GraphQL, Latency,
Network, Deployment, Tracing and more), with Reset all filters.
A leading - or ! excludes, on every plan. Several exclusions are combined into one: a
request is hidden only when it matches all of them. A field inside an exclusion still needs its
own plan, so excluding by a field your plan does not include is refused as that field.
Only my requests narrows the list to requests sent from your browser’s IP address, which is
the quickest way to find a request you just made. It filters by client IP, so like that filter
it needs Jet (Starter) or above. On a service that stores client IPs truncated or not at all
(telemetry.client_ip), it matches nothing, since
your full address is never stored there; a request without a stored address shows Not
stored as its IP.
Filters are where plans differ. Method, path, hostname, status, operation name and type, latency and sizes are available on every plan, and so is what the cache and your origin did: cache status, cache lookup, Shield result, Not cached because, Segmentation (Public, Private or Vary), origin status, Origin outcome, Masked origin error and Request failed. Other filters open up on Jet (Starter) and above (for example client IP, client ID, device type, country, cache age and TTL, Segment source and Segment, edge and origin latency) or on Airliner (Business) and above (for example surrogate key, cache key, cache hits, retries, edge location, trace ID). A filter your plan does not include is shown disabled, and says which plan includes it.
Not cached because covers every reason nothing was stored, whether the cache was never
consulted (a CACHE_PASS_* code) or the response was not stored (a CACHE_SKIPPED_* code). Its
choices are grouped by who can act on them: Your configuration, The request, Your
origin’s response, Your schema or partitioning, Shield, Follows from another outcome
and GraphPilot (internal). In the filter bar it is cache.reason; cache.pass.reason and
cache.skip.reason are read as the same filter.
Origin outcome says what became of your origin for a request: Called, Call failed, Called via shield (the shield called your origin), Not called (shield cache), Not called (cache), Shield failed (the shield gave no usable answer, and whether your origin received the request is not known) or Not called (refused by GraphPilot). On a shielded request it is the reading to trust: the edge records a request it sent on to the shield the same way as a cache hit, even when the shield then called your origin. Request failed selects the requests that failed for the client, the same rule as the Error rate figure, and Masked origin error the ones whose origin failed while the client still got a status below 400.
Segment takes source=value pairs, and every pair must hold on the same request. Type the
value as it was recorded: a pseudonym (hmac-sha256:…) or digest (v1=…) is best copied from a
request’s Cache tab, or reached through Requests in this bucket there. A value in clear only
matches on a service that stores vary values in clear, and never matches its pseudonym.
Presets
Section titled “Presets”Presets (the button beside the filters) applies a set of filters in one click. Applying one replaces the filters you had; the time range stays. It comes with built-in presets grouped under Errors, Cache, Performance, GraphQL, Origin and Client. Star a preset to keep it under Favorites. Save current filters stores what you have applied under Saved, and a saved preset can be deleted from there.
A preset uses the same filters you could set by hand, so it needs the plan those filters need.
Favorites and saved presets are kept in your browser, not in your account: they do not follow you to another browser or device, and other members do not see them. To hand a set of filters to someone, share the page address, which carries the filters.
Every built-in preset
| Group | Preset | Keeps |
|---|---|---|
| Errors | Errors | Requests that failed: a 4xx or a 5xx, or a response with at least one GraphQL error. |
| Server errors | Requests that failed with a 5xx. | |
| Client errors | Requests that failed with a 4xx. | |
| Auth failures | Requests answered 401 or 403. | |
| Rate limited | Requests answered 429. | |
| Gateway timeouts | Requests answered 504. | |
| GraphQL errors | Responses that carried at least one GraphQL error. Also listed under GraphQL. | |
| Masked origin errors | Requests your origin answered with an error while the client still got a status below 400. Also listed under Origin. | |
| Errors hidden from client | GraphQL errors the edge removed before the client saw them. | |
| Cache | Cache hits | Requests answered from a fresh cache entry. |
| Cache misses | Requests the origin answered and the cache stored. | |
| Not cached | Requests nothing was stored for: the cache was not used, or the response was not stored. | |
| Stale served | Requests answered from a stale entry. | |
| Queries not served from cache | Queries your origin answered: a cache miss, or nothing was cached. | |
| Private responses | Entries stored for one caller only. | |
| Vary-segmented | Entries shared within one segment of callers. | |
| Performance | Slow requests | Requests that took 1s or more in total. |
| Slow edge | Requests with an edge latency of 100ms or more. | |
| Large requests | Requests of 100 KiB or more. | |
| Large responses | Responses of 1 MiB or more. | |
| GraphQL | Queries | Every query, cached or not. |
| Mutations | Every mutation, cached or not. | |
| Non-GraphQL requests | Requests that carried no GraphQL operation. | |
| Anonymous operations | GraphQL operations with no name: the request sent no operationName and the document does not name the operation either. | |
| Persisted queries | Requests that sent a persisted query hash instead of a document. | |
| Rewritten by GraphPilot | Requests whose document GraphPilot changed on its way to the origin. | |
| Origin | Served without origin | Requests a cache answered, at the edge or at the shield, without calling the origin. |
| Slow origin | Requests the origin took 1s or more to answer. | |
| Origin retries | Requests the edge had to send to the origin again. | |
| Origin failures | Origin calls that failed without a response. | |
| Rejected at the edge | Requests the edge refused before they reached the origin. | |
| Client | My requests | Requests sent from this browser’s address. |
| Desktop requests | Requests from desktop devices. | |
| Mobile requests | Requests from phones, tablets included. | |
| Bots | Requests from crawlers, downloaders and feed readers, AI agents not included. | |
| AI agents | Requests from AI crawlers and from assistants fetching for a user. |
Columns
Section titled “Columns”Columns, the button at the right of the list’s header, chooses which columns the list shows and in which order. Its menu has three parts:
- Views: All presets holds the built-in views (Overview, the default, then Errors, Cache diagnosis, Performance, Origin, GraphQL and Clients and geo). Star one to keep it under Favorites. Save current view stores your columns, in order, under Saved.
- Columns, grouped (Request, Operation, Response, Latency, Origin, Cache, Client, Geo, Network, Edge, Other), each with a count of how many are shown. The timestamp column cannot be hidden. A column your plan does not include is shown locked, with the plan that includes it.
- Arrange columns, to change the order.
The column choice is part of the page address, so a link you share opens with the same columns. Favorite and saved views are kept in your browser, like saved presets.
List columns are the other place plans differ. Timestamp, method, path, status, operation, latency, sizes, the cache Segment and the Request ID (the same id the detail panel shows as Entry ID) are available on every plan. So is what the cache and your origin did with each request: cache status, Not cached because, Shield result, Origin status and Origin outcome. Columns such as client name and version, client IP, geography, TTL, and edge and origin latency need Jet (Starter) or above; Cache key, Hits, Retries, Edge location and connection details need Airliner (Business) or above.
The list shows a code by its words, the same words the filter uses, with the code itself in the tooltip. A few fields are not list columns, because the detail panel shows them on every plan: surrogate keys, the cache Lookup, the Policy source, the cache entry’s max age and stale-while-revalidate window, and the provider and servers under Diagnostics.
The request detail panel
Section titled “The request detail panel”Select a row to open the request, or operation, in a panel beside the list. It has four tabs:
| Tab | Shows |
|---|---|
| Overview | The request (method, path, host, size, client, device, the Entry ID and the Correlation ID, both with a copy button) and the response (status, size); what was sent to your origin (Request says whether it was sent at all), with its status, latency and retries; for a request routed through a shield, the Shield set: the shield location with its city and country, how the hop ended (Result, with what it means) and, when the shield called your origin, that call’s status, latency and retries; the edge’s location, latency and version; then Diagnostics, for a support case: the Provider, the Edge server within the location that answered and, for a shielded request, the Shield server. Then four header sets: Headers from the client, Headers back to the client, Headers sent to the origin and Headers from the origin. Which headers are recorded is set in [telemetry.. A sanitized value is shown as the digest the edge recorded, hmac-sha256: followed by 16 hex digits, marked with a shield icon: it is a pseudonym of the value, not the value itself, and two requests of one service that sent the same value show the same digest. Last, for a request that has any, Edge codes: GraphPilot’s codes for the request (what it decided, such as CACHE_STORED, or why it refused it) with the detail it had, such as the header or cookie that kept a response out of the cache. |
| GraphQL | The operation name (the operationName the request sent or, when it sent none, the name the document gives its only operation) and type, the query and variables hashes, and a persisted query hash if the client sent one. Document shows the operation three ways: Origin, the document your origin received; Client, the document the client sent; and Diff, the two against each other, which marks the fields GraphPilot injected. The heading says GraphPilot touched this document when fields were injected and Sent to the origin as written when none were, and the Diff reading then says so instead of a comparison. A request answered from the cache at the edge location says Served from cache, not sent to the origin; a request GraphPilot rejected says Answered by GraphPilot, not sent to the origin. Errors lists the GraphQL errors your origin answered with (at most ten are kept per request; the heading says Showing 10 of the total when there were more), each with its code, message and path. An error marked Stripped before client was removed by the edge, so the client never saw it. Only for GraphQL requests. |
| Cache | The cache status; the Lookup, which says what the cache lookup found (an entry, no entry, an entry that could not be read or was older than the client’s max_age, or a failed lookup); Not cached because for a request nothing was stored for, with the reason’s code under it (the Decision section above says whether the cache was consulted first); for a shielded request the shield answered without storing, the shield’s own reason, marked Decided at the shield, in place of CACHE_ (filtering by the row still matches that code, which is the request’s own); Policy source, Hits, the freshness timeline, the Segmentation (Public, Private or Vary, and what it was split by; each value marked pseudonymized, anonymized or clear; a vary rule’s value is a keyed pseudonym unless the rule sets pass_to_origin = "anonymized" or the service sets telemetry.vary_values = "clear", see what Insights records), the Cache key, and every surrogate key the response carries. |
| Client | Recognized client (the client profile the request matched, with its version), Client ID, IP, the user agent with its Device type (for example desktop, mobile, tablet, bot or AI agent), location and connection details. |
The freshness timeline draws the entry’s life with two markers: At this request and Now.
The figures under it are read at the request, not at the moment you look: Status (Fresh,
Stale or Expired), Age, and TTL left, or for a request served stale, Stale for,
how far into the stale-while-revalidate window it was served, out of the whole window. A MISS
that stored the entry reads Fresh with an age of 0s. Then the instants (Stored,
Served, Stale from, Expires) and the policy. A STALE request also says what happened
to the entry: that this request refreshed it in the background, from your origin or through the
shield, or that it started no refresh of its own, which is the case when another request is
already refreshing the entry.
Several fields carry an action: filter the list by this value, or purge. The panel header
offers Ask support, which opens a support request with the entry’s ids attached, and
Purge this request, on every tab. The Cache tab offers Purge this cache key, and each
surrogate key (or a whole level of them) can be purged on its own. The GraphQL tab purges
the operation, with these variables or with every variable set. Without the cache:purge
permission the purge controls are not shown. See Purges.
The panel does not show the warnings and errors GraphPilot writes as log
lines. Read them through the API’s Service.logs with the
request’s Entry ID as requestId (see the API).
A cache hit links to the request whose miss stored the entry it was served from.
With shielding, request telemetry records how the hop to the
shield went (a hit, miss, stale entry, pass, fallback, timeout, or unavailable for a mutation) alongside the entry’s own
status, so you can tell a hit the requesting location already had from one it fetched from the
shield. The hop to the shield is part of the same request: Insights records it once and counts it
as one request. Usage is counted in request units instead: by
response size, at every edge location a request passed through, with a background refresh
through the shield as a request of its own, so the request units for a period are higher than the
request count Insights shows.
The Overview tab shows the hop in its Shield set, and the list can be filtered by
Shield result and show it as a column. When the shield sent the request on to your origin, the
GraphQL tab shows the document your origin received as the shield recorded it, and says so;
the Diff reading compares it with the document the client sent. When the shield answered from its
own cache, the tab says Answered from the shield’s cache and names the shield.
A request the shield sent on to your origin (shield result MISS or PASS) carries the hash of
the document your origin received, so when GraphPilot changed that document the list marks the
request (GraphPilot touched this document) and the Rewritten by GraphPilot filter finds
it, the same as a request that was not shielded. A shield HIT or STALE sent nothing to your
origin and is never marked. Shielded requests recorded before runtime 1.6.0 stay unmarked and do
not match the filter. All of this
reads the same on a request opened from the Requests list and on an operation opened from the
Operations list.
Related
Section titled “Related”- Cache statuses: what
HIT,MISS,PASSand the reasons mean - Debugging surrogate keys
- Telling your clients apart: name your clients so Insights can
- Alerts