Random Picker
Fair and random selection tool for raffles, draws, and picks
What is a Random Picker?
A random picker selects one item from a list without requiring a person to choose manually. Common uses include classroom participation, meeting order, lightweight giveaways, task assignment, lunch choices, team warmups, and any situation where a visible neutral choice helps avoid bias. This page works with a line-by-line list, can animate the draw, can keep a local draw history, and can optionally avoid repeated selections by removing chosen items from the remaining pool. Randomness can make a choice fair in the statistical sense, but it does not validate identities, prevent duplicate names in the input, or provide audit evidence. For official raffles, compliance, eligibility checks, and prize distribution, use a process with records and rules appropriate to the event.
How to Use
Operation Steps
- Enter options in the text box, one per line
- Set the number of items to pick
- Choose whether to allow duplicates
- Click 'Start Draw' button
- View results on the right side
Fair Draw Tips
- Put one candidate per line and remove accidental blanks or duplicates unless duplicates are intentionally allowed.
- For public draws, decide the seed, duplicate rule, and redraw rule before starting so the result is easier to explain.
Use Cases
Technical Principle
Random Picker is built on the Web Crypto API (W3C, WHATWG), specifically crypto.getRandomValues(typedArray), which is the only cryptographically secure random source exposed in browsers. Under the hood the browser calls into the operating system's CSPRNG: CryptGenRandom on Windows (AES-256 in CTR-DRBG mode since Windows 10), getrandom(2) on Linux (which reads from the same ChaCha20-based pool that feeds the kernel's /dev/urandom), SecRandomCopyBytes on macOS, and the equivalent on iOS, Android, and BSD. The output is suitable for key generation, nonces, salts, IVs, and any place where predictability would be a security problem. The 'crypto-grade' distinction matters. Math.random() in V8 uses xorshift128+ (a fast, low-entropy algorithm) and returns a 64-bit float in [0, 1); a hostile actor who observes a few outputs can in principle reconstruct the 128-bit state and predict every future value. The same is true for SpiderMonkey and JavaScriptCore. This makes Math.random() unfit for any use where the result must be unguessable — fair selection of a winner, a token, a one-time password, a deal in a card game, an audit sample. crypto.getRandomValues(typedArray) is the only choice for those. Mapping uniform 32-bit integers to a uniform index in [0, N) without modulo bias is the second engineering detail that separates correct from broken. Naively, idx = randomUint32 % N is wrong: if N does not divide 2³², the first 2³² mod N values are slightly more likely. The correct algorithm is rejection sampling: compute limit = 2³² - (2³² mod N); draw a 32-bit value r; if r >= limit, redraw; otherwise return r % N. The bias falls from O(N / 2³²) to zero. For N = 2 or N a power of 2 the modulo is exact, but rejection sampling is the safe default and costs at most one redraw on average (and always terminates). The picker stores results in localStorage with a versioned key, so a session can survive a page reload and a user can review the draw history. The history is not encrypted or signed — it is local, non-sensitive, and easy to clear. For no-repeat mode the algorithm draws without replacement using a Fisher-Yates partial shuffle: at step k of N, swap element k with a uniformly chosen element in [k, N) and lock element k as drawn. This is O(N) time, O(1) extra space, and gives every permutation equal probability, which is the right combinatorial guarantee. (The naive 'draw N times, rejecting repeats' is also correct but O(N²) and can stall on long sessions.) For weighted picks (each option has its own probability), the standard algorithm is inverse-CDF sampling with a prefix-sum array: build a prefix sum of weights, draw a uniform real in [0, total), and binary-search for the smallest i such that prefix[i] >= u. That is O(log N) per draw, and the prefix sum is built once per change. Alias method (Walker-Vose) gives O(1) per draw at the cost of O(N) setup, which is worthwhile only when N is large and the distribution is fixed.
- Source of randomness: crypto.getRandomValues(typedArray) — the only cryptographically secure RNG in browsers, backed by OS-level CSPRNG (AES-256 CTR-DRBG on Windows 10+, ChaCha20 on Linux/macOS/iOS/Android).
- Math.random() is xorshift128+ on V8 (and variants on other engines): fast but predictable. Never use it for fair selection, tokens, OTPs, or audit samples — only for visual noise, animations, or non-security sampling.
- Unbiased index mapping: rejection sampling, not modulo. Compute limit = 2³² - (2³² mod N); if the random uint32 >= limit, redraw; else return r % N. Avoids the classic 'modulo bias' where short-range indices appear more often.
- No-repeat draws use Fisher-Yates partial shuffle in O(N) time, O(1) space: at step k swap element k with a uniform element in [k, N), then lock k. Every permutation is equally likely.
- Weighted picks use inverse-CDF sampling: build a prefix sum of weights once, draw a uniform real in [0, total), binary-search for the smallest prefix[i] >= u. O(log N) per draw.
- Draw history is persisted in localStorage with a versioned key, so a session survives a page reload. The history is local-only and not security-sensitive — clear it from the UI when finished.
- Fisher-Yates vs 'draw N times with rejection': both are correct in distribution, but Fisher-Yates is O(N) total and O(1) memory, while naive rejection is O(N²) in the worst case (lots of repeats near the end of a long list).
- Output range and types: getRandomValues accepts Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, Uint32Array, BigInt64Array, BigUint64Array — and the page always uses Uint32Array to feed the index-mapping step.
Examples
No-repeat draw from a candidate list
Input list (one per line):
Alice
Bob
Charlie
David
Eve
Frank
Allow duplicates: OFF Picks: 3
Result:
#1: Charlie
#2: Alice
#3: Frank
(Bob, David, Eve remain in the pool)
The page calls crypto.getRandomValues() on a Uint32Array to generate
a uniform integer in [0, n) for each draw, where n is the number of
remaining candidates. Each name has the same 1/n probability on every
pick, and the chosen index is fixed before the animation starts.Repeat-allowed draw with timestamped history
Input list (one per line):
Head
Tails
Allow duplicates: ON Picks: 5
Result:
#1 (14:23:01): Head
#2 (14:23:01): Tails
#3 (14:23:01): Head
#4 (14:23:01): Head
#5 (14:23:01): Tails
In repeat mode the same entry can be picked on consecutive draws, and
the pool never shrinks. The draw timestamp is added to each record so
the same candidate list can be reused across rounds while the history
shows exactly when each pick happened. Clear records separately from
the candidate list - they are stored under different localStorage keys.JavaScript snippet for the underlying selection
// Pick one index from [0, n) using Web Crypto (CSPRNG)
function pickIndex(n) {
// crypto.getRandomValues gives a uniform 32-bit value; modulo n
// is safe here because n is at most a few thousand for a list draw,
// and the modulo bias is negligible (2^32 / n is large).
const buf = new Uint32Array(1);
crypto.getRandomValues(buf);
return buf[0] % n;
}
// pickIndex(6) -> e.g. 4 (Charlie in the example above)
// pickIndex(2) -> 0 or 1 (Head or Tails)
//
// Note: for huge pools where n approaches 2^32, use rejection sampling
// to remove the modulo bias, e.g.:
// const limit = Math.floor(0xFFFFFFFF / n) * n;
// let r; do { crypto.getRandomValues(buf); r = buf[0]; } while (r >= limit);Fairness check across 1,000 draws
List: ['A', 'B', 'C', 'D'] (4 entries, expected share 25.0%)
Draws: 1,000 Allow duplicates: ON
Observed:
A: 247 (24.7%)
B: 256 (25.6%)
C: 248 (24.8%)
D: 249 (24.9%)
A 1,000-draw run with crypto.getRandomValues should land within about
+/- 3 percentage points of the expected share on every entry; larger
deviations (e.g. one entry at 35%) usually mean the implementation is
calling Math.random() or applying the modulo wrong. For a regulated
raffle, save the source list, the random seed source (browser/OS
entropy), the draw timestamp, and a witness signature - localStorage
is not a durable system of record.FAQ
Is the pick actually random?
Yes. Selection uses crypto.getRandomValues from the Web Crypto API, which is cryptographically strong. Each option has equal probability unless you configure weights.
Can the same option be picked twice in a row?
Yes - that's how independent random selection works. With 5 options, the probability of two same picks in a row is 1/5 = 20%. If you don't want repeats, enable 'remove after selection' which draws without replacement until the list is empty.
How is 'pick N items' handled?
By default it samples without replacement - each item can be selected at most once per N-item draw. Toggle 'with replacement' if duplicates are acceptable (e.g. picking N tasks for one person). N cannot exceed the option list size in without-replacement mode.
Can I add weights to bias the picks?
Some builds support per-option weights (e.g. option A weight 3, option B weight 1 - A is 3x more likely). The page normalizes weights to probabilities. Without weights, every option has equal probability.
Why is this fairer than picking 'gut feel'?
Humans are bad at random - we tend to avoid recent picks, over-pick salient options, and unconsciously bias toward names we recognise. A computer pick removes that, which makes raffle-like decisions feel cleaner to participants.
Is my list saved?
Some builds save to localStorage so the list persists in the same browser. Closing the tab or switching browsers loses it unless you exported. Nothing is uploaded.
Should I use it for legal lotteries?
No. Legal raffles, lotteries, and gambling drawings require auditable random procedures, often physical or certified RNG hardware. A general web tool isn't documented or audited - use it for office raffles and informal draws only.