Vigil

Privacy Policy

Last updated: 5 October 2026

Vigil sits in the path of your AI API calls, so the only honest place to start is what we can see and what we keep. This page answers both — and for the records the proxy keeps of each call and of each request it refuses or cannot complete, it answers at the level of individual database columns. Where the answer is uncomfortable, or where we do not yet know, it says so instead of rounding.

1.Who we are and how to reach us

Vigil is operated by Evolmet B.V., a private limited company (besloten vennootschap) registered in the Netherlands. These are the details a supervisory authority, an OAuth reviewer, or your own vendor due-diligence process will ask for, so they are stated here rather than left to be requested:

IdentificationAs registered
Legal nameEvolmet B.V.
Trade register (KvK)42006185
Registered addressSaturnusstraat 95, 2516 AG ’s-Gravenhage, Netherlands
VAT numberNL869250759B01
Contactsam@vigil.wtf

Which role we occupy depends on which data you mean, and this policy never blurs the two. Evolmet B.V. is the controller for your account data — how you sign in, what plan you are on, your settings — and decides why and how that is processed. For the telemetry produced by the AI traffic you route through the proxy, Evolmet B.V. is a processor acting on your instructions, and you are the controller. Section 2 sets out the split in full; the Article 28 terms for the processor half are in the Data Processing Addendum.

Vigil is an AI-observability service. It has two parts: a dashboard at vigil.wtf and a proxy at api.vigil.wtf that sits in the path of the AI API calls you route through it.

For anything in this policy, and to exercise any right described in section 11, email sam@vigil.wtf. That is a monitored mailbox and the only channel — there is no separate privacy address to work out, deliberately.

We have not appointed a Data Protection Officer. On our reading of Article 37 one is not required — there is no large-scale processing of special-category data and no systematic monitoring of a public area — but that reading has not been confirmed by a lawyer, and section 19 lists it as open rather than settled.

2.The two data flows, and our role in each

Vigil holds two different kinds of data and occupies a different legal role in each. This distinction shapes everything below it, so it comes first.

The dataYou areWe are
Your account — how you sign in, what plan you are on, your settingsThe data subjectThe controller
Telemetry about the AI traffic you route through the proxyThe controllerA processor acting on your instructions

What that means in practice. For your account, we decide why and how the data is processed, and this policy is our disclosure to you. For the traffic you send through the proxy, you decide what goes through it. If your prompts carry personal data belonging to your own users, that is your decision and your lawful basis to establish; we never determine the purpose of it. The Article 28 terms for that relationship are in the Data Processing Addendum.

3.What we hold about you

From signing in

Authentication runs on Supabase Auth. You can sign in with an email address and password, or with GitHub or Google. If you use one of those providers, Supabase stores the profile fields the provider returns — which is more than Vigil itself uses:

StoredWhere it comes fromWhat Vigil does with it
Email address, and whether it is verifiedYou, or your GitHub/Google profileIdentifies your account; the only field the app itself reads
Name, full name, usernameYour GitHub or Google profileNothing. Stored by Supabase Auth as part of the sign-in record; no Vigil screen displays it
Avatar or profile picture URLYour GitHub or Google profileNothing. Same as above — it is a link to an image on the provider, not a copy of it
Provider account identifierGitHub or GoogleLinks your sign-in to the same account next time
A Vigil user id (a UUID we generate)UsEvery row below is keyed on it
Account created, last signed inUsSupport and abuse investigation
The IP address and browser of each signed-in session, and a log entry for each sign-in, sign-out and session refreshSupabase Auth, from the requests that sign you in and keep you signed inNothing. No Vigil screen reads them. Section 8 says where Supabase keeps them and for how long
The campaign that brought you, if anyThe link you arrived onTells us which marketing actually works. Four values — source, medium, campaign, content — taken from the signup URL. No click identifier and nothing that ties you to an advertising account. If you arrived directly, the record exists with all four values empty

We are listing the name and avatar fields even though nothing in Vigil reads them, because they are held and you are entitled to know that. If you would rather they were not, sign in with email and password instead of a provider.

From using the product

StoredDetail
SettingsTheme, notification preferences, your plan; for each agent and each optimisation, the mode you chose, its options (for prompt caching, the cache lifetime; for history trimming, how many recent turns it keeps), and when you switched it on and last changed it; your account-wide default for each optimisation, if you set one — its mode, its options, and when you switched it on and last changed it; for each agent you stopped with the kill switch, when you stopped it; and, for an optimisation that can change answers, per agent: the share of conversations it is tried on, when it first ran in Shadow mode and when Vigil last checked the trial — which Vigil records itself — and, when a trial did worse than the calls it is compared with, when Vigil set its share to zero and why, from a fixed list — with when its share, its first Shadow day or a stop last changed, how many times they have changed since it was created, and whether the alert for a stopped trial is still to be filed
API key recordsA SHA-256 digest of each key, a short display prefix, the label you gave it, and timestamps. The key itself is shown once and never stored — we cannot recover one for you
Billing identifiersYour Stripe customer and subscription ids. Card details never reach us; see section 12
Alert rulesAny monitoring rules you configure
Team invitationsThe email address you invited, its role and status
Feature waitlistThe email address you enter when asking to be told about a feature that is not built yet
Plan code redemptionsIf you redeemed a code, the fact that you did
Monthly usage meterPer calendar month: how many calls we counted toward your plan, how much optimised spend they represented, and when that count last changed. Optimised spend is kept two ways. The first is the bill, for the calls Vigil’s cache markers optimised. The second, where the meter counted it, covers every call an optimisation changed: its bill plus the saving Vigil measured on it. That figure is never less than zero and never an estimate — what history trimming or model routing may have saved is not counted. Beside it, for each month, one SHA-256 checksum per optimised prompt shape, made from two of the section 4 fingerprints, which is how your plan’s optimised-agent limit is counted; and, if the meter ever failed to count a call, or to count the optimised spend of a call it counted, a note of that call’s id, the database’s error message and when it happened. No prompts, models or agent names. It only counts upward; see section 11 for why it is not cleared with your history

4.What the proxy records about each call

One row per call you route through api.vigil.wtf — until your plan's monthly logged-call volume is used up, after which a call is still forwarded and counted but not logged. This is the complete list of what that row contains.

Usage and cost

  • Input, output, cache-read and cache-creation token counts, the input-plus-output total, and how much of the cache creation was for the one-hour cache lifetime
  • Cost in USD, and the cache-read ratio
  • How many web searches the provider billed on the call; when the call used advisor, fallback or compaction steps, how many billed model steps the provider reported, the model’s own turns included; and how much the searches and those extra steps added to the cost
  • Latency in milliseconds
  • Model and provider names. A model id is kept as the provider or your request gave it, so it can carry your cloud account number or organisation name — an AWS inference-profile ARN or an OpenAI fine-tuned model id, for example
  • How the call was priced, where recorded: the platform that served it and that platform’s own id for the model, whether it went to a global, regional or multi-region endpoint, the billing mode (for example on-demand or batch), whether the prompt was long enough to fall in a long-context price tier, and the evidence behind the rate — for example VERIFIED, read off the provider’s own price list
  • Success or error status; the error type when one occurred; and the names of any problems our detectors found on the call, even a successful one — for example pii_leak or cost_spike — never the evidence
  • The HTTP status code the provider returned — or, for a call Vigil refused, the one Vigil returned
  • The provider’s own error code when a call failed — for example authentication_error — drawn from a fixed list we recognise, or the word “unrecognized”
  • When we can tell why a call failed, a one-sentence reason in our own words, from a fixed list — for example “The provider rejected the API key as invalid”. Never the provider’s wording.
  • What the call would have cost without Vigil’s cache markers, and the difference from the bill — the saving, which can be negative; for an agent with prompt caching in Shadow mode, Vigil’s estimate of that saving; and a short code when a saving could not be worked out. Where recorded, when an optimisation changed the call, what it would have cost without Vigil’s changes — Vigil’s estimate where history trimming changed it; the bill alone where a saving could not be worked out; zero where the bill itself could not be — and zero when no optimisation changed the call

Fingerprints of your prompt shape

  • prefix_hash, system_hash, tools_order_hash — 8-character FNV-1a checksums
  • An estimated token length for the cacheable prefix
  • On OpenAI-compatible providers, where recorded, the cache key Vigil sends — or, in Shadow mode, would send — so the provider can reuse its cache: two more checksums of the same kind, one of the model with your system messages and one of the model with your tool definitions

Prompt structure — counts, lengths and a yes/no flag, plus two fragments kept verbatim: tool names and a timestamp excerpt

  • The character LENGTH of your system prompt
  • The NUMBER of tools on the request
  • The NAMES of your tools
  • Whether a timestamp was detected in the prefix
  • If one was: a short excerpt of that timestamp, capped at 32 characters
  • The token offset of your first cache marker, and the model’s minimum cacheable length

Labels and identifiers

  • The id of the Vigil account the call belongs to
  • The agent label you supply in the X-Vigil-Agent header
  • Whether the call presented a Vigil API key, and what the check found: valid, missing, not found or revoked, belonging to a different Vigil account, or the check itself failed
  • A row id and a timestamp for the call itself, and — when there was one — the request id we returned to you in the x-vigil-request-id response header: a random identifier we generate when the request arrives, so you can find the call later
  • Whether the call is Vigil’s own test traffic, decided from a fixed list of Vigil’s test agents and accounts
  • The path you called on the provider, as you sent it, never the query string — for example v1/messages. It can name your Google Cloud project and region (Vertex AI); your AWS region and model, or an inference-profile ARN that includes your AWS account number (Bedrock); or a provider’s id for a batch or a file
  • Where recorded, an identifier for the provider-side cache the call could use, which keeps one credential’s cache apart from another’s. For Google Vertex AI it is your Google Cloud project id and location, in clear. For other providers it is a one-way digest of the provider credential the request carried — on Bedrock, with the AWS region in clear — never the credential itself. The digest is two 8-character FNV-1a checksums, not encryption: it cannot be turned back into the credential, but someone who already had your API key could confirm the match, and the same API key always gives the same digest
  • Three fields reserved for a session id, a parent-call id and a trace id, which the proxy does not write. The only rows with a value in them are Vigil’s own test traffic from June 2026, each holding a random session id

Cache decision metadata

  • The cache lifetime chosen, the estimated cached span, and how many cache markers were placed
  • Where the cache markers went — the system prompt, the messages or the tools — whether the cached span stopped at a timestamp, and whether your system prompt was sent as plain text
  • Whether the call qualified for Vigil’s caching and, when Vigil did not add cache markers, why not, from a fixed list — for example your request already carried its own, part of the prompt changes on every call, the prompt was shorter than the model’s minimum, the provider caches automatically, the request was signed with AWS SigV4 so it could not be changed, or the step failed — and a broader label for that reason, such as whether it would resolve itself as the prompt grows or needs the prompt to change; with the figures behind that decision: the span measured, the model’s minimum and the model it came from, which part of the prompt changed, how much text came before a timestamp, the shape of the system prompt, and the kind of AWS credential used
  • On OpenAI-compatible providers: how the provider caches, where Vigil puts its cache key — a field in the request or a header — whether Vigil asked the provider to report token usage on a streamed call and, if not, why not, and pricing notes: why a call could not be priced, the price-list entry it was priced as when that differs from the model’s name, and whether a cache saving can be shown for that model
  • For an agent in Shadow mode, what the saving estimate rested on: the typical gap between the calls it was compared with, this one included; roughly how many calls one cache write would serve at that pace — the cache lifetime divided by that gap, capped at 10,000; how many earlier calls from the past seven days it drew on; and the span it assumed would be cached

Optimisation decisions, trials, and how the response ended

  • For each optimisation, the mode you set and the mode actually applied to the call — and, where recorded, whether the setting came from the agent, from your account default, or from Vigil’s default of Off when neither was set, and why the applied mode was lower than the one you set, from a fixed list (for example: your request switched it off with X-Vigil-Optimise or X-Vigil-Skip, your plan’s limit applied, the provider does not support it, Vigil could not verify your Vigil API key on the call, the call fell in the group a trial is compared with, or the optimisation had not yet run a full day in Shadow mode)
  • Whether Vigil added cache markers to the call, and whether your request already carried its own; and, where recorded, what each optimisation did — changed the request, would have changed it (Shadow mode), decided not to, failed and let the request go on unchanged, or did not run
  • Where recorded, for each optimisation, the saving attributed to it, whether that figure was measured or is Vigil’s estimate — Shadow mode is always an estimate, and so is what history trimming saves in On — and a short code when it could not be worked out
  • For an optimisation that can change answers — history trimming or model routing — where recorded: whether the call fell, or in Shadow mode would have fallen, in the group the optimisation is tried on or in the group it is compared with; the share of conversations set to be tried at the time; and, for each such optimisation, a number from 0 to 9,999 that decides the group and lets a trial count conversations rather than calls. It is the same on every call that shares the conversation’s first user message — or its X-Vigil-Conversation header, when you send one — and the agent label. Vigil works it out in memory from your account id, that label and that message or header; neither the message nor the header is written down. The number cannot be turned back into either, but someone who already had your account id, the label and a message could confirm the match — and with only 10,000 numbers, many messages share each one
  • Where recorded, how the model’s response ended, from a fixed list — it finished, stopped at a token limit, stopped to call a tool, stopped at a stop sequence, refused, was blocked by a content filter, or other — how many tool calls it made, how many tool calls it attempted with arguments that were not valid JSON, and whether it was refused or blocked. Never the arguments themselves, and never the words of a refusal
  • For history trimming, where recorded: how many recent turns it keeps, how many earlier turns and messages it dropped — or, in Shadow mode, would have dropped — and an estimate of how many tokens they held; when it dropped none, why, from a fixed list — for example a cache marker sat on the part it would drop, the conversation carried the model’s thinking, the conversation was too short, or the request was too large to examine; and, on providers that cache automatically, whether the provider’s cache reached past that part and what dropping it would have saved
  • For model routing, where recorded: the model it would have chosen for the call and the model your request asked for; the size band and the tool-count band of the conversation’s opening — its system prompt, tool definitions and first message — and the opening’s length in characters, never its text; the routing level the agent was at, and the lowest level that would route the call; the estimated saving, and how much prompt-cache saving switching models would give up; when it would have kept the model your request asked for, why, from a fixed list — for example the model was pinned, the request needed something the cheaper model lacks (and what, from a fixed list), or the opening’s bands are above the agent’s level. The models it chooses between are the one your request asked for and cheaper ones from the same provider: the next one down, and any further down you allow; like any model id, the one your request asked for can carry your cloud account number or organisation name. The choice depends on the conversation’s opening, not its later turns, so every call of a conversation gets the same answer — except a call the cheaper model could not take

Scores you send. When we accept a score you send for a call — a whole number from 1 to 5, posted to /v1/feedback with the request id we returned in the x-vigil-request-id header — we keep it in a record of its own: the account it belongs to, that request id, the score and when it arrived. A later score for the same request replaces the earlier one. Nothing else you send with it is kept. We do not use scores for anything other than comparing the calls an optimisation changed with the calls it did not. They are part of your call history: Delete all data removes them with it, and so does deleting your account.

The agent name is a label you choose and send in the X-Vigil-Agent header. If you put something identifying in it, we store what you sent.

5.What we never store

There is no database column for any of the following, so this is a statement about the schema rather than a policy we apply to it:

  • Your prompt text, apart from the tool names and timestamp excerpt disclosed separately
  • Your message content
  • The model’s responses
  • Your tool call arguments
  • Your tool schemas, or your tool descriptions beyond a timestamp excerpt
  • Your tool results
  • The text of a provider’s error message

Your prompts and the model's responses are not stored. No message bodies, no system prompts, no completions, no tool arguments or results. The proxy reads the request in memory to do its job (section 7) and writes only what this page lists: the call record and the scores you send in section 4, the detector findings below and the alert Vigil files when it stops a trial, the record in section 8 of a request it refuses or cannot complete, your API key's last-used time, the monthly usage meter, and the trial settings Vigil records itself, both of which section 3 lists in full — with the two exceptions in section 6, which we would rather spell out than let you discover.

Provider error messages are not stored either. When a call fails we record the HTTP status and the provider's machine-readable error code, never the message text. When we can tell why a call failed, we also store a one-sentence reason we wrote ourselves, chosen from a fixed list — the provider's wording is still discarded.

When our detectors find a problem we store the finding, never the evidence. If the model emits personal data, the stored record names the kinds found — for example email, phone — and never the values.

6.The two exceptions: content we do keep

Two things derived from your prompt are stored. Both exist to diagnose caching problems, both apply only to calls to Claude models — sent to Anthropic directly, or through AWS Bedrock or Google Vertex AI — and both are real fragments of what you sent rather than statistics about it. You should learn them here rather than from a schema.

1. The names of your tools, verbatim. Not their descriptions, input schemas, arguments or results — the names only, in the order you sent them, because reordering tools silently destroys your cache and we cannot tell you that without knowing the order. If your tool names are themselves sensitive, treat them as visible to us.

2. A short excerpt of any timestamp we detect, capped at 32 characters. A clock or date inside the cacheable part of your prompt rewrites it on every call and destroys the cache — the most common and most expensive mistake we see. To show you exactly what to move, we keep the matched substring and nothing around it. We look for this in your system prompt and your tool descriptions; we never scan your user messages for it. In practice it looks like 2026-08-31T14:22:04Z or Current date:.

On the fingerprints

We also store three short checksums of the cacheable part of your request — one of the system prompt, one of the tool ordering, one of both together. They are 8-character non-reversible hashes, used only to compare calls with one another — whether two share a prefix, the same system prompt or the same tool names — for example, to find why a cache was missed, or to count the optimised prompt shapes your plan's limit applies to (section 3). They are not encryption and we cannot recover your prompt from them, but they are derived from it: two identical prompts produce identical hashes. On OpenAI-compatible providers, the cache key section 4 lists is two more checksums of the same kind, of the model with your system messages and of the model with your tool definitions.

7.What happens in memory and is never written

The proxy reads your full request in transit. It has to. It parses the request body to find the cacheable span of your prompt and place cache markers — and, where history trimming or model routing runs for an agent, to tell which conversation the call belongs to, which earlier messages trimming would drop, and, for routing, how long the conversation's opening is, how many tools it defines, and whether the request needs something a cheaper model cannot handle (such as images, documents, certain tools, structured output, extended thinking, or more input or output than it supports). It scans the model's response for personal data the model produced itself so it can warn you, and, where Vigil records how a response ended, reads it to see how — whether it finished, stopped at a token limit, was refused, or called a tool with arguments that are not valid JSON. This happens in memory, for the duration of the request, on Cloudflare's edge network.

None of that content is written to disk by us. What persists is what this page lists: the call record and the scores you send in section 4, the detector findings in section 5 and the alert Vigil files when it stops a trial, the record in section 8 of a request we refuse or cannot complete, your API key's last-used time, and the usage meter and the trial settings described in section 3 — with the two exceptions in section 6. The request is then forwarded to the provider you chose, which receives it in full — that is the point of a proxy, and it is why section 12 lists those providers.

8.Requests we refuse

When we refuse a request — a malformed URL, a rejected API key — or cannot reach the provider or read its answer, or something fails inside the proxy itself, we normally record it in a separate ledger, because there is no model, token count or cost we could record for it and it would otherwise distort your dashboard. That record holds a row id and when it happened; the account named in the address, and that identifier as you typed it, even when it was malformed; the provider you addressed, as you typed it or, once we had recognised it, in lower case; what kind of refusal or failure it was and why; the status we returned; the path as you sent it, without the query string; a truncated diagnostic message; when there was one, the request id we returned to you in the x-vigil-request-id header; and, where recorded, for a request whose Vigil API key we verified while an optimisation able to change answers ran for its agent — in Shadow mode or On, in either group: the agent label you sent, when it is at most 1,024 bytes long, the group the request was in, the conversation's number from section 4, and the mode the optimisation ran in, with why it was lower than the one you set. The identifier, the provider and the path are each cut at 200 characters, and the message at 500.

No record is written when the address names an account id that does not exist, or when the flood limit described below applies: once one IP address — or, for a request that arrives without one, one account identifier as typed — has produced 60 records in an hour, or, for a new one, while the running copy of the proxy that received it is already counting 10,000 others. Each running copy counts on its own. Neither limit holds back the record of a provider failure on a request whose Vigil API key we verified while an optimisation able to change answers ran for its agent.

A request we refuse at the API-key check can also appear in your call history, with no model, tokens or cost, when the account named in its address has created an API key or has settings saved with us — so you can see it where you already look.

The proxy does not store your IP address. It reads it from the incoming connection and uses it only, in memory, to stop a flood of refused requests filling the table. There is no column for it in any table we create.

Supabase Auth does keep IP addresses. It runs sign-in for us, as our processor, and keeps them in three places:

  • Your sessions (the auth.sessions table): one for each browser you are signed in on, with the IP address and browser (user-agent) of its latest sign-in or refresh — your address when your browser made that request, our web host’s when our server made it for you. Signing out deletes every session on your account, and so does deleting your account. If you never sign out, a session can be kept until you delete your account.
  • Its audit log: an entry for each sign-in, sign-out and session refresh, with the IP address, the browser and your email address. None is written to our database (its table there, auth.audit_log_entries, is empty), but every entry also goes to Supabase’s own service logs, which are kept apart from our database, in a region we have not confirmed. We can read those logs for up to 7 days, the period Supabase’s documentation gives for our plan. How long Supabase itself keeps them, we have not confirmed: the period its documentation gives is how long we can read them.
  • Two-factor checks (the auth.mfa_challenges table), each with the IP address it came from. Vigil offers no two-factor sign-in, so signing in to Vigil never makes one.

9.How long we keep it

TODO — not yet finalised

This section needs review before it is relied upon. It states current behaviour, which is not the behaviour the plan tiers describe. Read it as a factual disclosure of a gap, not as a policy anyone has approved.

Stating it plainly: today we keep call telemetry indefinitely, on every plan including Free. No call telemetry has ever been deleted by a retention process. Not on one tier, not partially. The refused-request ledger below is the one exception.

The sweep that would enforce the windows below is written and tested, but two independent safety catches have kept it inert: its schedule was not registered until recently, and the switch that lets it delete rather than preview is not set on the production service. The oldest call telemetry in our database is more than three months old on a tier whose intended window is seven days.

We are not going to publish a retention period we do not enforce. When the sweep is armed we will update this page and the date at the top of it before it first runs, not after.

The windows each plan is intended to carry, once enforcement is switched on. These are targets today, not descriptions:

PlanIntended retention window
Free7 days
Plus30 days
Pro90 days
Supreme365 days
EnterpriseSet per contract

None of the windows above is currently applied. When they are, they will be ceilings we do not exceed rather than promises to delete at a precise moment.

What this means for you right now

  • Your telemetry persists until you remove it. Two controls do work today, immediately and on demand: Delete all data in Settings clears your call and error history, and deleting your account removes everything except the records listed under “What survives a deletion” in section 11. Both are described there.
  • The refused-request ledger is a partial exception. Its seven-day sweep is not behind the same switch: it runs daily and deletes refused-request records once they are seven days old.
  • Account data is kept while your account exists. Two kinds outlive it. The sign-in entries in Supabase's service logs (section 8) stay for as long as Supabase keeps those logs. Billing and accounting records outlive it too: as a Dutch company we are bound by the fiscal retention obligation (art. 52(4) AWR and art. 2:10(3) BW) to keep our books, invoices and payment records for 7 years, counted from the end of the financial year the record belongs to rather than from the date on the invoice. That is a legal obligation under Article 6(1)(c), not a choice we make, and it is why erasing your account cannot erase an invoice we have already issued. It covers the accounting trail only — never your call telemetry, which goes with the account.

11.Your rights, and how to use them

If the GDPR applies to you, you have the rights below. Two of them are buttons in the product; for the rest, email sam@vigil.wtf and we will respond within one month, as Article 12(3) requires.

  • Access (Art. 15) — your call and error history is visible in the dashboard and exportable as CSV from Settings. For anything not on screen, ask us.
  • Erasure (Art. 17) — Settings → Delete account. It is immediate and irreversible; what outlives it is listed below, under “What survives a deletion”. Settings → Delete all data is the narrower version: it clears your call and error history and leaves the account open. Clearing your data keeps the monthly usage meter, by design — see immediately below.
  • Rectification (Art. 16) — your settings are editable in the product. Telemetry is an append-only record of what actually happened and is not editable; if you believe a row is wrong, tell us.
  • Portability (Art. 20) — the CSV exports in Settings are machine-readable and yours to take anywhere.
  • Restriction and objection (Arts. 18, 21) — email us. Where we rely on legitimate interests you can object, and we will stop unless we have compelling grounds not to.
  • Withdraw consent (Art. 7(3)) — we rely on consent for exactly one thing, the advertising cookie in section 16. Withdraw it from Cookie settings in the footer of any public page; it takes effect immediately, and refusing or withdrawing costs you nothing. Nothing else we do rests on consent, so there is nothing else here to withdraw.
  • Complain to a supervisory authority (Art. 77) — you can complain to the authority where you live or work. Ours is Autoriteit Persoonsgegevens.

What survives a deletion, and why

One record is deliberately kept when you clear your data: the usage meter. It holds, per calendar month and keyed to your account id, how many calls we counted toward your plan, how much optimised spend they represented and when that count last changed — with the per-prompt-shape checksums and the notes of calls it failed to count, or failed to count in full, that section 3 lists. It contains no prompts, no models and no agent names.

Why it is not cleared. Plan limits are counted from this meter rather than from your call history, precisely so that deleting history cannot reset them. If the meter followed the history down, “Delete all data” would become a way to reset a monthly allowance and start the month again — once for every customer, every month. The meter only ever counts upward within a period, and a new period starts it at zero regardless.

So Delete all data removes your call and error history and leaves that meter standing. Your plan limits continue to reflect the traffic you actually sent this month. Deleting your account is different: the meter goes with it, because the reason above stops applying the moment there is no allowance left to reset.

Deleting your account leaves two kinds of record behind: billing and accounting records, for the period in section 9, and the sign-in entries in Supabase's service logs (section 8), for as long as Supabase keeps them.

We do not charge for any of this and we will not make you justify the request. If we cannot identify you from what you send us, we may ask for enough to be sure we are not handing your data to someone else.

12.Who else processes it

We use the processors below. Each receives only what it needs. Your prompt and response content reaches only Cloudflare, which runs the proxy and reads it in memory, and the AI provider you deliberately route to — apart from the two fragments in section 6, which are stored with Supabase.

ProcessorWhat it doesWhat it receivesWhere
SupabaseDatabase and authenticationEverything in sections 3, 4, 6 and 8, and the detector findings in section 5; your email and sign-in identity. The sign-in entries in its own service logs (section 8) are kept apart from our database, in a region we have not confirmedCentral EU (Frankfurt) · eu-central-1
CloudflareRuns the proxy at api.vigil.wtfYour full request and response, in memory, in transitGlobal edge network
VercelHosts the dashboard at vigil.wtfHTTP request data for pages you loadGlobal edge network
StripePaymentsYour email, billing name and address, VAT number if you give one, and card details — which go to Stripe directly and never reach usUnited States / Ireland
GitHubOAuth sign-in, only if you use itThat you signed in; returns the profile fields in section 3United States
GoogleOAuth sign-in, only if you use itThat you signed in; returns the profile fields in section 3United States
The AI provider you route toAnswers your API callsYour full request, including anything in your promptsDetermined by the provider you choose
PlausibleCounts visits to the public pages, if analytics is enabledThat a page was loaded, and the fields in section 16 — no cookie, no identifier, no IP address storedEuropean Union
RedditAdvertising attribution — only if you accept advertising cookiesThat a marketing page was visited, and that you created an account if you did. Both are tied to the _rdt_uuid identifier in section 16. A page visit that came from one of our ads also carries that ad click's identifier, _rdt_cid (section 16); the account report never does. No email address, no name, nothing else from the proxy, the dashboard or your account. Nothing at all if you declineUnited States

The last row is the one to read twice. Vigil forwards your request to Anthropic, OpenAI, Google, Mistral or whichever provider you addressed. That provider receives your prompt in full and processes it under its terms, in whatever region it operates. Choosing the provider is your decision and we do not override it. Your relationship with them is yours, and their data handling is theirs to describe.

13.International transfers

Our database and authentication run in the EU — Central EU (Frankfurt) (eu-central-1). That is where your account and your telemetry are stored at rest.

It does not follow that Vigil is EU-only, and we are not going to imply it is. The proxy runs on Cloudflare's edge network, which means your request is processed at whichever location is nearest to the machine making the call. The dashboard is served the same way by Vercel. Supabase keeps its service logs, which hold the sign-in entries described in section 8, apart from our database, and we have not confirmed where. Stripe processes in the United States and Ireland. GitHub and Google process sign-ins in the United States. And the AI provider you route to processes wherever it operates.

One transfer here is yours to switch off. If you accept advertising cookies, Reddit receives your marketing-page visit in the United States; decline, or withdraw later from Cookie settings, and that transfer does not happen at all. It is the only row in section 12 that works that way — the rest are needed to run the service and are not optional in the same sense.

Where those transfers leave the EEA, they rely on the European Commission's Standard Contractual Clauses or an adequacy decision, as incorporated by each provider's own data processing terms. We have not independently audited the transfer mechanism of every provider a customer might route to — section 19 says so rather than implying we have.

14.Security

  • Everything travels over TLS. The proxy refuses plain HTTP.
  • Row-level security is enabled on every table, keyed to your account, so one customer cannot read another's rows through the API.
  • Vigil API keys are stored as SHA-256 digests. A key is displayed once, at creation, and cannot be recovered — if you lose one, revoke it and mint another.
  • Your provider API keys are never stored. A call record can hold a digest of the provider key the request carried (section 4): a short checksum, not encryption — it cannot be turned back into the key, but someone who already had the key could confirm it matches.
  • Card details never touch our servers. Checkout and the billing portal are hosted by Stripe.
  • Prompt and response bodies are never written to disk, so a database compromise does not expose them.

No service can promise it will not be breached, and we are not going to. What we can say is what we hold: your account records and the usage meter in section 3, the call record and the scores you send in section 4, the detector findings in section 5, and the refused-request record in section 8 — the blast radius of a compromise of our database is those records, the two fragments in section 6 included, not your customers' conversations.

15.If there is a breach

If a breach is likely to result in a risk to your rights and freedoms, we will notify the competent supervisory authority within 72 hours of becoming aware of it, as Article 33 requires, and we will tell you directly without undue delay where Article 34 applies. We will say what happened, what data was involved, and what we are doing — not a reassurance-shaped summary.

16.Cookies

We set the cookies needed to keep you signed in. Those are strictly necessary to provide a service you asked for, so they need no permission and you will not be asked about them. There is no session recorder anywhere in Vigil, and the signed-in dashboard sets nothing beyond the session itself — no advertising cookie, no analytics cookie, no tracker.

The public marketing pages can run one more thing, and it is the one we have to ask about: Reddit's advertising pixel. If you accept, it stores an identifier cookie, _rdt_uuid, on this domain, set to expire after 90 days, and a settings entry, _rdt_cfg, in your browser's session storage, which your browser clears when you close the tab. If you came here by clicking one of our ads on Reddit, the address you arrived on carries Reddit's identifier for that click. If you accept while it does, the pixel stores that identifier as a second cookie, _rdt_cid, on this domain, set to expire after 90 days. It holds the click identifier and nothing else, and it tells Reddit which of its ad clicks brought you here. Like the rest, it is never set before you accept. On each page you visit here, the pixel sends a report to Reddit's servers at alb.reddit.com, carrying _rdt_uuid and, if you have one, _rdt_cid. That is how Reddit learns that a visit followed one of our ads, and how it can connect that visit to your Reddit account, if you have one. Until you accept, the script is not loaded and no request is made to Reddit at all. Decline and the page behaves identically; there is nothing behind the prompt that refusing costs you. You can change your answer whenever you like, from Cookie settings in the footer of any public page. Withdrawing removes all of them, _rdt_cid included, and reloads the page, so the script is gone rather than merely told to stop. _rdt_uuid is also what lets us tell Reddit if you go on to create an account — a report sent from our server, described in section 10 — so removing it stops that too. Reddit is a United States recipient — section 12 lists it and section 13 covers the transfer.

We also store your answer itself, as vigil-consent-v1 in your browser's local storage, so that we do not have to ask again on every page. It holds your choice, when you made it, and the version of the question you answered — nothing else. It is strictly necessary — it is what makes a “no” stick — and it is set whichever way you answer.

Analytics is separate, and your answer above does not change it — because there is nothing in it to consent to. The public pages load Plausible, which counts page views and measures how far down a page you scrolled and how long you stayed. It sets no cookie and writes nothing to your device — we tested that in a browser rather than taking it on trust, and that is why it is not part of the prompt above: consent is required for storing things on your device, and this stores nothing. We could have swept it behind the same banner to look cautious, but it would have implied it does something it does not. For what happens at Plausible's end we rely on their published data policy rather than our own testing: no persistent identifier, no tracking between sites, and your IP address used only to derive a country and a daily-rotating hash, never stored. Plausible processes in the EU only, and is listed in section 12.

17.Children

Vigil is a developer tool and is not directed at children. We do not knowingly collect data from anyone under 16. If you believe a child has created an account, email us and we will delete it.

18.Changes to this policy

When this page changes materially we update the date at the top. For a change that reduces your protections — a new processor, a new category of data, or arming the retention sweep in section 9 — we will update the page before the change takes effect, not after.

19.What this page cannot yet answer

TODO — not yet finalised

Listed here rather than answered with a plausible sentence. Each needs a decision or a lawyer, and writing a confident answer we have not verified would be worse than the gap.
  • Whether our role in your telemetry is purely that of a processor. Sections 1 and 2 say it is: you are the controller, we act on your instructions. Section 10 then claims a legitimate-interests basis of our own — Art. 6(1)(f) — for detecting abuse and protecting the service, and a legitimate interest is something a controller asserts, not a processor. Both statements are about the same telemetry, and they sit uneasily together. We would rather you read that from us than find it yourself: we have not picked whichever reading is more convenient, and which one is right for which processing is a question for a lawyer. If you are relying on the processor characterisation for your own Article 28 position, ask us before you do.
  • When the retention sweep in section 9 will be armed, and whether the intended windows are the right ones. Until then, that section describes indefinite retention because that is what happens.
  • Whether a DPO is required under Article 37. Our reading is no; it has not been confirmed.
  • Whether every downstream AI provider's transfer mechanism is adequate. We rely on their published terms and have not audited them.
  • Whether this document satisfies any regime other than the GDPR — CCPA, UK GDPR, or others. It was written against the GDPR only.

If one of these matters to your decision to use Vigil, email sam@vigil.wtf and ask. A direct answer is better than a document that guesses.