Privacy & data flow
Test results are unusually revealing: they carry your source paths, error messages, screenshots of your app, network calls, and sometimes your git history. That's a good reason to know exactly where the bytes go. This page is the inventory.
The short version: Piwi makes no outbound network call you didn't configure. There is no telemetry, no usage analytics, no update check, no crash reporting, and no license or activation call. An instance running on an air-gapped network works the same as one on the internet.
What leaves your server
Every outbound connection Piwi can make is something you switched on:
| Destination | When | Carries |
|---|---|---|
| Your AI provider | Only if you configure AI diagnosis | The diagnosis context: error text, failing steps, the relevant git diff, and — if enabled — failure screenshots |
| Your git host | Only if you connect a repository with a token | API reads: commits and diffs for the project's repo |
| Your SMTP server | Only if you configure email notifications | Notification and account emails |
| Your Slack / webhook URLs | Only for subscriptions you create | The event payload (run status, cluster, test names) |
| Your S3 endpoint | Only if you switch storage to S3 | Trace files, HTML reports, attachments |
| Google / GitHub | Only if you enable OAuth sign-in | The standard OAuth exchange |
Nothing on that list has a default. With none of them configured, a Piwi instance talks to nobody.
The AI provider is the one worth pausing on, because it's the only case where your code and error text can leave your network. It's opt-in, it goes only to the endpoint you set — including a local model over Ollama or vLLM, in which case nothing leaves the machine at all — you can preview the exact context before it's sent, and you can cap its size. See AI diagnosis → Privacy.
What never leaves your server
- Traces. The Playwright trace viewer is bundled and served by your own instance at
/trace-viewer/. Opening a trace from Piwi never uploads it anywhere — unlike sending a colleague to the hostedtrace.playwright.dev. - The API reference.
/docsis rendered in-app from your instance's own OpenAPI spec, with no third-party CDN, so it works offline. - Screenshots, videos, HTML reports. Stored on your disk or your S3 bucket, served by your instance.
- Your IDE mapping. The Open in IDE workspace root lives in your browser's local storage, because the source is on your machine, not the server's. It is never sent to the dashboard.
What Piwi deliberately does not capture
Some data is skipped at the source, so it never exists to leak:
- Input values. The capture fixtures record what an element is — role, accessible name, test id — never what was typed into it. A password field's value is never captured.
- Storage and cookie values. Page state records the names of
localStorage/sessionStoragekeys and their value lengths, and cookie names with their flags. Never the values. - Sensitive headers.
Authorization,Cookieand friends are masked server-side in the trace network view, and token-shaped strings in URLs and bodies are masked too — so a bearer token that appeared in a request doesn't end up readable in the dashboard. - Backend logs, in production. The backend-log integrations emit their header only in development and test environments by default.
Secrets at rest
Credentials you store in the dashboard — AI API keys, SCM tokens, webhook signing secrets — are encrypted with AES-256-GCM using PIWI_SECRET_KEY. Set it in production. With the variable unset, Piwi falls back to a hardcoded default string that is published in this repository — the values are encrypted, but against a key anyone can look up, so treat that as no protection at all.
node -e "console.log(require('node:crypto').randomBytes(32).toString('hex'))"API keys are stored as SHA-256 hashes and shown exactly once, at creation. A leaked database gives an attacker no usable key.
Secrets provided by environment variable are never written to the database and never returned by the API — the settings UI shows them as read-only with a lock badge.
The demo
The live demo has no backend. It runs the real application against an in-browser SQLite database seeded with fake data, inside a service worker. Nothing you click there reaches a server, and there is nothing for it to collect.
Retention
Data you keep is data you're responsible for. Piwi can prune it for you: set PIWI_RETENTION_DAYS for nightly automatic pruning of old runs and their files, or delete in bulk from Settings → Storage. Deleting a run removes its executions, traces, reports, and any evidence payloads no longer referenced by anything else. See Storage → Data retention.
Verifying any of this
You don't have to take the page's word for it. The source is MIT-licensed and the outbound surface is small enough to audit: watch the container's egress, or read server/utils/ — the AI provider, SCM, SMTP, storage and notification clients are the only things there that open a socket.
See also
- Authentication — roles, API keys, and project-level access
- Deployment → Security — hardening a public instance
- Why Piwi? — the same question, short form