Why Math.random() Is Not Safe for Giveaways
Browser-side randomization is invisible to your audience — and that's a problem when trust is on the line.
The Hidden Problem With "Random"
You run a giveaway. The wheel spins. A name lights up. You announce the winner — and immediately someone in chat types: "rigged."
Most of the time, that person is wrong. But here's the uncomfortable truth: with browser-based wheel spinners, there is genuinely no way to prove them wrong after the fact. That's not a bug in your process — it's a fundamental limitation of how most randomizer tools are built.
How Most Wheel Spinners Generate "Random" Numbers
Open the source code of the most popular wheel spinner tools and you'll find something like this:
// How most free wheel spinners pick a winner
const winnerIndex = Math.floor(Math.random() * entries.length);
Math.random() is a pseudo-random number generator (PRNG). It produces numbers that look random but are determined by a starting seed value. The same seed always produces the same sequence. More importantly, it runs entirely in your browser — meaning the decision is made on your device before anything is displayed on screen.
Why This Matters for Live Giveaways
There are three specific problems with client-side randomization for giveaways:
- No independent verification. The number was generated by JavaScript running on the host's device. There's no way for a viewer or participant to confirm the result wasn't pre-determined or altered.
- No durable record. Once you reload the page, the history is gone. There's no signed receipt, no hash chain, no audit trail.
- Perceived manipulation risk. Even if you're 100% honest, you can't prove it. In a world where audience trust is currency, "you'll just have to believe me" is a losing position.
Most tools that use window.crypto.getRandomValues() are better than Math.random() — but they still run in the browser, and they still produce no verifiable receipt.
What Server-Side CSPRNG Actually Means
A cryptographically secure pseudo-random number generator (CSPRNG) is designed to be statistically unpredictable. Node.js exposes one via crypto.randomInt(). When a spin happens on Picksy, the outcome is determined by:
// Server-side: outcome is decided before it reaches the browser
const { randomInt } = require('crypto');
const winnerIndex = randomInt(0, entries.length);
This matters for two reasons. First, it runs on the server — not in the browser — so there is no client-side code the host could modify. Second, it produces output suitable for security-sensitive applications (not just casual games), as defined by NIST SP 800-90A.
The Missing Piece: Verifiable Receipts
Even server-side randomization doesn't fully solve the trust problem unless it comes with a receipt. Picksy generates a SHA-256 hash of each spin result, chained to the previous one — similar to how blockchain systems ensure tamper-evidence.
After every spin, a public audit link is generated. That link shows:
- The exact timestamp of the spin
- The input (all entries at the time of the spin)
- The outcome (winner selected)
- The SHA-256 hash for that result
- The hash of every previous result in the chain
Anyone — your audience, your platform, a third party — can visit that link and verify independently that the outcome matches the record and that nothing in the chain has been altered.
The Practical Takeaway
For casual, low-stakes spins, Math.random() is fine. No one's going to dispute who gets extra homework problems.
But for anything where real value changes hands — prizes, subscriptions, free products, cash, tickets — you need two things: server-side randomization that can't be client-manipulated, and a shareable receipt that proves it after the fact. That's what Picksy Proof is built to provide.