Skip to content

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

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:

PlanRequest 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.

TabShows
RequestsEvery HTTP request to the service, GraphQL or not.
OperationsEvery 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.

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.

The Latency figure shows one statistic of one part of the time a request took. The menu in its header picks both:

PartMeasures
TotalClient to response.
EdgeEdge processing (total minus origin).
OriginEdge 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 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.

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.

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.

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 (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
GroupPresetKeeps
ErrorsErrorsRequests that failed: a 4xx or a 5xx, or a response with at least one GraphQL error.
Server errorsRequests that failed with a 5xx.
Client errorsRequests that failed with a 4xx.
Auth failuresRequests answered 401 or 403.
Rate limitedRequests answered 429.
Gateway timeoutsRequests answered 504.
GraphQL errorsResponses that carried at least one GraphQL error. Also listed under GraphQL.
Masked origin errorsRequests your origin answered with an error while the client still got a status below 400. Also listed under Origin.
Errors hidden from clientGraphQL errors the edge removed before the client saw them.
CacheCache hitsRequests answered from a fresh cache entry.
Cache missesRequests the origin answered and the cache stored.
Not cachedRequests nothing was stored for: the cache was not used, or the response was not stored.
Stale servedRequests answered from a stale entry.
Queries not served from cacheQueries your origin answered: a cache miss, or nothing was cached.
Private responsesEntries stored for one caller only.
Vary-segmentedEntries shared within one segment of callers.
PerformanceSlow requestsRequests that took 1s or more in total.
Slow edgeRequests with an edge latency of 100ms or more.
Large requestsRequests of 100 KiB or more.
Large responsesResponses of 1 MiB or more.
GraphQLQueriesEvery query, cached or not.
MutationsEvery mutation, cached or not.
Non-GraphQL requestsRequests that carried no GraphQL operation.
Anonymous operationsGraphQL operations with no name: the request sent no operationName and the document does not name the operation either.
Persisted queriesRequests that sent a persisted query hash instead of a document.
Rewritten by GraphPilotRequests whose document GraphPilot changed on its way to the origin.
OriginServed without originRequests a cache answered, at the edge or at the shield, without calling the origin.
Slow originRequests the origin took 1s or more to answer.
Origin retriesRequests the edge had to send to the origin again.
Origin failuresOrigin calls that failed without a response.
Rejected at the edgeRequests the edge refused before they reached the origin.
ClientMy requestsRequests sent from this browser’s address.
Desktop requestsRequests from desktop devices.
Mobile requestsRequests from phones, tablets included.
BotsRequests from crawlers, downloaders and feed readers, AI agents not included.
AI agentsRequests from AI crawlers and from assistants fetching for a user.

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.

Select a row to open the request, or operation, in a panel beside the list. It has four tabs:

TabShows
OverviewThe 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.headers]. 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.
GraphQLThe 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.
CacheThe 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_SKIPPED_SHIELD_RESPONSE_NOT_STORABLE (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.
ClientRecognized 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.