Security
I watch your application from the outside, hold as little as I can get away with, and throw most of it away after 30 days.
- EU
- 30 days
- 0
- 2
Security one-pager
Everything on this page, printable, for your boss or your client.
How your data moves
What passes through each step, and when it’s gone.
Side route: an AI request goes to the pinned EU provider, today Azure in the EU, through OpenRouter (US), only when proposing checks or finding a moved element.
When things are deleted
- 30 minA first look without an account
- 24 hA recorder session and its element crops
- 2 weeksRaw visitor-error events
- 30 daysEvery recording and screenshot, on every plan
- 30 daysThe hostnames a recording’s browser opened
- 30 daysEncrypted backups, with a restore checked monthly
Where the infrastructure is
Core infrastructure is hosted in the European Union, and not as a setting somebody could change without noticing: it is where the machines are.
Servers and database
Hetzner, in Germany. Nothing of yours is hosted anywhere else.
Storage
Screenshots, video and traces, in EU object storage, on private buckets reached through one-off URLs rather than with a key.
Email
Sent through Seznam.cz, in the Czech Republic.
Backups
In a separate private bucket on the same EU infrastructure, with separate credentials, encrypted with a key that the rest of the product never holds.
One thing can leave the EU, so I name it.
An AI request is routed as the next section says.
How AI requests are routed
This is a different question with a different answer, so it gets its own heading rather than a clause in the one above.
I use AI in two places only: proposing checks when you add a project, and locating an element as a last resort after deterministic methods fail. For the first I send the server-rendered HTML of your home page and the links on it; when that page arrives empty for a script to fill, I send the HTML, links and accessibility structure a browser read after the script ran instead. For the second I send the screenshot and the page’s accessibility structure and ask where the element went. Nothing else in the product asks a model anything.
I restrict AI inference to the EU regional endpoints pinned below, today Azure in the EU. OpenRouter is the routing layer and is a United States company, so I don’t describe the complete AI path as wholly EU-resident: the request passes through OpenRouter on its way to the pinned provider, with logging switched off on that account.
Right now every pinned provider is an EU regional endpoint, so inference for both of those calls happens inside the EU. That is a property of the list below rather than a promise: pin a provider without an EU region and inference leaves the EU, and this page will say so instead.
Pinned right now
- azure/eu
What holds the model in check
Last resort, optional
Never with a secret
Never the judge
Closed by default
Prompt logging off
I hold no individual written zero-retention letter from OpenRouter or from the inference provider, and I don’t claim one. What I rely on is the request-level instructions above, the logging switch on the account, and the providers’ published retention and training commitments, which I re-read before each deployment. If the pinned provider ever stops meeting them, that AI path stops until a compliant provider is configured; it never falls back to a provider that retains. The whole chain, including who built each model, who routes the request and who runs it, is on subprocessors.
How each run is boxed in
Each check runs in an isolated browser container. It has no access to my database, my storage credentials or my AI credentials. The container is created for one run and destroyed after it, with a read-only filesystem, no extra privileges, a memory limit and a hard timeout, because it opens pages I do not control and some of them will one day be hostile.
It cannot reach my internal network. It fetches its job through a signed channel, writes its screenshots and video through one-off URLs issued for that run, and everything it sends back is treated as untrusted input and validated before anything is stored. The one thing it does hold, for one run, is the sign-in values that run needs, and the next section says how.
Your application credentials
Stored application credentials are encrypted at rest and opened only inside the isolated runtime that needs them. The master key never goes to a runner: a runner receives the ciphertext and the data key of the values the current run references, opens them in memory, and loses them when the container is destroyed. This is envelope encryption with a narrow per-run key, and I don’t call it zero-knowledge encryption, because the control plane holds the master key and that phrase would mean it does not.
Decrypted values are never written to a log, an error record or an alarm. A run that carries a credential or an email step records no video and no network trace at all, is never offered to the visual AI fallback, and sign-in fields are blanked out of any step screenshot I take. I recommend a dedicated account in your application for these checks, with the narrowest permissions that let the check run.
What I keep, and for how long
I keep recordings for 30 days and no longer. They can contain your users’ names and email addresses, and I’d rather not hold that longer than I need to.
That cap is the same on every plan, including the one that keeps a year of history. History is the record of what happened; recordings are the video of it, and a run older than 30 days says the recording is gone rather than showing an empty player. Raw visitor-error events go after two weeks, a run started from the landing page without an account within 30 minutes, together with any picture a browser took of the page for it, and a recorder session with its element crops within 24 hours. The hostnames a recording’s browser opened stay for 30 days, without the pages or anything typed, so that I can answer a complaint that it was misused. The privacy notice has the full table.
Backups and an outside check
The database is backed up daily. Backups are encrypted separately, with a key that only the backup process holds and this website never sees, retained for 30 days, and restoration into an empty database is verified automatically every month. An upload that was never restored is not counted as a backup: only a proven restore is. A production deployment refuses to start without that key, so there is no production configuration of this product that runs without backups.
An outside service asks every five minutes whether this installation answers. It sees the health endpoint and nothing of yours. Its health may differ from the public production status.
What I never get
Your database. Outside checks need nothing installed, no agent on your servers and no connection into your infrastructure. I read your application the way one of your visitors does, over the public internet.
Network traces. I record them for debugging and I never offer them to you for download, because they can hold tokens and other people’s personal data.
Your address, on a session. The IP address and browser identification of a sign-in are deliberately not stored. A run started without an account keeps a keyed hash of the visitor’s address, used only for a rate limit, and never the address itself.
Your visitors’ identity. The optional snippet, for errors and page-load speed, sets no cookie, creates no identifier, reads no storage and sends no form value; the query string and fragment are cut before anything leaves the browser, and I store neither the visitor’s IP address nor the full User-Agent. An error message or a URL path can still carry something your application put there, and I don’t pretend otherwise.
Logging, and what I don’t claim
I don’t log decrypted application credentials, session tokens or secret field values. Links that carry a token, the sign-in link, the ones in an alert email, the one your deploy calls, are stripped out of the access log before it is written. That is a rule about what is written on purpose, not a guarantee that no sensitive value can ever appear anywhere.
I hold no SOC 2 attestation, no ISO 27001 certificate, no HIPAA attestation and no PCI certification of my own; card details are entered on Stripe’s pages and never reach me. I am not “GDPR certified”, because no such certificate exists, and the subscription includes no contractual uptime percentage or service credits. What is on this page is what I actually do, and it is what you may rely on.
Signing in
A one-time link in an email. There is no password to lose. The session lasts seven days and is refreshed while you use the product.