Privacy Policy

What we store, what we never store, and who else touches it.

Tamperlens inspects documents and keeps almost nothing. This page describes the actual system, column by column, rather than the usual list of everything a company might conceivably collect.

The short version

  • The PDFs you inspect are never written to disk and are not kept after the response. No copies, no cache, no backups of them.
  • We never log a document's content, its text, or its filename in normal operation.
  • The database holds three things about you: an account row, a hash of your API key, and one ledger line per inspection.
  • There are no analytics cookies and no third-party trackers on any page. Page counting happens on our own server and records only a date, a path and a number.

1. Documents you submit for inspection

When you upload a PDF — to the free checker, to the dashboard test console, or to POST /api/v1/inspect — the bytes are held in memory, parsed on a worker thread, turned into a report, and discarded when the request finishes. Nothing is written to disk at any point, and there is no queue, cache or object store behind the endpoint.

The report is returned to you and not stored on our side either. If you want to keep it, keep it yourself.

Encrypted PDFs are reported as "not content-analysed" rather than decrypted. We do not attempt to break password protection.

Server logs record the fact of a request (method, path, status, duration), never a document's contents. Filenames are not logged in normal operation.

2. Your account

If you create an account we store, in a single SQLite database:

  • your email address, lower-cased;
  • a scrypt hash of your password with a per-account random salt — never the password itself, and the hash is not reversible;
  • the timestamp at which you confirmed your email address, if you did;
  • your Stripe customer id, if you have ever started a checkout — an opaque reference, no card data;
  • the date the account was created.

API keys: only a SHA-256 hash of each key is stored, alongside its plan, monthly quota, label and creation date. The key itself exists in our systems for exactly as long as it takes to show it to you once. That is also why we cannot resend it — rotation issues a new one.

Sessions: logging in creates a row holding a random session id, your account id and an expiry (30 days, extended while you keep using the dashboard). Logging out deletes it; expired rows are deleted automatically.

Email links: "confirm your address" and "reset your password" links are backed by a row holding a SHA-256 hash of the token, its kind, its expiry (7 days for confirmation, 1 hour for a reset) and whether it has been used. Each link works once. Expired rows are deleted automatically.

3. The usage ledger

Every inspection appends one row to a usage log. That row is the entire record of the request:

  • a timestamp;
  • the size in bytes of the submitted file;
  • the risk band of the resulting report (low / elevated / high);
  • and either the id of the API key used (for authenticated calls) or the client IP address (for anonymous calls to the free checker) — never both.

There is no column for the document, its name, its contents, or any signal it produced. The ledger exists to enforce monthly quotas, to bill correctly, to show you your own usage, and to make the anonymous rate limit auditable.

Retention:

  • Anonymous rows (with an IP address): 90 days. An IP address is personal data, so these are the shortest-lived thing in the database.
  • Keyed rows (with no IP address): 400 days — a year plus slack, so month-over-month comparisons still work.

A daily sweep deletes anything past those limits.

4. Cookies

There is exactly one cookie on this site: tl_session, set when you log in. It holds a random session identifier and nothing else — no name, no email, no preferences. It is HttpOnly (JavaScript cannot read it), SameSite=Lax (browsers never send it with a request made by another site — only when you yourself navigate here, which is what makes returning from the payment page work), Secure in production, and it expires after 30 days.

That cookie is strictly necessary to keep you logged in, which is why there is no consent banner asking about it. There are no advertising, analytics or preference cookies, and nothing on any page loads a script, font, image or stylesheet from another domain — the Content-Security-Policy on every page forbids it.

5. How we count page views

We do want to know whether anyone is reading the site. So the server keeps a counter: for each successfully served page it increments one row keyed by (UTC date, page path).

That is the whole record. There is no IP address, no user agent, no referrer, no cookie, no session, no visitor or device identifier, and no way to reconstruct one — a row says "the pricing page was served 14 times on 2026-07-25" and cannot say more, because the table has no other columns. We cannot tell whether that was 14 people or one person fourteen times, and we are content with that.

Only the site owner can read these counters, through an endpoint protected by a separate secret token.

6. Who else processes your data

  • Hetzner (hosting) — the application and its database run on a single virtual server in Hetzner's Helsinki, Finland data centre. Hetzner is a German company and its facilities are in the EU. Encrypted database backups stay within the same provider.
  • Cloudflare (CDN, proxy, TLS) — all traffic reaches us through Cloudflare, which terminates TLS, serves cached static assets and provides the tunnel to our server. Cloudflare processes request metadata, including your IP address, under its own terms; we receive the client IP through the CF-Connecting-IP header and use it only as described in section 3.
  • Stripe (payments) — if you subscribe, Stripe collects and processes your payment details and billing information. Card data never touches our servers; we store only Stripe's customer reference. Stripe acts as an independent controller for its own compliance purposes.
  • Resend (transactional email) — used, when configured, to send the two emails this service sends: address confirmation and password reset. It receives your email address and the message. There is no marketing list and we do not send newsletters.

We do not sell or rent personal data, and we do not share it with anyone else except where we are legally compelled to.

7. Why we are allowed to hold this (legal bases)

  • Performing our contract with you — your account, your key, the quota ledger, the session, the emails about your account. Without these the service cannot function.
  • Legitimate interests — the anonymous rate-limit ledger and the page counters, both of which are the minimum needed to keep the service available and to know whether it is being read.
  • Legal obligation — keeping billing records for as long as tax law requires.

8. Your rights

You can ask us to show you what we hold about you, correct it, export it, or delete it. Write to [email protected] from the address on the account and we will act on it — normally within a few days, and in any case within a month.

Deletion removes your account row, your key hashes, your sessions and your usage ledger entries. Two things survive, and it is fair that you know: billing records held by Stripe, which we cannot delete on their behalf and which tax law requires be kept; and the page-view counters, which contain no reference to you at all and so cannot be linked back to you in the first place.

If you are in the EU or the UK you can also complain to your local data-protection authority. In Brazil, the ANPD.

9. Security

  • Everything is served over HTTPS; there is no plain-HTTP endpoint.
  • Passwords are scrypt-hashed with per-account salts; API keys and email tokens are stored as SHA-256 hashes.
  • Every page runs under a strict Content-Security-Policy with no inline scripts and no third-party origins.
  • The PDF parser treats every file as hostile: hard caps on size and complexity, a wall-clock budget, and execution in a separate worker thread that is killed and replaced if a file takes too long. Embedded JavaScript is flagged, never run.
  • The application container runs as a non-root user with a read-only filesystem apart from its data volume, and publishes no ports directly to the internet.

No system is perfect. If you find a vulnerability, please write to [email protected] before disclosing it publicly, and we will work with you.

10. Children

Tamperlens is a developer tool and is not directed at children. We do not knowingly create accounts for anyone under 16.

11. Changes to this policy

The "last updated" date at the top always reflects the current version. If a change materially affects how we handle personal data, we will email account holders before it takes effect.

12. Contact

The data controller is the individual owner of Tamperlens, in Brazil. For any privacy question, request or complaint: [email protected].