October 31, 2026
The Booking Widget That Took Your Browser’s Fingerprint
Clearing cookies doesn’t change your GPU. A look at the scripts on a checkout page, and what they can learn about a device without storing…

By Tinguyen
9 min read
Clearing cookies doesn't change your GPU. A look at the scripts on a checkout page, and what they can learn about a device without storing anything at all.
Open almost any event checkout page. Before you pick a seat, open DevTools and switch to the Network tab.
You'll see a lot more than the booking form. There's the payment provider's script. There's often an anti-fraud script, sometimes loaded by the payment provider itself. There's analytics, a chat bubble, maybe a tag manager that pulls in three more things nobody remembers adding. Some of them run in iframes. Some run right on the page.
I build an event-booking platform in Ho Chi Minh City, so I spend more time than most people looking at that list. One question keeps coming back to me, and I think a lot of builders get it wrong:
If a user blocks cookies, clears storage, and books in a private window, what can those scripts still learn about them?
Quite a lot. The essay Fingerprints are the new cookies on royfish.dev lays it out well. It walks through how browser fingerprinting works and argues that it's replacing the cookie as the industry's default way to track people. I want to take that argument somewhere smaller: the booking widget, and the person who chose to embed it.
The cookie was always the polite version
The difference between the two is the whole story, so it's worth getting straight first.
A cookie is state. A server hands your browser a short string and asks for it back later. It lives on your device. You can see it, delete it, block it, or let the browser partition it so a script on one site can't read what it stored on another. Nearly every privacy tool of the last decade, from consent banners to Safari's tracking prevention, assumes that tracking means storing something.
A fingerprint isn't stored anywhere. It's computed.
The script asks your browser a pile of harmless-looking questions. What time zone are you in? How many CPU cores do you have? What GPU? What does this exact line of text look like when you draw it? Then it hashes the answers together. If you come back tomorrow it asks again, gets the same answers, and ends up with the same hash. Nothing was saved on your machine, so there's nothing for you to clear.
Deleting cookies doesn't change your graphics card. Incognito doesn't swap out your fonts.
That's why I call the cookie the polite version. You could find it and delete it. A fingerprint is built from the device itself.
How a browser gives itself away
The essay goes through the main signals one at a time. That's the right way to read them, because each one looks harmless when you see it alone.
Canvas. The script draws text and an emoji into an invisible <canvas> element and reads the pixels back. Your operating system, fonts, GPU and anti-aliasing all shift those pixels slightly. Two machines that look identical to you will produce slightly different images. Roughly:
const c = document.createElement("canvas");
const ctx = c.getContext("2d");
ctx.textBaseline = "top";
ctx.font = "16px Arial";
ctx.fillStyle = "#f60";
ctx.fillRect(10, 1, 62, 20);
ctx.fillStyle = "#069";
ctx.fillText("Book now 🎟️", 2, 15);
const data = c.toDataURL(); // hash thisconst c = document.createElement("canvas");
const ctx = c.getContext("2d");
ctx.textBaseline = "top";
ctx.font = "16px Arial";
ctx.fillStyle = "#f60";
ctx.fillRect(10, 1, 62, 20);
ctx.fillStyle = "#069";
ctx.fillText("Book now 🎟️", 2, 15);
const data = c.toDataURL(); // hash thisThere's no permission prompt and no warning. As far as the browser can tell, the page is just drawing something.
WebGL. It's the same trick, aimed at the GPU. The script can often read the graphics vendor and renderer strings directly, along with a long list of supported extensions and limits. Then it renders a scene and hashes the result.
Audio. An OfflineAudioContext lets a page generate and process sound without playing it. If you run an oscillator through a compressor, the floating-point output varies slightly with the CPU and audio stack. Nobody hears anything.
Intl. The [Intl](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl) API reports your time zone, locale, calendar and number formatting. The essay points out something easy to miss: a VPN changes your IP address, but your browser still reports the real time zone. A Vietnamese locale with Asia/Ho_Chi_Minh is ordinary here. Add an English UI and a European date format and the combination is already less common.
Navigator. This gives core count through hardwareConcurrency, a rounded memory figure through deviceMemory in Chromium browsers, plus languages, platform and touch support.
Then crypto.subtle hashes it all into one short ID. The essay's live demo turns that hash into a nickname for whoever is reading it. It's a nice touch, because it makes clear that the "anonymous" visitor now has a name.
Why a handful of boring facts is enough
The obvious objection: lots of people have an iPhone, and lots of people share my time zone. How does any of this pick one person out?
The essay answers with information entropy. It's the part I most wish more engineers understood.
Think of each trait as shrinking the group you could be in. A trait that splits people 50/50 is worth one bit. A trait shared by 1 in 128 people is worth seven bits. When traits are independent, the bits add up, so the group shrinks by multiplying. Getting down to one person out of roughly eight billion takes about 33 bits, since ²³³ is a little over 8.5 billion.
Thirty-three bits isn't much. A time zone gives a few. Screen resolution plus device pixel ratio gives a few more. A canvas hash can give a lot, because the number of possible renderings is huge. And as the essay says, a fingerprint doesn't need to be globally unique. It only needs to be unique enough to tell visitors apart on one site.
None of this is new. In 2000, Latanya Sweeney estimated that ZIP code, birth date and sex were enough to uniquely identify about 87% of Americans. Later work using newer census data put the figure closer to 60%. The exact number moved, but the lesson didn't. Three boring fields, each shared by thousands of people, add up to something very close to a name.
A browser gives away far more than three fields.
You can check your own setup with the EFF's Cover Your Tracks. It shows how many bits each attribute reveals and whether your browser looks unique in their test sample. It's worth running at least once. A setup that feels completely ordinary can turn out to be rare.
Then the rules changed
For years the big platforms at least said fingerprinting was off limits. That's no longer the case.
Google told advertisers that starting 16 February 2025, its ad platform policies would no longer prohibit fingerprinting. The UK's Information Commissioner's Office called the change irresponsible. The ICO also quoted Google's own 2019 position back at it: fingerprinting doesn't meet users' expectations for privacy, because people can't easily consent to it the way they can with cookies.
The cookie side went the other way. In April 2025, Google said it would keep its current approach to third-party cookies in Chrome and drop the standalone choice prompt it had planned. Then in October 2025 it announced the retirement of most Privacy Sandbox technologies, the APIs that were supposed to replace third-party cookies with something gentler. Google gave low adoption as the reason.
The essay tells this as three acts: promise to kill cookies, offer an alternative that goes nowhere, then make room for something worse. You don't have to accept every part of that story to see where things ended up. Cookies stayed. Fingerprinting got a green light from the biggest ad platform on the web. And the industry learned that the stateless method is harder to see, harder to regulate, and harder to opt out of.
Back to the booking widget
This is where it stops being an ad-tech story and becomes my problem.
On a checkout page, most fingerprinting isn't for ads. It's for fraud. Payment providers and anti-bot vendors fingerprint devices because it works. Picture a stolen card used from a device that has made dozens of bookings across many merchants in an hour. Now picture a card used from a phone that has bought two concert tickets this year. Those look very different. Ticketing gets hit hard by scalpers and card testing, and device signals are one of the few defenses that hold up.
I'm not going to pretend that's sinister. If every fraud signal disappeared tomorrow, scalpers would get the inventory and organizers would get the chargebacks.
But that's the trap. "It's for fraud" is true, and it's also the cover story for whatever else comes along with it.
When I embed a vendor's script, I'm not adding a feature. I'm giving someone else's code access to my visitor's browser, the same access my own code has. If that script draws a canvas, reads the WebGL renderer and runs an audio context, it doesn't ask me first. The user has no idea which of the six scripts on the page did it. To them, it's just my booking page.
In Europe, the law has caught up with this. The European Data Protection Board's guidelines on Article 5(3) of the ePrivacy Directive, adopted in October 2024, make it clear that the consent rule was never really about cookies. It covers gaining access to information stored on the user's device, and that includes fingerprinting techniques. Calling something "not a cookie" doesn't get you out of it.
The ICO's position says the same thing more plainly. Fingerprinting has to be lawful and transparent, and businesses that use it are responsible for that.
So whoever picked the widget is responsible for the fingerprint. On my pages, that's me.
Why the usual defenses don't help
What surprised me most when I dug into this was how little of the standard privacy toolkit applies.
Storage partitioning doesn't help. It stops a script running under one site from reading storage set under another. A fingerprint has nothing stored to partition. It's recomputed fresh on every site.
Sandboxed iframes don't help much either. Putting a vendor in an iframe keeps it out of your DOM, which is good. But inside its own frame the script still has canvas, WebGL, audio and Intl, so it can fingerprint the device just as well.
Consent banners usually don't cover it. Most banners are wired to cookie categories. A fingerprinting script often loads under "strictly necessary" because it came bundled with payments.
Permissions-Policy can switch off the camera, geolocation and payment APIs for embedded content. It can't switch off canvas.
On the user's side, the essay is blunt: no extension beats protection built into the browser engine. Tools like JShelter can interfere with fingerprinting scripts, but they can break sites, and because so few people use them they can make you stand out more. The browsers that actually work take one of two approaches. Brave adds small random noise to canvas, audio and other outputs so the hash doesn't stay stable. Tor Browser and Mullvad Browser go the other way and make every user look the same. Safari and Firefox protect you partly, but you can still be picked out.
As a builder, I control none of that. I can't make my users switch browsers. I can control what runs on my page.
Where I've landed
These aren't a checklist. They're the rules I'm holding my own booking pages to.
Keep an inventory. Every third-party origin that loads on a booking page should be on a list with a reason next to it. If I can't write the reason in one sentence, the script shouldn't be there. Tag managers make this harder by design, because anyone with dashboard access can add a script without a deploy. On a checkout page I treat that as a bug, not a convenience.
Enforce it with a Content Security Policy. A strict script-src allowlist means a new vendor can't quietly appear on checkout because someone clicked a button in a dashboard. It won't stop a script I did allow from fingerprinting. What it does is make the list I keep and the list the browser enforces the same list.
Keep checkout boring. The pages where people type card numbers and names don't need chat widgets, heatmaps or retargeting pixels. Any script there has the same reach as my payment code. Fewer is better.
Ask vendors directly. Do you fingerprint? Which signals? How long do you keep the hash? Do you link it across merchants? Do you use it for anything besides fraud? A vendor I trust with checkout should be able to answer in writing. If the answer is vague, that tells me something.
Disclose it. If fraud prevention fingerprints devices on checkout, the privacy policy should say so in plain words, not tuck it under "similar technologies." In places with strict rules, users may need to be asked. Everywhere else, they still deserve to know.
Lean on the signals I already have. A lot of fraud detection works fine on server-side data: how often a card, email or IP range shows up, or a billing country that doesn't match the event city. Those raise privacy questions too. But they come from a transaction the user chose to make, not from probing their graphics card.
The thing I keep coming back to
The cookie era taught me to think of tracking as something that gets left behind. A file, a string, something you'd find in an audit.
Fingerprinting broke that model. Nothing gets left behind. The tracking happens through the questions the script asks, and asking those questions looks exactly like a page rendering normally.
So I can't audit for fingerprints the way I'd audit for cookies. I have to audit for who's allowed to ask. On my booking pages, that means whatever code I chose to load. Every script tag decides who gets to question a user's device while they're trying to buy a ticket.
I used to think of embeds as features I was adding.
Now I think of them as guests I'm letting into someone else's house. If one of them takes a fingerprint on the way out, the user won't blame the guest. They'll blame me, because I let them in.