How Our Random Number Generator Works
A short technical explanation of the algorithm, statistical properties, and why it matters for fair draws.
Summary
Every number on onlinerandomnumber.com is drawn from the browser's Web Crypto API — specifically crypto.getRandomValues(), a cryptographically secure pseudo-random number generator (CSPRNG). We apply rejection sampling to convert 32-bit random words into uniform integers in your chosen range, eliminating the modulo bias that affects naive implementations. Each integer in your range has exactly equal probability.
Why Not Math.random()?
JavaScript's Math.random() is a pseudo-random generator designed for speed, not unpredictability. Its internal state can be partially reconstructed from observed outputs, which means a motivated adversary could predict future values. For games and trivial decisions this is fine. For giveaways, raffles, and anywhere the result has real consequences, it is not.
crypto.getRandomValues() uses the operating system's secure random source (e.g., /dev/urandom on Linux, BCryptGenRandom on Windows). Its output is statistically indistinguishable from true random and computationally infeasible to predict.
| Property | Math.random() | crypto.getRandomValues() |
|---|---|---|
| Predictability | Partially predictable | Computationally infeasible |
| Statistical quality | Good | Excellent |
| Speed | Very fast | Fast |
| Suitable for fair draws? | Marginal | Yes |
| Suitable for cryptographic keys? | No | Yes |
Modulo Bias and How We Avoid It
The obvious way to turn a random 32-bit integer into a number in [min, max] is:
// BAD: introduces modulo bias
const range = max - min + 1;
const x = crypto.getRandomValues(new Uint32Array(1))[0];
return min + (x % range);
If range does not evenly divide 2³², the lower values in the range are slightly more likely than the upper values. For range = 10, the bias is negligible (~10⁻⁹). For larger ranges or higher-stakes draws, it matters.
We use rejection sampling: draw a 32-bit random word, discard it if it falls outside the largest multiple of range below 2³², and retry. This guarantees a perfectly uniform distribution.
function secureRandomInt(min, max) {
const range = max - min + 1;
const maxUint32 = 0xFFFFFFFF;
const limit = maxUint32 - (maxUint32 % range) - 1;
const buf = new Uint32Array(1);
let x;
do {
crypto.getRandomValues(buf);
x = buf[0];
} while (x > limit);
return min + (x % range);
}
Statistical Properties
- Uniform: every integer in
[min, max]has probability exactly1 / (max - min + 1). - Independent: each draw is independent of the previous — no "due" numbers, no streaks other than those expected by chance.
- Unbiased: no modulo bias, no floating-point bias.
When to Use True Random Instead
For almost every everyday purpose — giveaways, games, research sampling, naming, team assignment — CSPRNG is the right choice. It is fast, free, and statistically equivalent to true random.
Use a dedicated true-random service when you need:
- Physical randomness for cryptographic key material (hardware RNG, atmospheric noise, quantum).
- Externally auditable draws for regulated lotteries or legal proceedings.
- Public, timestamped randomness as a trust anchor (e.g., drand).
For these cases, services like RANDOM.ORG (atmospheric noise) or the NIST Randomness Beacon provide certified true-random bits.
Privacy
Random number generation happens entirely in your browser. We never see your ranges or results. Analytics (Google Analytics) track page-level usage only. Shared result URLs encode range and result in the query string; only the person you send the link to can see it.