Legal
Security
Last updated: October 31, 2026
This page is the data-handling record behind the privacy promise. The plain-English version is the privacy promise. The legal text is the privacy policy.
What a scan stores
A dynamic-code scan writes one row. The redirect is sent first. The row is written after the response.
- Country and city, from the hosting provider’s geo headers. City is stored in a canonical form. A street address and GPS coordinates are not stored.
- Device class (phone, tablet, or desktop) and OS family (for example iOS or Windows), parsed from the User-Agent. The model and the OS version are not stored.
- A daily fingerprint: SHA-256 of the IP address and the User-Agent, salted with the UTC date and a server secret. The raw IP is discarded. The same device on a later day produces a different fingerprint.
- Timestamp, an optional A/B variant letter, and the referring hostname when one is present. The referrer’s path and query are dropped.
Static downloads do not create a scan row. There is no server in the path after the file leaves the browser.
What an account stores
- Email and authentication are held by the database provider (Supabase Auth). QRBliss does not store a password in its own tables.
- QR records: the name, the type, the content, and the styling. A dynamic code also stores the destination URL and the short code.
- Logos for a signed-in library are stored as files in a private bucket. A logo used before sign-up stays in the browser until you claim it. Palette extraction for Brand Sync runs in the browser.
- Payment cards are entered on Stripe’s pages. QRBliss stores the Stripe customer id and the plan, not the card number.
Page analytics use Plausible, which does not set a tracking cookie, plus first-party event rows. Page-view rows can include country, device class, OS family, a daily fingerprint, a referring hostname, and allowlisted campaign parameters: utm_source,utm_medium, utm_campaign, utm_content,utm_term, and gclid. Those campaign fields are stored separately from the page path. The landing-page handoff puts what you typed into the URL; the typed contentvalue and other unapproved query parameters are discarded before storage. Other product events can also store an event type and related product metadata, and are associated with your account when you are signed in.
Who else receives data
- Supabase — database, authentication, and file storage.
- Vercel — hosting. Geo headers on a scan request are how country and city are derived.
- Stripe — subscriptions and invoices.
- Plausible — cookie-free page counts.
- Resend — transactional email, such as a safety notice or a billing message.
- Google Safe Browsing — the destination URL of a dynamic code is checked when you save it, and again on a schedule. A flagged URL is paused.
QRBliss does not sell scan data. Rate-limit keys are a salted hash of the IP address. The raw IP is not written to the database for that either.
How long it stays
The free plan’s scan dashboard shows the last 30 days. Pro and above show full history. Deleting the account cancels the Stripe subscription first, deletes uploaded files, and then deletes the auth user. Codes, dynamic destinations, and their scan rows are removed by database cascade. Page-level event rows lose the user id and remain as anonymous counts. Stripe keeps its own customer record under Stripe’s terms.
The steps are on the delete-account page.
Controls in the product
- HTTPS, and HSTS in production. Pages send a content security policy,
X-Content-Type-Options: nosniff, a frame-denial header, a referrer policy, and a permissions policy that turns off camera, microphone, and geolocation. - Row-level security is the authorization boundary. A signed-in request uses a user-scoped database client. The service-role client is reserved for the scan writer, the Stripe webhook, cron, and admin routes after an admin check.
- The Stripe webhook checks the signature before it changes a plan. Public API keys are stored as a hash. A key’s scopes are limited by plan.
- Dynamic destinations must be http or https URLs. Short links are served from qrbliss.com (or a verified custom domain). They are not pointed at the database host.
Independent assessment
A third-party penetration test has not been completed. As of October 31, 2026 there is no external report to publish. This section is the summary slot for that test. When a report exists, the firm, the date, the scope, and any finding that stayed open will be added here. A result will not be written on this page before that report is in hand.
The internal review on this date checked the controls in the section above against the code that ships them. It is a control inventory, not a penetration test.
The test we are asking an assessor to cover:
- The public site and the generator, signed out.
- Signed-in QR editing, dynamic rules, logo upload, and account deletion.
- The public API: key authentication, plan scopes, and quotas.
- The short-link resolver, including open redirects and destination checks.
- The Stripe webhook, and whether one account can read another account’s codes, scans, or files.
Researchers and test firms can send a report or a proposed scope to hello@qrbliss.com.