Methodology
Last updated
The claim being tested
100% Private & Local — Your data never leaves your browser. These QR codes are permanent and will never expire.
The first half of that sentence is a claim about behaviour, and behaviour can be observed. This page gives you four ways to check it, in ascending order of how conclusive they are, plus an honest account of what none of them can prove. None requires anything beyond a browser.
Test one: watch the network panel
- Open any generator page on this site.
- Open developer tools. In Chrome, Edge or Firefox that is F12, or Ctrl+Shift+I; on a Mac, Cmd+Option+I. In Safari, enable the Develop menu first in Settings, under Advanced.
- Select the Network panel and reload the page. You will see the document, a handful of stylesheets,
/theme.js, the JavaScript chunks that hydrate the workspace and the web manifest. A moment after the page finishes loading you will also see/service-worker.jsand the few pages that worker stores so the site opens without a connection. Every one of them is served from this domain; there is no request to any other host, because the site loads nothing from anywhere else. - Let the panel settle, then clear the network log so it is empty.
- Now use the tool. Type a password into a Wi-Fi field, change the colours, choose a logo image, switch the error correction level, and export the file.
- Look at the panel. It is still empty. Not "requests without your data in them" — no requests at all. The exported file was produced in the page, and the download comes from a
blob:URL created in the tab rather than from a server.
Filtering the panel to Fetch/XHR makes the point cleaner. The only entries that ever appear there are the service worker storing this site's own pages, in the second or two after the document loads. From the moment you start typing to the moment the file lands in your downloads, nothing is added to it.
Test two: pull the plug
The blunter version of the same test, and the more convincing one, because it removes the possibility of a request you failed to notice.
- Load a generator page normally and let it finish loading.
- Disconnect from the network: switch off Wi-Fi, or set the Network panel's throttling menu to Offline.
- Complete the form, style the symbol, add a logo and export a PNG, a WebP or an SVG. All of it works, offline, because none of it ever needed a server.
- Reloading while still offline is a second, separate test, and it depends on what this device has already stored. A service worker registers once the first page of your visit has finished loading, and from then on it keeps a copy of every page it fetches — so a page you have opened since then comes back from that copy rather than from the network. A page it has never stored, which on a first visit is most of the site, shows the offline notice instead. That is the honest answer rather than a broken tab, and it is why this test is about reloading a page you have already been to.
A tool that sent your input somewhere would fail this test in an obvious way: the export would hang, or error, or silently return nothing.
Test three: read the response headers
- In the Network panel, click the request for the HTML document itself.
- Open the Headers view and find the Response Headers section.
- Read the
Content-Security-Policyvalue. Two directives in it are the ones that matter here:connect-src 'self'means the browser will refuse any connection this page tries to open to another origin, andform-action 'none'means it will refuse to submit a form on this site to anywhere at all.
This is stronger than the first two tests, because it is not a statement about what the code does — it is a rule your own browser enforces against the code, whatever the code turns out to be. The security page prints the whole header set, and explains the one respect in which the deployed policy is stricter than the block it prints.
Test four: read the page itself
- View the source of any page with Ctrl+U or Cmd+Option+U.
- Search the source for
<script— the opening tag, not the word, which also appears in the copy. A generator page has six of them. One carries asrcand points at/theme.json this domain: that is the code that applies your saved theme before the page paints, and it is a file rather than an inline block so the security policy needs no exception for it. Three are markedtype="application/ld+json"— structured data for search engines, which the browser parses as data and never executes. The last two are Astro's island bootstrap, the custom element that hands the workspace over to JavaScript, and they are the only inline code on the page that runs. The home page carries the same workspace with one structured-data block instead of three, so it has four. This page you are reading has exactly one: the/theme.jsfile, and nothing inline at all. - There is no third-party tag of any kind: no analytics snippet, no tag manager, no ad script, no consent platform, no font from another host, no tracking pixel.
- The document is already complete. The copy, the sections, the questions and answers and the workspace markup itself are all in the HTML before any JavaScript runs — the page was built once, ahead of time, and the same file is served to everyone. JavaScript takes over the form it finds rather than creating the page.
What the build refuses to ship
These are internal checks: this site's source is not published, so you cannot inspect them directly, and they are listed as context for the tests above rather than as evidence in their own right. Each stops a release rather than printing a warning.
- A source scan for the browser's request primitives and for any identifier that names sending bytes somewhere. The permitted-exception list is empty.
- A scan of both the source and the built output for third-party hosts — CDNs, font services, analytics endpoints, ad networks — in markup, styles, scripts and comments alike.
- A check of the built output that fails if it contains a server function or worker bundle of any kind, if any emitted file names an external origin, or if an inline script or style appears that the Content Security Policy does not already cover by hash.
- A check that no unfinished text — a marker, a stub, an empty required field — reaches a published page.
What none of this proves
The tests above are about OpenQRS. They say nothing about the rest of your machine, and this page will not pretend otherwise:
- A browser extension can read the contents of any page you open, including this one. Nothing a website does can prevent that.
- Your operating system can see anything you type, into any application.
- Your network operator and DNS resolver can see that you connected to this domain, even though they cannot see the contents of the page or anything you did in it.
- The host serving the files processes the requests needed to deliver them, in the way every web host does. See the privacy statement.
What is deliberately not promised
- Not that every code will scan on every device. Camera apps and readers differ, and a payload format that opens a dialog on one phone shows as raw text on another. Test your artwork before a print run.
- Not that a destination will keep working. The symbol is permanent; the website behind it belongs to somebody who can take it down.
- Not a performance score. Laboratory numbers depend on the device and the connection, so none is quoted as a guarantee.
- Not that a styled code stays readable. Heavy styling, a large logo or a reduced quiet zone all cost scan reliability. The workspace warns where it can, and the finished artwork is still your decision.