Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions api/routers/feedback.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@


IP_HASH_PREFIX = "hmac:"
"""Marks a salted `ip_hash` (`_hash_ip`). Rows written before it carry an unsalted SHA-256 of
the address, which a migration has to clear: it is left alone here."""
"""Marks a salted `ip_hash` (`_hash_ip`). The unsalted SHA-256 hashes that rows written before it
carried were cleared once by hand on 2026-11-02 after a snapshot; no migration is needed."""
_IP_SALT = secrets.token_bytes(32)
"""This process's salt for `_hash_ip`. Never logged and never configured, so it dies with the
process, and with it every way to tell which address a stored hash came from."""
Expand Down
60 changes: 38 additions & 22 deletions api/routers/seo.py
Original file line number Diff line number Diff line change
Expand Up @@ -1205,32 +1205,48 @@ async def seo_libraries():
'<a href="https://x.com/MarkusNeusinger">X</a>). Full legal notice with '
'contact details on the <a href="https://anyplot.ai/legal">interactive page</a>.</p>'
"<h2>Privacy</h2>"
"<p>Analytics: Plausible Analytics (EU), served over a path on this domain — no cookies, no "
"cross-site identifier, no IP address stored. Server logs are kept 30 days in Google Cloud Logging "
"in the Netherlands (europe-west4); entries written before the move on 2 November 2026 stay in "
"Google's global log storage until their 30 days are over. A feedback entry "
"is kept until it is deleted by hand and is readable only by the operator, and the salted "
"hash of the IP address that limits feedback spam is cleared after ten minutes. Hosting: "
"Google Cloud Run (Netherlands), with Cloudflare at the edge.</p>"
"<ul>"
"<li>Swiss data protection law applies, and the GDPR for visitors from the EU.</li>"
"<li>Analytics: Plausible Analytics (EU), through this domain; no cookies, no cross-site id, "
"no IP address stored.</li>"
"<li>Hosting: Google Cloud Run, SQL and Storage in the Netherlands (europe-west4), Cloudflare at "
"the edge, which uses your IP address to rate-limit, filter bots and absorb DDoS attacks. Server "
"logs: kept 30 days in Google Cloud Logging in the Netherlands (europe-west4).</li>"
"<li>Feedback: your message and reaction, the optional contact field, the page, window size, "
"user-agent and a random id that ties your own submissions together; read only by the operator, "
"kept until you ask to delete it. The salted IP hash against spam is cleared by the next "
"feedback after ten minutes, and its salt dies with the server instance.</li>"
"<li>No cookies for visitors (admins: the Cloudflare Access login cookie), no accounts, and no "
"name or email unless you type one. Suggesting a plot type on GitHub may credit your public "
"username in its spec.</li>"
"<li>No AI training on what you send; browsing the catalogue never reaches a model.</li>"
"<li>Legal bases: legitimate interest (Art. 6(1)(f) GDPR) for the site and the assistant's "
"telemetry and limits; your request (Art. 6(1)(b) GDPR) for a plot; consent (Art. 6(1)(a) GDPR) "
"for a feedback case, withdrawable at any time.</li>"
"<li>Google Cloud and Cloudflare apply their data processing terms, with safeguards for "
"transfers outside Switzerland and the EU.</li>"
"<li>Rights: access, correction, erasure, restriction, objection, and a complaint to a "
"supervisory authority.</li>"
"</ul>"
'<h2 id="assistant">Data assistant (experimental)</h2>'
"<p>Only if you use it: the data assistant adapts a catalogue plot to data you bring. It is "
"open to everyone as an experimental feature, and the operator may pause it at any time. What "
"you paste and write goes to Claude models by Anthropic through Google Cloud Vertex AI in the "
"EU; results can be wrong, and nobody checks them by hand. Sessions live in the server's memory "
"only and end after an hour without activity. Its log lines carry no content, only a random id "
"of your browser tab salted with a value that lives as long as the server instance; the limits "
"per network count your IP address the same way, in memory only. Nothing is stored unless you "
"send feedback: then the conversation, the plots, the code and a 5-row sample of your data, and "
"the whole data file only if you tick the box (it starts unticked), go to a private bucket for "
"180 days. A feedback case rests on your consent (Art. 6(1)(a) GDPR), given when you send it, "
"which you can withdraw at any time by asking. The code it writes is yours to use, as is; Highcharts is free for non-commercial use, "
"and a commercial use needs a licence from Highsoft. Google Cloud and Cloudflare process data "
"under their data processing terms, including their safeguards for transfers outside "
"Switzerland and the EU.</p>"
"<ul>"
"<li>Only if you use it: open to everyone as an experimental feature, and the operator may "
"pause it at any time. No warranty: results can be wrong, and nobody checks them by hand.</li>"
"<li>Input goes to Claude by Anthropic via Google Cloud Vertex AI in the EU, under Google "
"Cloud's data processing terms; it is not used for training.</li>"
"<li>Sessions: server memory only, cleared after an hour idle.</li>"
"<li>Logs and telemetry hold no content; ids and IP addresses are salted with a value that lives "
"as long as the server instance. Telemetry: up to 180 days.</li>"
"<li>Stored only with feedback: the conversation, plots, code, a 5-row sample, and the data file "
"only if you tick the box (it starts unticked); private bucket, 180 days. The triage row stays "
"until you ask to delete it.</li>"
"<li>Its code is yours to use, as is; Highcharts is free for non-commercial use, and a commercial "
"use needs a licence from Highsoft.</li>"
"</ul>"
"<h2>Transparency</h2>"
"<p>The whole stack — specs, pipeline, API and frontend — is open source at "
'<a href="https://github.com/MarkusNeusinger/anyplot">github.com/MarkusNeusinger/anyplot</a>; '
"the catalogue content is MIT-licensed.</p>"
"the catalogue content is MIT-licensed. Running costs about $60 a month (October 2026).</p>"
)


Expand Down
Loading
Loading