Privacy policy
Draft, not reviewed by counsel. Written by an agent from
docs/ARCHITECTURE.md§10 and the database schema, so every number and table below is what the code actually does. It is not legal advice and it has not been read by a lawyer. Take it to one before it is published. Notes addressed to that lawyer are marked [For counsel].
1. Who is responsible
HonestFetch is operated by HallinCreations, in Sweden. The same operator the bot page names, and the same one the Cloudflare Verified listing names.
[For counsel] The legal form is undecided (docs/adr/0006-business-setup.md). The beta
runs without a registered entity because nothing is sold. Once a form is chosen, the legal
name, the organisation number and a postal address belong in this section, and the same
three belong on https://honestfetch.dev/bot.
Contact: bot@honestfetch.dev.
2. What HonestFetch is, in one paragraph
An agent sends a URL and an optional question. HonestFetch fetches that one page, checks the site's own rules first, and returns a short extract of the text. It signs every request so a site owner can tell who it was. It is a reading tool, not an archive.
3. The promise this policy exists to make
HonestFetch never stores the pages it fetches. Page content lives in memory for the length of one request and is never written anywhere: not to the database, not to a log, not to a cache, not to a file.
This is structural rather than a policy. The database schema has no column that could hold
page content, and a test (no-content.integration.test.ts) asks the database directly and
fails the build if content ever appears in one.
4. What is stored, and why
Six tables, and this is all of them.
| Table | What it holds | Why |
|---|---|---|
customers |
Account name, plan, an optional operator handle, when the account was created, and whether it has been disabled | To know whose key it is |
api_keys |
The first characters of a key, a SHA-256 hash of the whole key, and timestamps | To authenticate. The key itself is never stored; only the hash |
usage_events |
Customer id, destination host, an optional truncated path prefix, the decision, the status, the reason, byte and token counts, latency, and any quoted price | Metering, and the accountable record §3 of the architecture requires, so abuse can be traced and cut off |
usage_daily |
Customer, day, host, and three counts | The same picture after the raw rows are deleted |
domain_optouts |
A domain, the verification method, a keyed hash of the contact address, a hash of the DNS token, and timestamps | The site-owner exclusion list |
plans |
Pricing plans | Limits and, later, billing |
usage_events holds no URL. It holds the host, and at most a truncated path prefix.
No query string, ever.
The contact address of a site owner is never written down. domain_optouts keeps a
keyed HMAC-SHA256 hash of it and nothing else. The hash exists for one purpose: to
recognise the same person if they write again. A copy of that table hands a reader no
address, and because the hash is keyed with a secret held outside the database, it cannot
be turned into a lookup table for "did this person write in".
5. Requested URLs are treated as personal data
A URL can identify a person. https://example.com/profile/anna-svensson is a name.
So the URL an agent sends is handled as personal data throughout: it is used to make the one request it was sent for, it is never written to the database in full, it never appears in a log line, and it is gone when the request ends.
For that URL, you are the controller and HonestFetch is your processor (ADR-0018). It arrives as your instruction and HonestFetch keeps none of it. The records HonestFetch does keep, and why, are in §4 and §11.
6. Logs
Two logs exist. Neither holds a fetched page, an API key, or a requested URL.
The web server log records the time, the status, the path called on HonestFetch's own
API, and the address the call came from. Authorization, Proxy-Authorization and
Cookie headers are deleted before the line is written. The path is safe to keep because
the URL to read travels in the request body: an inbound line says /v1/read and nothing
more.
The application log writes only fields from a fixed allow-list, and every value is capped in length. Request headers are never serialised at all, because redacting headers by name leaves the next one to be discovered.
The web server log is rotated every day and rotated files are deleted after 30 days, so
the address a call came from is kept for at most 30 days, the same period as the raw usage
records in section 7. The rotation is a file on the host (infra/logrotate.conf),
installed with the web server's configuration.
7. How long things are kept
| Data | Kept for |
|---|---|
| Raw usage events | 30 days |
| Daily aggregates | 13 months |
| Opt-out requests that were never verified | 30 days, then forgotten |
| Verified opt-outs | Until the site owner asks for removal |
| Account and key records | While the account exists |
| Fetched page content | Not kept at all |
A job deletes raw rows and rolls them into aggregates in one transaction, so nothing is lost on the way and nothing outlives its window.
8. Where it is stored
In the European Union. The server is a Hetzner Cloud machine in Helsinki, Finland. The database and the cache run on that machine. No data is transferred outside the EU.
9. Who else touches it
| Who | What they do | Where |
|---|---|---|
| Hetzner Online GmbH | Hosts the server, and takes encrypted backups of it | Helsinki, Finland |
| Cloudflare | DNS for the domain, and forwards mail sent to bot@honestfetch.dev |
Global |
There is no analytics provider, no advertising network, and no third-party script on any page HonestFetch serves.
[For counsel] A payment provider joins this list before the first paid customer.
docs/adr/0006-business-setup.md recommends Stripe with Stripe Tax.
10. Cookies
HonestFetch sets no cookies on any page it serves.
It also sends none: a cookie is stripped from every outbound request, and any cookie a site tries to set is stripped from the response. That is part of never logging in and never passing a paywall.
11. Your rights
Under the GDPR you may ask for access to your personal data, correction of it, erasure of it, restriction of processing, portability of it, or to object to processing. You may also complain to a supervisory authority; in Sweden that is Integritetsskyddsmyndigheten (IMY).
Write to bot@honestfetch.dev.
The legal basis for each thing HonestFetch keeps as controller (ADR-0018):
| Data | Basis |
|---|---|
| Account and API key records | Contract, Art. 6(1)(b): the service cannot be provided without them |
| Usage events and daily aggregates | Legitimate interest, Art. 6(1)(f): the accountable record that lets a site owner's complaint be answered with facts, and metering |
| The opt-out list | Legitimate interest, Art. 6(1)(f): honouring a site owner's request, which is their interest as much as ours |
| Caller addresses in the web server log | Legitimate interest, Art. 6(1)(f): security |
For the URL and question you send, the basis is yours: HonestFetch processes them on your instruction (§5).
[For counsel] Confirm the bases, and whether the balancing test for the two legitimate interests should be written down here or kept internally.
12. Site owners
If you run a site and do not want HonestFetch to read it, you have four ways to say so, and
HonestFetch obeys all of them: robots.txt, Content Signals, an RSL licence it cannot meet,
and its own exclusion list at https://honestfetch.dev/bot.
An exclusion takes effect on the very next request, before HonestFetch asks your server
anything at all, including for robots.txt. It covers every subdomain.
13. Changes
A change to this policy changes the version and the date at the top. Material changes are sent to customers at the address on their account.