Published revision 1.0 (2026-10-18). This page is generated from the canonical policy text; both carry the same revision.

TameFlash data and privacy policy

Revision 1.0 — 2026-10-18. This file is the canonical, owner-approved text (issue #109). The published copy at https://tameflash.com/privacy (Cloudflare Pages) is generated from this file by scripts/build-site.mjs and carries the same revision. The extension bundles the revision its Privacy link points at and shows a one-time notice in the popup and on the Options page when that revision changes (a fresh install records the current revision at install time, so only a change is announced).

Data controller: Jan Bednář, an individual developer in the European Union. Privacy requests, deletion requests and support: privacy@tameflash.com. GDPR applies to users in the EU and is the baseline applied to everyone.

1. Summary

2. Locked constraints (from issue #109, verbatim in substance)

3. Decisions (owner, 2026-10-18) and PROPOSED values

ItemStatusValue
Controller and lawDECIDEDJan Bednář, individual, EU; GDPR baseline for all users
Contact routeDECIDEDEmail only: privacy@tameflash.com (the repository may stay private)
Manual-report retentionDECIDEDReport body eligible for deletion 180 days after receipt (reports received before 2026-10-19 keep their 90-day schedule: longer retention is not applied retroactively); note 30 days; removal by the hourly cleanup job; after deletion or expiry only a hashed idempotency tombstone for 7 days
Free-text notesDECIDEDRead by the maintainer only (Cloudflare dashboard / D1 console); a note that contains health details, names or contact data is deleted as soon as it is seen; never shared or exported
PublicationDECIDEDThis file is canonical; https://tameflash.com/privacy on Cloudflare Pages mirrors the approved revision before the store listing goes live (#5)
Change notificationDECIDEDVersioned policy; one-time in-extension notice when the bundled revision changes (src/core/policyRevision.ts; acknowledged revision stored device-locally under tameflashAcknowledgedPolicyRevision); a revision that collects more or keeps data longer is marked stricter, announced with its effective date at least 30 days after publication, and every consent-based feature stays off until re-enabled
Incident responseDECIDEDContain (disable the endpoint, rotate Cloudflare credentials, delete affected rows), assess, record; notify users through an in-extension notice and the website, and the supervisory authority within 72 hours where GDPR requires it
Approval scopeDECIDEDShipped flows (local processing, manual reports) are approved now; planned flows below are PROPOSED and each later issue must obtain approval on #109 or its own issue before shipping
Exact lookup dataPROPOSEDRequest body only (canonical video identity + compatibility metadata); no server-side storage of lookups beyond Cloudflare's sampled operational logs; cache on device ≤ 7 days
Detector-evidence sharingPROPOSEDCandidate evidence kept 365 days while under review; rejected evidence deleted 30 days after rejection; verified intervals kept while the catalog record is live, derived and withdrawable
Creator uploads (preflight)PROPOSEDSource media deleted from R2 within 7 days after the scan completes or fails; scan results kept 90 days unless the creator deletes them earlier or publishes them; creator tokens hashed, revocable, kept until revoked
Exceptional retentionPROPOSEDMaterial tied to an abuse or security investigation may be kept up to 90 days beyond its schedule, with a written reason in the incident record
Scanner job recordsPROPOSEDJob metadata (digests, build, revision, throughput) kept 365 days; scratch data deleted after each job

4. Data inventory

Columns: what is collected; purpose; lawful basis; where; who can access; retention; deletion path; backups and logs; incident handling. "Device" means the user's browser profile. Most Device rows never leave it; the exceptions are stated in the row itself: a report draft's serialized payload, note and idempotency key are transmitted when the user submits or retries that report, and a stored deletion code is transmitted when the user deletes that report. Nothing in a Device row is transmitted without one of those explicit actions.

4.1 Shipped today

ClassFieldsPurposeBasisStorageAccessRetentionDeletionBackups / logsIncident handling
Local video analysisDecoded frames, luminance statistics, hazard risk per frame, lookahead buffersFlash reductionNot personal data processing by the controller: happens entirely on the deviceDevice memory onlyThe page's own tabDiscarded continuously; nothing persistedn/aNonen/a
Settings (synced)The SETTINGS_SCHEMA keys: enabled, safe mode, strength, sensitivity, startup/degradation policies, detector thresholds, HDR display nits, WebGPU toggles, debug HUDKeep the user's preferences across their own browser profilesUser's own browser sync; TameFlash never receives itchrome.storage.sync (the browser vendor syncs it under its own policy)The userUntil changed or the extension is removedChange or uninstallBrowser vendor's sync backups, outside TameFlashn/a
Device-local stateSite protection policy per origin (tameflashOriginPolicy: the exact origins of websites the user added, with their mode), the acknowledged privacy-policy revision (tameflashAcknowledgedPolicyRevision), expert/diagnostic preferences, compatibility mismatch flag, safety diagnostics (event list: protection states, failure reasons, settings keys, timings, plus the browser's user-agent string stored once per recorder for version context; events about an emergency cover carry that cover's random session id, which therefore outlives the cover in the diagnostics until eviction or Options → Clear; no URLs, no credentials; bounded per recorder, see below), report drafts (tameflashIncidentReportDraft:*: the complete captured report context, and once a submission was attempted also the serialized payload including the optional note, the idempotency key and the plaintext deletion secret, kept until the draft's 30-minute sweep so a timed-out or offline submission can be retried without changing the payload), submitted-report receipts with their deletion codes (tameflashSubmittedIncidentReport:*), generic-site activation records (session storage)Operate the extension; let the user delete reports laterLocal operationchrome.storage.local / sessionThe user; the extension itselfDrafts become eligible for removal 30 minutes after capture and are removed by a housekeeping check that runs every 5 minutes while the browser is running (so up to about 35 minutes, longer if the browser is closed meanwhile); diagnostics are bounded per recorder (content script, bootstrap, service worker: 100 events / 20 errors each, so at most 300 events / 60 errors on the device; the Options view shows the merged, trimmed list) and cleared from Options; session storage ends with the browser session; a receipt and its deletion code stay on the device until the user presses Delete for that report (also after the server has already expired it, which answers "not found" and removes the local record) or uninstalls the extensionOptions → Clear (diagnostics), the report page's Delete button (receipts), uninstallNone (local only)n/a
Emergency-cover session stateWhile "Pause and cover" is active: the covered tab id, a random session id, the activation time, sometimes the window id and tab index (activePanicSessions), and a ledger of random cover tokens per covered tab (activeUniversalPanicCoverTokens) that proves which cover the extension ownsKeep the emergency cover authoritative across worker restarts and tab movesLocal operationchrome.storage.sessionThe extension itselfUntil the cover is released or the browser session ends; session storage never survives a browser restart (the random session id also appears in safety-diagnostics events, where it stays until eviction or Options → Clear)Release the cover; close the browserNone (local only); never transmittedn/a
Diagnostic video labels (opt-in)When the user enables "diagnostic video labels" in Options, each safety-diagnostics event also stores a sanitized label of the video it concerns: the page title on dedicated providers, the hostname on added websites, cut to 160 charactersLet the user match a diagnostic event to the video it happened onLocal operation; the user's explicit opt-inchrome.storage.local (tameflashSafetyDiagnostics)The userWith the diagnostics (100 events); turning the preference off stops new labels and existing labels are dropped at the next write; Options → Clear removes themOptions → Clear, disable the preference, uninstallNone (local only); never transmitted, not part of reportsn/a
Manual incident report (transmitted)schemaVersion, kind (flash-through / over-dimmed / protection-unavailable), reportedMediaTimeSec, optional note (≤ 1000 characters), context: capture time (UTC), extension version, canonical media reference (provider, provider id, public video id for YouTube/Twitch/Kick where one exists, content kind, confidence, ad state, catalog eligibility), media session identity (provider route identity; withheld for added websites), video session id (a per-video value made of the capture time and a random suffix, not tied to the user), media time, duration, playback rate, paused, live edge, analysis revision, detector/response/scanner fingerprints (hashes of settings profiles, not of the user), protection state, failure reason, lookahead state, HDR flags, safe mode, weakened keys, mitigation flag, up to 20 recent hazard episodes (times, peak risk, channels, display area), up to 600 trace samples (media time, risk values, applied gain). Never: page URL, title, hostname of added websites, account, cookies, user agent, IP as a field, install identifierLet the maintainer reproduce a protection failure or over-dimming on a specific public videoConsent, given per report by pressing Submit after reviewing the exact payloadCloudflare Worker tameflash-reports → D1 database tameflash-reports-eu, created with --jurisdiction=eu (Cloudflare guarantees the data stays in the EU; it runs in the EEUR region)Maintainer only, via the Cloudflare dashboard / D1 consoleBody: eligible for deletion 180 days after receipt; reports received before 2026-10-19 keep the 90-day schedule they were submitted under. Note: eligible after 30 days. An hourly cleanup job removes eligible rows in bounded batches, so removal follows that schedule (a backlog or outage delays it and is monitored as a job failure). Deleted/expired rows leave only a hashed idempotency key for 7 days so a retried submission cannot recreate themDELETE /v1/reports/{receipt} with the one-time deletion code kept on the device (server stores only its SHA-256); the report page lists submitted reports with a Delete button; email requests honoured for anyone who can quote a receipt. Deletion removes the rows from the active database immediately; Cloudflare's point-in-time history ("Time Travel", always on) can restore the database to a state before the deletion for up to 30 days, after which the data is gone from that history tooCloudflare D1 Time Travel (up to 30 days) is the only backup and is outside the application schedule; the Worker records only status/error codes and retention counters at 10 % sampling; Workers invocation logs (which would include URLs) are disabled in the checked configurationSection 6
Request metadata (Cloudflare edge)Connecting IP address, request time, TLS and HTTP metadata, the request's Origin header (a fixed Chromium extension origin shared by every install; on Firefox a per-install moz-extension:// UUID)Deliver the request; rate-limit abuse (10 requests per 60-second window per connecting IP, through Cloudflare's Workers rate-limiting binding)Legitimate interest in running and protecting the serviceCloudflare's global edge network: the Worker runs at the Cloudflare location nearest the user, wherever that is; only the database is EU-constrained (no Regional Services or metadata-boundary product is configured)Cloudflare as processor; the maintainer sees only sampled application logs without IP or OriginThe rate-limit counter is keyed by the connecting IP and held by Cloudflare's platform (cached on the serving machine and asynchronously stored in that Cloudflare location); the 60-second period is the limiting window, not a deletion deadline, and the application receives no retention guarantee for the key beyond Cloudflare's own terms. The Firefox Origin is matched by shape and never logged or stored; Cloudflare retains edge metadata under its own termsNot applicable to the application; Cloudflare's retentionSee Cloudflare's processor terms; account-level Logpush and Tail Workers are not enabledSection 6
Operational logsBounded application log lines: status code, error code, retention countersOperate and debug the serviceLegitimate interestCloudflare Workers LogsMaintainerCloudflare's Workers Logs retention (platform-controlled, days); no payload, note, URL, IP or Origin contentn/aPlatformSection 6
Deletion receiptOn the device: receipt id + deletion secret. On the server: receipt id, SHA-256 of the secret, hashed idempotency keyProve the right to delete without any accountConsent (part of the report)Device chrome.storage.local; D1The user; the maintainer sees hashes onlyDevice: until the user presses Delete for that report or uninstalls; server: with the report, then the 7-day tombstoneDeleting the report (the only local-clear mechanism today; a server-side expiry does not remove the local record by itself)As aboveSection 6

4.2 Planned, not built, PROPOSED

ClassFieldsPurposeBasisStorageAccessRetention (PROPOSED)DeletionNotes
Exact video lookup (#120, #121)POST body: canonical video identity of a positively identified, catalog-eligible YouTube VOD/Short, analysis-compatibility metadataWarn before a verified hazardous videoConsent (default-off toggle; pre-enable preview shows the exact body)Cloudflare Worker; no lookup tableMaintainer (logs only)No server-side storage of individual lookups; sampled operational logs only; device cache ≤ 7 daysToggle off; clear device cacheReveals the watched video to the service at lookup time; disclosed in the toggle copy
Detector-evidence sharing (#121, #120)Canonical identity, analysis revision, detector fingerprint, content-driven hazard episodes, raw detector summaries, non-identifying provenance; one idempotent summary per media sessionBuild the candidate queue for the verified catalogConsent (separate default-off toggle)D1 candidate tables, separated from verified recordsMaintainer, reviewersCandidates 365 days while under review; rejected 30 days after rejection; verified intervals while the catalog record is live, withdrawableToggle off stops future uploads; deletion of a specific evidence row on request with its receiptLive, ad, unknown-identity sessions can never produce evidence
Verified catalog records (#120)Canonical identity, verified intervals, revision, review state, scanner provenanceServe lookupsLegitimate interest (derived, non-personal)D1Public through lookupsWhile the record is live; withdrawn records are tombstonedWithdrawal by the maintainerNot personal data; listed for completeness
Creator accounts/tokens (#124)Maintainer-issued token (hashed), creator contact for the invitation, quota countersInvite-only preflight scanningContract/consent with the creatorD1MaintainerUntil revoked; counters rollingRevocationTokens never double as extension-user identifiers
Uploaded media (#124, #114)The creator's file, digest, media metadata, rights attestation (who, when, which file)Scan before publicationConsent + rights attestationCloudflare R2 (temporary), scanner scratchMaintainer, scannerSource media deleted within 7 days after the scan completes or fails; attestation kept with the job recordCreator deletes earlier via the preflight pageAttestation wording in section 7
Scan jobs and results (#114, #124)Source authorization, digest, scanner build, analysis revision, profile, throughput, verified intervals, diagnosticsProduce verified intervals; operationsLegitimate interest / contractD1, scanner logsMaintainer; the creator for their own resultsResults 90 days unless deleted or published; job metadata 365 days; scratch deleted after each jobCreator deletion; maintainerPublication is a separate explicit choice
Scanner operational logs (#114)Job ids, timings, error codesOperate the scannerLegitimate interestScanner hostMaintainer30 daysn/aNever media bytes or creator contact in logs
Privacy ledger (#122)Device-only list of the latest 100 network operations for ≤ 30 days, with media ids redactedTransparencyLocal operationDeviceThe user30 days / 100 entries"Clear local ledger"Never uploaded

5. Processor boundaries

Cloudflare (Workers, D1, Workers Logs; R2 once uploads exist) is the only processor today. The Worker runs on Cloudflare's global edge network at the location nearest the user, so the request itself (IP address, timing, TLS metadata, Origin) is handled wherever that location is; no Regional Services or Customer Metadata Boundary product is configured, and this policy does not claim an EU boundary for request handling. The production database tameflash-reports-eu was created on 2026-10-18 with wrangler d1 create --jurisdiction=eu, the only way D1 location can be constrained, so EU residency is a Cloudflare guarantee rather than an observed region (it runs in EEUR). The previous database, created without a constraint and holding no user reports, is retired with the deploy that publishes this revision. Any future R2 bucket is created with the same EU jurisdiction. Cloudflare necessarily sees connecting IP addresses, request timing, TLS metadata and the request Origin. The application does not store any of them itself: the rate limiter is Cloudflare's Workers rate-limiting binding keyed by the connecting IP (counters are cached on the serving machine and asynchronously stored in that Cloudflare location; the 60-second period is the limiting window, not a documented deletion deadline), the Firefox per-install Origin is matched by shape only, Workers invocation logs are disabled in wrangler.toml, and application logs carry status and error codes only. Account-level Logpush, Tail Workers and Cloudflare's own edge analytics are governed by Cloudflare's terms, not by this repository, and are not enabled for this service.

Dedicated scanner (planned, #114): a maintainer-operated host that talks only to the authenticated Worker API and never receives direct database access. It holds uploaded media only for the duration of a job plus the deletion window above. Its trust boundary is the Worker's authentication; media never reaches it from any source other than maintainer fixtures or rights-attested uploads.

6. Incident response

  1. Contain: disable the affected endpoint (wrangler route removal or an immediate deploy of a refusing worker), rotate the Cloudflare API credentials and any scanner tokens, delete rows known to be affected.
  2. Assess: what classes (section 4) and which time window were exposed; record the incident with timestamps in the maintainer's incident log.
  3. Notify: users through a one-time in-extension notice and the website; the competent supervisory authority within 72 hours of becoming aware where GDPR requires it; affected creators directly when uploads are involved.
  4. Follow-up: a CHANGELOG entry and, where practices change, a policy revision under the change-notification rule.

7. Provider authorization and rights attestation

Manual report (shipped). The report page shows "The context below was captured when you clicked the report button. Review everything before submitting — nothing is sent without your explicit submit", the exact serialized payload under "Exactly what will be submitted", and, next to the note field, "Your note is stored on the report server when you submit. Do not include health details, names, or contact information." The Submit button is the consent. Each submitted report keeps its one-time deletion code on the device under "Previously submitted reports" with the explanation "Deleting removes the report and its note from the active database at once; Cloudflare's point-in-time backup history can still contain them for up to 30 days before it expires."

Optional diagnostics bundle. Not implemented. If added, it is a separate unchecked checkbox on the report page with its own field list.

Exact video lookup (PROPOSED, #121). Options toggle, off by default, with: "When on, TameFlash sends the identifier of the YouTube video you are watching to api.tameflash.com to check it against verified hazard records. This reveals what you watch to the service at that moment. Cloudflare still handles your IP address and the time of the request. Nothing is stored about the lookup." The toggle shows the exact request body before enabling.

Automatic detector-evidence sharing (PROPOSED, #121). Separate toggle, off by default: "When on, TameFlash uploads one summary per video of what its detector found (video identifier, hazard intervals, detector settings profile). It never uploads frames, notes, your settings strength, or anything about ads or live streams." The toggle shows an example payload before enabling.

Creator upload (PROPOSED, #124). The attestation in section 7, unchecked, followed by the limits and the deletion schedule, on the preflight page.

9. Your rights and how to exercise them

10. Store disclosures (Chrome Web Store, AMO)

Mapping to the Chrome Web Store user-data policy and disclosure requirements, and to AMO's privacy questions:

11. Change log