Security
No certifications to show you, so here is the thing underneath them: what Simplytics actually does, what it deliberately never holds, and what is still wrong with it.
The part that matters most: what is not here
Most analytics breaches are bad because of what the tool was keeping. Simplytics keeps almost none of it, which is a design decision rather than a security control — but it is the one that limits the damage of everything else.
- No passwords. There is nothing to hash, leak, reuse or crack. You sign in with Google, with GitHub, or with a link emailed to you.
- No cookies on your visitors, and no identifier reused across sites or days. The daily hash is HMAC-SHA256 over a truncated IP, the user-agent, the domain and the site-local date, under a server-held key. The saved hash can link visits on that site during that day and is deleted with the raw rows, within two nightly runs.
- No raw visit records after the night. Individual rows exist only to count a unique visitor within one day, and the nightly job deletes every day that has ended in the site's own timezone — never more than 48 hours, because the job runs at midnight UTC. Funnel journeys lose their visitor identifier within two nights and the rows themselves are deleted after 90 days.
- No card numbers. Dodo Payments is the merchant of record and we never see them.
- No names, pictures or profiles. Google is asked for
openid emailand GitHub foruser:email. We use the verified address and provider account ID to sign you into the same account.
How the account itself is protected
- Visitors can switch tracking off themselves. The script honours Global Privacy Control and a site's own “don't count my visits” switch, and sends nothing when either is set — see the opt-out page. A site owner can override the Global Privacy Control check, but not its own switch, with
data-honor-gpc="false", which is named here rather than left in the source. - Sessions are opaque 256-bit ids stored server-side, in an HttpOnly, Secure, SameSite=Lax cookie. Signing out deletes the row, not just the cookie.
- Emailed sign-in links live 15 minutes, work once, and are stored only as a SHA-256 hash in the database — a copy of that database is not a set of working keys. Opening one shows you which address you are about to sign in as before anything happens, which is what stops someone mailing you their link.
- Request URL query strings are redacted in the site Worker's Cloudflare logs. Sign-in, unsubscribe and checkout links can carry tokens or email addresses in their query strings. Cloudflare's automatic request-log URL field included query strings until 2026-09-29 at 14:50 UTC, and a separate cache-error message could still contain a full public-dashboard URL until 15:09 UTC that day. Anyone able to open the operator's Cloudflare account could then have seen sign-in links issued within the previous three days. Each sign-in link works for 15 minutes and only once. Earlier log entries will age out by the end of 2026-10-02 (UTC).
- Cross-site request forgery has two layers:
SameSite=Laxon the session cookie, and anOrigin/Sec-Fetch-Sitecheck on every mutating request. The beacons are excluded because they are cross-origin by design, and the webhooks because an HMAC signature proves more than either header could. - Webhooks from the payment provider are verified against an HMAC signature and de-duplicated by event id before anything is granted or revoked.
- Rate limits sit in front of sign-in, the beacons, the dashboard and the webhooks, keyed per IP — and the beacons additionally per site key, so one site cannot spend the whole account's budget from many addresses.
Transport and headers
- HTTPS is forced at the edge, minimum TLS 1.2, with HSTS for a year including subdomains.
X-Content-Type-Options: nosniff,X-Frame-Options: DENY,Referrer-Policy: strict-origin-when-cross-origin, and aPermissions-Policythat turns off camera, microphone and geolocation.- The two third-party scripts the dashboard loads are pinned to exact versions and checked against Subresource Integrity hashes, so a compromised CDN cannot change them.
Where the data is, and what happens if it is lost
- Analytics live in a Cloudflare D1 database whose primary storage is in the European Union (Warsaw).
- The person who administers it is based in India. Deploys, fault-finding and support all mean reaching that EU-hosted database from India, which raises an international-transfer question for EU customer visitor data — keeping the database in the EU does not settle that. The DPA covers it with the EU Standard Contractual Clauses and a published transfer assessment, and states the one case the clauses were not designed for; the privacy policy sets out what limits it.
- Government requests: none. No public authority, in India or elsewhere, has asked for Simplytics data or for access to it, as of 2026-09-23. This line is updated at least once a year, and a request would be handled as the transfer assessment describes.
- A full database export is made weekly through Cloudflare and stored in a private, EU-jurisdiction object store, and a lifecycle rule deletes each export 90 days after it is written. The stored copies are in the EU. The job that makes and checks each export runs on Cloudflare's network wherever Cloudflare places it, and Cloudflare does not say where it keeps the temporary files behind the one-hour export link and the database import, so we do not claim those steps stay in the EU. Until 2026-09-23 the export was made on a GitHub-hosted machine; neither the export nor its download link passes through GitHub any more. Each week the new export is loaded into a temporary EU-jurisdiction database, its tables and accounts are counted, and the temporary database is deleted when the check ends, or by a daily cleanup within about two days if the run fails. Only sizes and counts are reported out of that job.
- You can export the available analytics reports as CSV at any time, subscribed or not, and delete your account and the analytics it still holds from the Account page. When deletion succeeds, the account record and remaining analytics leave the live database immediately. History already handed to another account remains with that account, along with a minimal record of its source. Backups are the exception, and they expire rather than being purged on request: the point-in-time restore above is a rolling window of at most 30 days, and each weekly export is deleted 90 days after it is written. Copies of the data removed by account deletion age out within 90 days. Billing records and an address-level suppression record can remain, as the privacy policy explains. We read those backup copies only to recover from a disaster, with one exception: each week the job that writes a new export checks that it restores. It loads that export into a temporary database, counts its tables and accounts, and deletes the temporary database. Only sizes and counts are kept, and no older backup is read.
What is still wrong
A security page that lists only good news is an advertisement. These are the open items, in the order we would fix them:
- Our Content Security Policy blocks inline JavaScript and allows scripts only from our own site and three specific, version-pinned library files, which our pages load with integrity checks. Inline styles are still allowed. This reduces the risk from injected scripts; it is not a security guarantee.
- One person builds and runs this. There is no second pair of eyes on a deploy, no on-call rotation, and no separation of duties. The mitigations are that the blast radius is small by design and that everything ships through automated tests and a smoke check, but neither is the same thing. What you do get is that you need not take our word for whether the site is up: an independent monitor outside our infrastructure checks it every three minutes and publishes the result on a public status page, which stays online when Simplytics does not. There is still no uptime guarantee, and nobody is paged at 3am.
- The deploy pipeline can reach the data. Code reaches production through an automated job on GitHub that holds a Cloudflare credential. That credential can replace the main site's code and read and change its database, so a compromised GitHub account, workflow or build dependency could use it to read customer data, including the backups. The credential has no permission to open the backup storage directly and cannot change the code of the separate backup job, but Cloudflare does not require a separate permission to give the main site's code access to the backup storage, so code deployed with it could read them. The job itself never downloads the database or a backup. Moving deploys off GitHub would shrink this further; that has not been done.
- No SOC 2, no ISO 27001, no third-party penetration test. Each costs more than this product earns. If you need one of them to buy, Simplytics is honestly not the right tool for you yet.
Reporting something
Email nikhil@simplytics.dev. There is no bug bounty and no payout — saying so plainly is fairer than letting you spend a weekend assuming otherwise. Reports are read and answered, and /.well-known/security.txt lists what is already known and therefore not worth your time.
Please do not test against other people's accounts or send traffic that would distort a customer's numbers. A free trial takes no card and gives you a real account of your own to test against.