Algorithm Transparency

Every winner is chosen
100% fairly

Our open-source algorithm ensures complete fairness. More entries = better odds, but every participant has a real chance to win. Zero manipulation, zero bias, zero exceptions.

Our Transparency Promise

We believe trust is earned through transparency. Every aspect of our winner selection is open for inspection. No black boxes, no hidden algorithms, no secret parameters. What you see is exactly what happens.

The Algorithm Behind the Magic

Every winner is drawn by this code, straight from our codebase. Cryptographically secure randomness, no hidden functions, no secret parameters.

WinnerSelection.ts
1// src/lib/services/WinnerSelection.ts
2import { randomInt } from 'crypto';
3import { GiveawayEntry } from '@/components/dashboard/giveaways/types';
4
5/**
6 * Select winners using weighted random selection
7 * @param entries Array of giveaway entries with user IDs and entry counts
8 * @param winnerCount Number of winners to select
9 * @param hasFraudDetection Whether the server has fraud detection enabled (premium+)
10 * @param cooldownExcludedUserIds Optional array of user IDs to exclude due to winner cooldown
11 * @param geoExcludedUserIds Optional array of user IDs to exclude due to geo restriction
12 * (warn-mode entrants and block-mode strays that slipped past the submit gate)
13 * @param referralExcludedUserIds Optional array of user IDs to exclude because they are
14 * below the giveaway's Invite-to-Win referral requirement (premium feature)
15 * @returns Array of selected winner user IDs
16 */
17export function selectWinners(
18 entries: GiveawayEntry[],
19 winnerCount: number,
20 hasFraudDetection: boolean = true, // Default to true for backward compatibility
21 cooldownExcludedUserIds: string[] = [], // Users excluded due to recent wins (cooldown)
22 geoExcludedUserIds: string[] = [], // Users excluded due to geo restriction
23 referralExcludedUserIds: string[] = [] // Users below the Invite-to-Win referral requirement
24): string[] {
25 if (!entries || entries.length === 0) {
26 return [];
27 }
28
29 // Create a Set for O(1) lookup of cooldown excluded users
30 const cooldownExcludedSet = new Set(cooldownExcludedUserIds);
31
32 // Filter out:
33 // 1. Red-flagged entries ONLY if server has fraud detection enabled (premium+)
34 // 2. Users on winner cooldown (won from this server recently)
35 // 3. Users whose entry country falls under the giveaway's geo restriction
36 // 4. Users below the giveaway's Invite-to-Win referral requirement
37 let eligibleEntries = hasFraudDetection
38 ? entries.filter(entry => entry.fraud_flag !== 'red')
39 : entries; // Free servers: include all entries (ignore fraud flags)
40
41 // Apply cooldown exclusions (silent exclusion - users can still enter but won't win)
42 if (cooldownExcludedSet.size > 0) {
43 const beforeCount = eligibleEntries.length;
44 eligibleEntries = eligibleEntries.filter(entry => !cooldownExcludedSet.has(entry.user_id));
45 const excluded = beforeCount - eligibleEntries.length;
46 if (excluded > 0) {
47 console.log(`[Winner Selection] Excluded ${excluded} entries due to winner cooldown`);
48 }
49 }
50
51 // Apply geo exclusions (warn mode: entered with disclosure, can't win)
52 const geoExcludedSet = new Set(geoExcludedUserIds);
53 if (geoExcludedSet.size > 0) {
54 const beforeCount = eligibleEntries.length;
55 eligibleEntries = eligibleEntries.filter(entry => !geoExcludedSet.has(entry.user_id));
56 const excluded = beforeCount - eligibleEntries.length;
57 if (excluded > 0) {
58 console.log(`[Winner Selection] Excluded ${excluded} entries due to geo restriction`);
59 }
60 }
61
62 // Apply Invite-to-Win exclusions (entrants below the referral requirement;
63 // participants were told up-front they must invite X friends to be eligible)
64 const referralExcludedSet = new Set(referralExcludedUserIds);
65 if (referralExcludedSet.size > 0) {
66 const beforeCount = eligibleEntries.length;
67 eligibleEntries = eligibleEntries.filter(entry => !referralExcludedSet.has(entry.user_id));
68 const excluded = beforeCount - eligibleEntries.length;
69 if (excluded > 0) {
70 console.log(`[Winner Selection] Excluded ${excluded} entries below the Invite-to-Win referral requirement`);
71 }
72 }
73
74 // If no eligible entries remain (after fraud + cooldown + geo + referral filtering), return empty array
75 if (eligibleEntries.length === 0) {
76 console.warn('[Winner Selection] No eligible entries after filtering (fraud flags + cooldown + geo + referral-requirement exclusions)');
77 return [];
78 }
79
80 // Create weighted pool of entries based on entry count
81 const entryPool: string[] = [];
82
83 for (const entry of eligibleEntries) {
84 // Add user_id to the pool based on their entry count
85 for (let i = 0; i < entry.entries_count; i++) {
86 entryPool.push(entry.user_id);
87 }
88 }
89
90 // Randomly select winners without duplicates
91 const winners: string[] = [];
92 const winnerSet = new Set<string>();
93
94 // Limit winner count to available unique participants (only eligible entries)
95 const uniqueParticipants = new Set(eligibleEntries.map(entry => entry.user_id));
96 const availableWinnerCount = Math.min(winnerCount, uniqueParticipants.size);
97
98 // If there are no entries or the pool is empty, return empty array
99 if (availableWinnerCount === 0 || entryPool.length === 0) {
100 return [];
101 }
102
103 // Select winners
104 while (winners.length < availableWinnerCount && entryPool.length > 0) {
105 // Select a random entry from the pool
106 const randomIndex = randomInt(entryPool.length);
107 const selectedUserId = entryPool[randomIndex];
108
109 // If this user hasn't already been selected as a winner, add them
110 if (!winnerSet.has(selectedUserId)) {
111 winners.push(selectedUserId);
112 winnerSet.add(selectedUserId);
113 }
114
115 // Remove via swap-and-pop (O(1)) instead of splice (O(n)).
116 // Selection is uniform random so order of remaining elements doesn't matter.
117 entryPool[randomIndex] = entryPool[entryPool.length - 1];
118 entryPool.pop();
119 }
120
121 return winners;
122}

Key Algorithm Steps

Click on any step below to see its implementation in the code

Line 2

Secure Randomness

Winners are drawn with Node's crypto.randomInt, a cryptographically secure generator. There's no seed to predict and nothing to manipulate, not even by us.

Line 38

Fraud & Cooldown Filtering

Before the draw, fraud-flagged entries are removed on fraud-detection servers, and anyone on winner cooldown is set aside. Free servers keep every entry.

Line 86

Weighted Pool Creation

Fairness starts here. Each user is added to the pool once per entry they earned, so 5 entries means 5 chances. Proportional, never guaranteed.

Line 106

The Draw

A random index into the weighted pool picks each winner. More entries simply means more slots, and every slot has exactly equal odds.

Line 110

Duplicate Prevention

A winner set guarantees nobody wins twice, and we never draw more winners than there are unique eligible participants.

How Fairness Works

See exactly how our algorithm ensures every participant gets a fair chance, with better odds for those who engage more.

1

Entry Collection

Users complete tasks and earn entries based on their actions

2

Weighted Pool Creation

Every entry gets added to the selection pool based on tasks completed

3

Random Selection

Cryptographically secure randomness selects from the weighted pool

4

Duplicate Prevention

Ensures each user can only win once per giveaway

5

Winner Confirmation

Selected winners are verified and announced

Real Example

Alice completes 3 tasks, Bob completes 1 task, Charlie completes 5 tasks. The pool contains 9 total entries with proportional winning chances.

Alice

3 entries earned

33% chance

Bob

1 entry earned

11% chance

Charlie

5 entries earned

56% chance

The Pool (9 total entries)

Each dot represents one entry. Winner is selected randomly from all entries.

No More Rigged Giveaways

A Discord giveaway bot that shows exactly how winners are chosen

The Problem

Most Discord giveaway bots are black boxes. Even when the bot is legitimate and truly random, your community has no way to verify this. They can't see the algorithm, can't check the process, can't prove winners weren't hand-picked.

Without transparency, every giveaway feels suspicious. Your members start wondering if it's actually fair. Trust dies, engagement drops.

We got tired of watching communities die from broken trust

The Solution

Never worry about engagement drops from rigged giveaway accusations again. When members question fairness, just link them to this page.

ScopliDrop's giveaway bot certifies that server owners cannot edit giveaways or choose winners. Period.

We have a 'manually end giveaway' feature, but this only triggers our winning selection algorithm, nothing else. Server admins CANNOT choose winners by any means. This is our promise.

Fairness Questions

Learn how we ensure every giveaway is transparent, secure, and genuinely fair for all participants.

Join the Fair Revolution

Ready to Run Truly Fair
Giveaways Today?

Join thousands of Discord communities who've switched to transparent, verifiable giveaways. Start free, prove fairness from day one.