What leaves, and when
| What | When | Kept |
|---|---|---|
| A webhook delivery | A sender POSTs to your public channel URL | Until your Mac confirms it; 24-hour ceiling |
| Your license, which contains your email | The ~24-hour entitlement refresh, checkout, and the billing-portal link | Reduced on arrival to a salted one-way hash |
| Your email, if you try Watchflows AI | When you ask for a sign-in link | Kept, to send the link, receipts, and one trial reminder |
| A device code | When you sign in for free Sparks, or ask for a hosted-AI key | A one-way code made from this Mac's hardware ID, so the free Sparks come once per Mac. The hardware ID itself never leaves |
| An error report | Only if you turn on Share error reports | At our error-reporting service (Sentry) |
| Feedback | Only when you press Send in Send Feedback | It becomes an email to support |
| A flow you submit | Only when you press Submit — see Community Flows | Published if a human approves it |
Nothing else. Your flows, runs, canvas, payloads, AI cost history, and provider keys stay here. Hosted AI is not an exception: Watchflows mints a spend-capped OpenRouter key and your Mac calls OpenRouter directly, so no prompt passes through our servers.
Be clear about the second row, because it is the whole identity model. Your license is a signed blob with the purchase email inside it, so each refresh does transmit that address. On arrival it is verified and reduced to a salted one-way hash, and that hash is the only identity we store. If you never try Watchflows AI, there is no account, no signup, and no tracking beyond it. If you do, we also keep the email you signed in with — for the sign-in link, receipts, and one reminder before your trial ends. No newsletter.

An error report carries the error type, node type, app and macOS versions, device model, and a stack trace — never your flows, their data, your scripts, or your prompts. The Privacy pane keeps the newest 200 as they actually left, searchable.
The relay: what it sees, keeps, and cannot do
Direct download only. The Setapp edition has no public relay, so no webhook delivery from it ever reaches our servers.
A sender POSTs to your channel URL. The relay queues the delivery, pushes it to your Mac if you are connected, and deletes the row the moment your Mac confirms. That is the whole job — verification, parsing, and running your flow all happen here.
- It forwards bytes verbatim — body, headers, method, path, arrival time, up to roughly 100 KB of text or 70 KB of binary. It does not parse, transform, or inspect them.
- The queue is encrypted at rest. A delivery your Mac never collects is refused at read after 24 hours and physically deleted within 48.
- Channel bookkeeping is hashes — a SHA-256 of the access token, a peppered hash of the owning license, a created-at date, queue counters. Never the token, never the license string.
- Nothing is logged. Handlers log error names only, and both API gateways run with execution and access logging off, so bodies, headers, and your secret channel path never reach a log line. Function logs expire after 30 days.
- It cannot tell real from forged. HMAC verification runs on your Mac, with a secret the relay never has.
- It never answers for your flow. Senders always get
202 Accepted; no response from your Mac is proxied back.

Good to know
You hold the kill switches. Per channel, Regenerate replaces the URL on the spot and Revoke kills it, both in the node inspector. Per Mac, Settings ▸ Webhooks ▸ Enable public relay. Per license, deactivating revokes every channel it owns, server-side.
At-least-once means duplicates. A delivery stays queued until your Mac confirms it, so a dropped connection redelivers rather than losing it. The trigger keeps a persisted record of delivery ids that already fired, so a duplicate is confirmed back but your flow does not run twice, even across a restart.