Why a Truly Fair Coin Flip Is Harder to Code Than It Sounds
Published 2026-09-14
Not all "random" is equally random
JavaScript's built-in Math.random() is a pseudo-random number generator, designed for speed and general-purpose use, not for unpredictability against someone trying to game the outcome. Its internal algorithm is deterministic: given the same starting state, it produces the same sequence every time, and in principle its output pattern can be studied and predicted.
What crypto.getRandomValues() does differently
The Web Crypto API's crypto.getRandomValues() draws from the operating system's cryptographically secure random number source — the same quality of randomness used to generate encryption keys. It's built specifically to be unpredictable even to someone who understands the algorithm completely, which is a meaningfully stronger guarantee than Math.random() offers.
Does it matter for a casual dice roll?
For settling a friendly decision or rolling dice in a low-stakes game, either source is practically fine — nobody is cryptanalyzing your Monopoly turn order. But using the stronger source costs nothing extra to implement, and it matters a great deal the moment "random" outcomes have any real value attached, like a randomized prize draw or anything resembling gambling, where a predictable pattern could be actively exploited.
Try it yourself
Our Dice Roller & Coin Flip uses crypto.getRandomValues() for every roll and flip, so the randomness behind it holds up to the stronger standard even though the use case is casual.