Skip to content

Privacy and personal data

This page is the overview for a data protection review: what GraphPilot records about a request, where and for how long, what your origin receives, and each setting that reduces it. Every section links the page with the detail.

Everything configurable here is per service, in gpilot.toml, and applies from the next deployment. None of it changes what is billed.

Every request a service serves is recorded in Insights, unless telemetry.record leaves it out. A recorded request keeps:

CategoryWhat is keptCan be reduced with
Client addressThe IP address as the edge saw it, plus the location and network data looked up from it: country, region, city, latitude, longitude, postal code, ISP and ASN.telemetry.client_ip
ClientThe User-Agent and the device type derived from it, and the client profile the request matched.telemetry.record, to leave such requests out
RequestMethod, hostname, path, size, and the correlation ID the client sent.Not configurable
HeadersOnly the headers the [telemetry.headers] lists name. By default authorization and cookie are stored as a keyed digest and only a handful of descriptive headers in clear.[telemetry.headers]
GraphQLThe operation name and type, the query document, a hash of the document, and the GraphQL errors your origin answered with (message, path and code). Variable values are not stored: the request keeps a keyed hash of them.Not configurable; see the note below the table
CacheThe cache status and key, the surrogate keys of the response, and the segment values that partitioned it: a vary rule’s value as a keyed pseudonym by default, the private and public values always as a keyed digest.telemetry.vary_values, pseudonymize
ResponseStatus, size, latency and the recorded response headers. The response body is not stored.[telemetry.headers]

The warnings and errors the edge writes for a request are kept as its log lines. A log line carries the request’s id and the correlation ID the client sent, but no client address, location, User-Agent or client profile; those are kept with the request only. The full list of what each tab of a request shows is in the request detail panel.

Where it is stored: request telemetry and log lines are kept in the EU, for at most 90 days. Cached responses are a separate question: they are held in the edge cache wherever they were requested, with no region pinning. See where data lives.

The [telemetry] section decides what is stored, without changing how a request is served or cached. The full reference is [telemetry].

KeyDefaultDoes
recordunset (record everything)Which requests are recorded at all. "false" records nothing. A request left out is still served, billed and counted.
client_ip"full""truncated" keeps the network part of the address and drops latitude, longitude and postal code; "none" stores no address and no region or city.
vary_values"pseudonymized""clear" stores every vary rule’s value as derived, instead of a keyed pseudonym.
[[telemetry.headers.*]]narrow listsWhich headers are recorded, and which are stored as a keyed digest (sanitize) or left out (exclude).
gpilot.toml
[telemetry]
# Leave the cluster's health probes out of Insights.
record = "!starts_with(header:user-agent, 'kube-probe/')"
# 203.0.113.77 is stored as 203.0.113.0.
client_ip = "truncated"
# The default, stated so a review can see it.
vary_values = "pseudonymized"

vary_values = "clear" is an explicit choice for the whole service: a rule whose value is a session cookie, a token or an email address then stores that value in clear, and the header sanitize rules do not cover it. See vary values.

A header list you write replaces the default one entirely, its sanitize rules included, so put authorization and cookie first. See [telemetry.headers].

pseudonymize(s) replaces a value with a keyed pseudonym before the cache, your origin or your telemetry see it. It is accepted in cache.policy.public, cache.policy.private and a vary rule’s value. Equal inputs give equal pseudonyms within the service, so the partition still groups the same callers:

gpilot.toml
# The organization stays readable, the user id never leaves the edge.
[[cache.policy.vary]]
name = "x-user"
value = "auth:idp.org_id + ':' + pseudonymize(auth:idp.sub)"

Under the default vary_values = "pseudonymized", Insights shows a pseudonym either way; pseudonymize then decides what the cache partitions on and what a plain origin receives. Under vary_values = "clear", it decides which part of a value is readable. See keeping identifiers out of Insights with pseudonymize.

Your origin receives the request as the client sent it, with these exceptions. See request headers your origin receives.

WhatBy defaultChange it with
The client’s IP addressNot sent.origin.forward_client_ip = true sends it in gp-client-ip.
Forwarding headers a client sent (X-Forwarded-*, Forwarded, X-Real-IP and others)Removed.origin.forwarded_headers = "pass"
A vary rule’s derived valueNot sent.pass_to_origin: "anonymized" sends a keyed v1= digest, "plain" the value itself.
Any other header or cookie, Authorization includedSent unchanged.[origin.headers] and [origin.cookies] hide or only lists.
gpilot.toml
# The origin learns a stable, opaque id per shopper, and never sees the token.
[[cache.policy.vary]]
name = "x-shopper"
value = "pseudonymize(auth:idp.sub)"
pass_to_origin = "plain"
[origin]
headers = { hide = ["authorization"] }

A filter in [origin.headers] applies just before the request is forwarded, after the credential was verified and the cache key was built. With the credential hidden, have your origin check the request signature to know a request came through GraphPilot.

pseudonymize, a vary rule’s pass_to_origin and telemetry.vary_values act one after the other, each on the result of the one before:

  1. The rule’s value is derived. pseudonymize replaces its argument right there, so the derived value already holds the pseudonym. The cache key is built from this derived value.
  2. The origin receives it as pass_to_origin says: "plain" sends the derived value, "anonymized" a keyed v1= digest of it, "never" nothing.
  3. Insights records it. A rule at "anonymized" records exactly the v1= value the origin received, whatever vary_values says. A rule at "plain" or "never" follows vary_values: "pseudonymized" (default) records hmac-sha256: and 16 hex digits of the derived value, "clear" the derived value itself. private and public values are always recorded as a keyed digest.

For a vary rule with value = "pseudonymize(auth:idp.sub)":

pass_to_originvary_valuesThe origin receivesInsights records
plainpseudonymizedThe pseudonymA digest of the pseudonym
plainclearThe pseudonymThe pseudonym
anonymizedeitherA v1= digest of the pseudonymThe same v1= digest
neverpseudonymizedNothingA digest of the pseudonym
neverclearNothingThe pseudonym

Hashing a pseudonym a second time is harmless: both steps are deterministic and use the service’s key, so segments group and the cache hits exactly as with one step, and no clear value appears anywhere. It also adds nothing. pseudonymize earns its place in two cases:

  • With pass_to_origin = "plain", when the origin needs a stable value per user without learning who the user is.
  • With vary_values = "clear", to keep one part of a value readable, such as the organization, and hide the rest.

With "anonymized", or with the default vary_values and a rule at "never", it is redundant.

WhatHow long
Request telemetry in Insights1 day on Glider (Free), 7 days on Jet, 30 days on Airliner, 90 days on Jumbo. The GraphQL errors of a request go with it; error groups and filter suggestions are deleted once they have not occurred within the plan’s retention. See what Insights needs.
The raw telemetry copyAt most 90 days per file, in the EU, used only to rebuild Insights. See the raw telemetry copy.

To delete earlier:

  • Reset history. An Admin can delete a service’s request telemetry, purge history and alert history at any time in the portal, under Settings → General, without deleting the service. The request counts billing is based on and every invoice are kept. See reset history.
  • Delete a service, an organization or your account. Its telemetry, logs and stored files stop being readable at once and are deleted within minutes, once each service is off the edge. See delete the service, delete an organization and delete your account.

A deletion or a reset keeps some records on purpose: the billing and invoice history, the record of the accepted terms, the raw telemetry copy and backups until they expire. The full list is what a deletion keeps.

  • telemetry.client_ip = "truncated" or "none".
  • telemetry.vary_values left at "pseudonymized".
  • telemetry.record leaves out traffic you do not need, such as health probes.
  • Every replaced header list starts with the sanitize rules for credentials.
  • Personal parts of a partition value wrapped in pseudonymize.
  • Vary rules at pass_to_origin = "never" or "anonymized", unless the origin needs the value.
  • origin.forward_client_ip left off, unless the origin needs the address.
  • Personal values sent as GraphQL variables, not written into the document.

The worked example, with what Insights then shows, is keeping request telemetry minimal.

What a service records and passes on follows from its configuration, and the responsibility for that configuration, such as choosing vary_values = "clear", lies with you. How GraphPilot processes personal data on your behalf is set out in the data processing agreement.