Behind the button
How this random number generator works
You tap, a number appears. Here is everything that happens in between, in plain words — plus a test you can run on us any time you like.
Skip to the testStep one: ask the device for noise.
When you tap, the page calls a browser function named crypto.getRandomValues(). It is part of the Web Cryptography API, the same toolkit browsers use to protect passwords and payments. The W3C specification describes it as a cryptographically strong pseudo-random number generator seeded with truly random values, and asks browser makers to feed it from a high-quality source such as the operating system’s own entropy pool.
That pool is built from things no one can predict in advance: tiny timing differences in hardware, and on many devices a dedicated random-number circuit. Your browser stirs it into a stream of bits and hands us 64 of them per request.
Isn’t that “pseudo”-random, then?
Yes, and that is normal. MDN puts it plainly: to be fast enough, implementations use a pseudo-random generator seeded with enough entropy, and the algorithm is “suitable for cryptographic purposes”. The seed is the unpredictable part; the generator stretches it securely. For picking a raffle winner or a dice roll, this is far more than you need. The same page notes it is the only part of the Crypto interface that works on an ordinary (non-HTTPS) page, though we serve everything over HTTPS anyway.
Step two: fit the noise to your range — without bending it.
Sixty-four random bits give a number from 0 to about 18 quintillion. You asked for, say, 1 to 6. The tempting shortcut is to divide and keep the remainder. The trouble is that 18 quintillion is not a multiple of 6, so the remainders are not quite evenly shared: a few results would come up a hair more often than the others. That is called modulo bias.
We use the honest fix, rejection sampling. Work out the largest multiple of 6 that fits, and if the 64-bit number lands in the leftover sliver at the top, throw it away and ask for a fresh one. What survives is perfectly even. The sliver is so thin that a second try is almost never needed.
Show me the actual rule
With a range of n numbers and a 64-bit draw v: let cutoff = 264 − (264 mod n). If v ≥ cutoff, draw again. Otherwise the result is low + (v mod n). The arithmetic runs on big integers, so even a range spanning both ends of JavaScript’s safe integers (±9,007,199,254,740,991) is handled exactly. You can read the twelve lines yourself in number-model.mjs.
What we don’t do.
- No server. The number is made on your device. Nothing you type and nothing you draw is sent anywhere. (Optional, consent-based analytics record only that a tool was used, never the result.)
- No memory. Each tap is a fresh draw. The generator does not know what came before and does not try to “balance” results — which is why repeats happen, as this story explains.
- No
Math.random()for the main picker. JavaScript’s everyday random function is fine for games, but MDN is explicit that it does not provide cryptographically secure numbers. The number generator, the dice, the coin and the lottery picker all use the Web Crypto path described above. A few of our list tools — the letter picker, name picker, list shuffler, team picker and raffle picker — still useMath.random()for their choice. For a classroom draw the difference is invisible; we say so on those pages, and this page will be updated when they move over. - No passwords. This is a tool for choosing numbers, not for making secrets. For passwords use a password manager; for keys, use software built for that job.
Test it yourself.
We’ll draw thousands of numbers right now, in your browser, and run the same first check statisticians use on any generator: are the counts as even as chance allows?
Press the button. Each bar is one number’s count; the dashed line is the even share.
Nothing has been drawn yet.
This is Pearson’s chi-square goodness-of-fit test. The p-value is the chance that a perfectly fair source would produce a spread at least this uneven. Small p-values are not proof of a problem — a fair source produces p < 0.05 one run in twenty. The draws stay on your device.
What that test can and can’t tell you.
An even count is necessary but not sufficient. A “generator” that simply counted 1, 2, 3, 4, 5, 6, 1, 2, 3… would pass this test perfectly and be useless. Serious evaluations, such as the battery described in NIST Special Publication 800-22, run many different tests: runs and streaks, patterns in blocks, how often templates appear, and more. The system source behind getRandomValues() is designed and reviewed against that kind of scrutiny; our contribution is simply not to spoil it on the way to your screen.
If you ever see the test fail repeatedly — not once, which is expected, but run after run — we would like to know. Here is how to reach us.
Three honest limits.
- We can’t audit your device. If an operating system’s random source were broken, every app on it would share the problem, and we would inherit it.
- We don’t certify draws. For a prize draw that must be provably fair to outsiders, keep a record and draw in front of witnesses; our raffle guide explains a sensible procedure.
- We don’t generate secrets. See “No passwords”, above. We mean it.
Now that you know what’s under the button…
Set a range and tap. Nothing leaves your device.
Pick a random numberWhere we looked things up
- Crypto.getRandomValues() — MDN Web Docs
- Web Cryptography API — W3C specification
- Math.random() — MDN Web Docs
- Chi-square goodness-of-fit test — NIST/SEMATECH e-Handbook
- SP 800-22 Rev. 1a, A Statistical Test Suite for Random and Pseudorandom Number Generators — NIST
- The picker’s source code (number-model.mjs)