How randomness works in your browser
Every RandoKit result comes from the same short pipeline: entropy collected by your operating system, a cryptographic generator, unbiased mapping onto your entries, and a shuffle that treats every ordering equally. Here is what each of those steps does.
A computer is a deterministic machine
Run the same program twice with the same inputs and you get the same output. That is the whole point of a processor, and it is why software cannot conjure randomness out of arithmetic alone. What it can do is measure the messy physical world it lives in: the exact microsecond a network packet arrived, jitter between hardware clocks, noise from a dedicated on-chip source, the timing of key presses. These measurements are unpredictable in their low bits, and the operating system mixes them into a pool of entropy.
That pool is small and slow to refill, so it is not handed out directly. Instead it seeds a cryptographically secure pseudorandom number generator (CSPRNG), which stretches a few hundred bits of genuine unpredictability into as much output as you need. The guarantee a CSPRNG makes is precise and worth stating carefully: given any amount of its previous output, no practical computation recovers the internal state or predicts the next value.
Two random APIs, two very different jobs
Browsers expose randomness twice. Math.random() is a fast, ordinary pseudorandom generator. It is perfect for scattering particles in an animation and unsuitable for anything a person might contest, because its internal state can be inferred from enough observed output.
crypto.getRandomValues() is the one RandoKit uses. It fills a typed array with bytes from the platform CSPRNG:
const buf = new Uint32Array(4);
crypto.getRandomValues(buf);
// Uint32Array(4) [ 2419513288, 771049255, 4084221171, 33920617 ]The full comparison, including performance and when the cheaper API is genuinely the right call, is in the guide on Math.random versus crypto.getRandomValues.
Turning random bytes into a fair pick
Random bytes are uniform over 0–255. Your wheel has six names. The obvious conversion is the wrong one:
const index = randomByte % 6; // don't do thisThere are 256 possible bytes and 256 divided by 6 is 42 remainder 4. Indices 0, 1, 2 and 3 are produced by 43 different bytes each; indices 4 and 5 by only 42. That is a 2.4% edge for four of your six names — invisible on a single spin, and exactly the kind of thing that makes a repeated draw indefensible.
The fix is rejection sampling: throw away the unbalanced tail.
- Compute the largest multiple of 6 that fits in the range: 252.
- Draw a byte. If it is 252 or higher, discard it and draw again.
- Otherwise return the byte modulo 6.
Each remaining index now corresponds to exactly 42 byte values, so every name has an identical chance. Roughly 1.6% of draws are discarded, which costs microseconds. RandoKit applies this to every integer it generates, from a d20 roll to a range on the random number generator.
Shuffling: why the algorithm matters
Ordering a list is a different problem from picking one item, and it has a famous wrong answer. Sorting a list by a random comparator — sort(() => Math.random() - 0.5) — is not a shuffle. The result depends on the sorting algorithm’s internals and produces measurably lopsided distributions, with items near their starting position far too often.
The correct method is the Fisher-Yates shuffle. Walk the list from the end to the start; at each position, swap the current item with an item chosen uniformly from the part of the list not yet fixed. Each of the n! possible orderings comes out with equal probability, provided the index at each step is drawn without bias — which is why the two halves of this page belong together.
What that means in practice
- Running orders. One shuffle gives you a complete, repeat-free order — see randomizing presentation order.
- Multiple winners. Shuffle once and take the first three names rather than re-running a single-winner draw, which can hand the prize to the same person twice. Picking without repeats covers the trade-offs.
- Teams. Shuffle, then deal the list out like cards, which distributes any remainder evenly. That is exactly what the team generator does.
What fairness actually requires
A correct generator is necessary and not sufficient. The people affected by a draw judge it by the process around it, and that part is yours to design.
Be honest about the limits, too. A browser-side draw stores no seed and produces no receipt, so a determined sceptic cannot replay it and confirm the number that came out. What they can verify is that you announced the rules first, drew once, and published the result. For a classroom or a prize draw that is enough; for a regulated lottery it is not, and you should be using an audited provider. The giveaway guide walks through the difference.
Where your list goes
Nowhere. All of the above happens in the tab you have open. Entries stay in memory and in your browser’s local storage so a refresh does not wipe them, and nothing you type is transmitted to us. More detail is on the about page and in the privacy policy.