Key facts
The Web Cryptography API specification "provides no lower-bound on the information theoretic entropy present in cryptographically strong random values" and advises seeding from an OS source such as /dev/urandom.
W3C — Web Cryptography APIcrypto.getRandomValues returns cryptographically strong values from a PRNG seeded with high-entropy input, is capped at 65,536 bytes per call, and is not the recommended path for key generation.
MDN Web Docs — Crypto.getRandomValues()NIST SP 800-90A Rev. 1 (June 2015) specifies deterministic random bit generator mechanisms built on hash functions or block cipher algorithms.
NIST Special Publication 800-90A Rev. 1Mulberry32 uses a 32-bit state, giving a period of around 4 billion, and one analysis notes it appears to skip roughly a third of all 32-bit values.
bryc — JavaScript PRNGs referenceComputed by us: folding a 0–255 source into a 1–100 range with a remainder makes 56 of the 100 outcomes 50% more likely, because 256 = 2 × 100 + 56.
Vibe Numbers — worked example of modulo bias
Three things people mean by random
True randomness comes from a physical process nobody can predict: radioactive decay, thermal noise in a resistor, the jitter between hardware interrupts. There is no formula behind it because there is no formula.
Pseudorandomness comes from an algorithm. You give it a starting number, called the seed, and it produces a sequence that passes statistical tests for randomness while being entirely determined. Same seed, same sequence, every time, on every machine. That reproducibility is a feature in simulations, games and anything that has to be replayed.
Cryptographic randomness sits between the two. It is still an algorithm, but seeded from a pool of genuine physical entropy the operating system collects, and built so that seeing part of the output tells you nothing useful about the rest. NIST's SP 800-90A specifies the standard constructions, all built on hash functions or block ciphers.
The distinction that matters is not "real versus fake". It is whether the sequence can be reproduced by someone who knows how it started.
How a pseudorandom generator works
Underneath, a PRNG is a small piece of memory called the state and a rule for scrambling it. Each time you ask for a number, the rule updates the state and squeezes an output out of it.
Because the state is finite, the sequence must eventually repeat. A generator with a 32-bit state has at most about 4.3 billion distinct states, so its period is capped there. That sounds enormous and is far too short for cryptography, where an attacker would simply search the space.
The seed decides which point in that cycle you start from. This is the whole trick behind reproducible randomness: fix the seed and you fix everything that follows.
The generator behind our daily numbers
The daily lucky numbers on this site are seeded and deterministic on purpose, and the code is public in core/rng.ts.
The seed is built by joining your birth date, today's date and the name of the tool into one string, so a set is a function of exactly those three things. That string goes through xmur3, a hash based on MurmurHash3's mixing function, which folds any-length text down to a single 32-bit value. That value becomes the starting state of Mulberry32, a minimal 32-bit generator that returns doubles in the range 0 to 1.
The consequence is the thing we want. Your numbers hold still from midnight to midnight, change when the date changes because the date is an ingredient rather than a timer, and come out identical on your phone and your laptop. Open how it works and you will find a worked example computed from a fixed seed, which you can recompute yourself and get the same six numbers.
One thing this is not: Mulberry32 is not secure, has a period of only about 4 billion, and by one analysis skips roughly a third of all possible 32-bit outputs. None of that matters for drawing a lucky number and all of it would matter for a key. It is a fairness generator, not a security generator.
The generator behind the dice, coins and pickers
The random tools work the opposite way and share no code with the daily numbers. They call crypto.getRandomValues, the browser's cryptographic random source, which MDN describes as producing cryptographically strong values from a PRNG seeded with high-entropy input. There is no seed we control and no way to reproduce a roll.
Getting from raw random bits to a fair die roll is where most implementations quietly go wrong. The obvious approach is to take a random integer and use the remainder, x % 6. That is biased whenever the range of x is not an exact multiple of 6.
The bias is easy to see at small scale. Take a source producing values 0 to 255 and ask for a number from 1 to 100. Since 256 = 2 × 100 + 56, the remainders 0 to 55 can be reached three ways and 56 to 99 only two, so 56 of the hundred outcomes come up 50% more often than the rest. Nothing about the source is at fault; the folding is.
Our fix is rejection sampling, and it is in components/random/random.ts. We compute the largest multiple of the range that fits inside 2³², draw a 32-bit value, and if it lands above that cut we throw it away and draw again. What survives is exactly uniform. The cost is a repeat draw on a vanishingly small fraction of calls.
Cryptographic does not mean magical
Two honest caveats belong here, and both come from the specifications rather than from us.
The Web Cryptography API sets no floor on entropy. Its own words: the specification "provides no lower-bound on the information theoretic entropy present in cryptographically strong random values", and it advises implementers to seed from an operating-system source such as /dev/urandom. In practice every current browser does exactly that. The guarantee is a strong convention, not a mathematical certificate.
The API also declines to be everything. MDN steers key generation towards generateKey() rather than getRandomValues, and caps a single call at 65,536 bytes. For rolling dice and drawing lottery lines this is comfortably the right tool. For encrypting anything, it is not the whole answer.
When a seed is the right answer
Seeded randomness has a reputation problem it does not deserve. In a great deal of software it is the correct engineering choice, not a compromise.
Game replays and speedrun verification need it: the same seed replays the same run, so a recording can be checked rather than trusted. Procedurally generated worlds need it, which is why a game can hand you a short string that reconstructs an entire landscape. Scientific simulation needs it, because a result nobody can reproduce is not a result. A/B testing needs it, since a user has to land in the same bucket on every visit.
Our daily numbers sit in that family. The product is not unpredictability, it is the ability to open the site on a second device and see the same set. A truly random daily number would be indistinguishable from the site making something up each time you looked.
The inverse rule is where a seed becomes a defect. Anywhere an adversary profits from predicting the next output, a reproducible generator is a vulnerability: session tokens, password reset links, shuffle order in a real-money card game. Those need cryptographic randomness, and NIST's SP 800-90A exists because getting it wrong has a long history.
The two are not better and worse versions of the same thing. They answer opposite questions, and the mistake is only ever using one where the other belongs.
Checking any of this for yourself
The daily numbers are the easy one. Load the same page on two devices with the same birth date set and compare. If the sets differ, our claim is wrong and we would want to hear about it.
The random tools are checkable in the opposite direction. Roll the same die repeatedly and the outcomes should not repeat in any pattern, and no share button should ever reproduce a past roll from a link. Both tools keep a local history so you can look back at the spread yourself.
The deeper check is the source. Both generators are a few dozen lines each, they are named in this guide, and they ship unminified in a public static build. A claim about randomness that cannot be inspected is just a claim.
How Random Is Random? — frequently asked
Reproducibility. Pseudorandom output comes from a formula and a starting seed, so anyone holding both can regenerate the whole sequence. Genuinely random output cannot be regenerated by anything, including the machine that produced it.
Deliberately not. They are seeded from your birth date and today's date, which is why they hold still all day and match across your devices.
It is a cryptographically strong pseudorandom generator seeded from the operating system's entropy pool, which is not the same thing as a physical noise source. The Web Cryptography specification is candid about that: it sets no lower bound on the entropy present and only advises implementers to seed from something like /dev/urandom. Every current browser does. For rolling a die that is far more assurance than the job needs.
It means throwing away any random value that falls outside a clean multiple of your target range and drawing again. Skip it and the leftovers bias you. Folding a 0–255 source into 1–100 makes 56 of the hundred outcomes come up half again as often as the rest, because 256 is not a multiple of 100.
A seeded one can, trivially, by choosing the seed. That is why our tools take no seed and our daily numbers publish theirs.