Guides
Giveaways
Start a giveaway with a Join button, then pick a random winner with one command.
You will build a giveaway system:
| Part | Job |
|---|---|
/giveaway | Posts the giveaway with a Join button |
Giveaway join event | Saves each member who clicks Join |
/gend | Picks a random winner and announces it |
Works on every plan. One giveaway runs at a time.
What you need#
- About 10 minutes.
- A channel for giveaways.
Entries are saved in a Mongo database called giveaway, one row per member. A member who clicks twice still has one entry. See Saving data.
1. /giveaway#
Open Create → Slash Command.
| Field | Value |
|---|---|
| Command Name | giveaway |
| Description | Start a giveaway |
Add a Text argument named prize, Required on.
Open the permissions part of the form. In Discord permissions, pick Manage Server. Under Behavior, turn on Only the user sees the reply.
Pre-hook:
# Start fresh: remove entries from the last giveaway.
entries = SlashMongo("giveaway")
await entries.delete_many({})
update_server_var("giveaway_prize", prize)
join = ComponentBuilder()
join.add_button("Join", style="success", emoji="🎉", custom_id="giveaway_join")
send_message(
channel,
message=Message(
title=f"🎉 Giveaway: {prize}",
description="Press **Join** to enter. Good luck!",
color="#E91E63",
),
components=join,
)
set_content("Giveaway started. Run /gend to pick the winner.")update_server_var saves the prize name, so /gend can show it later.
2. The Join button#
Open Create → Event.
| Field | Value |
|---|---|
| Name | Giveaway join |
| Type | Button Click / Select Menu Change |
| Custom ids | giveaway_join |
Code:
defer_response(ephemeral=True)
entries = SlashMongo("giveaway")
await entries.update_one(
{"_id": str(user.id)},
{"$setOnInsert": {"joined": int(unix_timestamp)}},
upsert=True,
)
total = await entries.count()
respond_interaction(interaction, f"You are in! {total} entries so far.")- The member's ID is the row's
_id, so a second click finds the same row. No double entries. $setOnInsertonly writes when the row is new.count()counts every entry.
3. /gend#
Make another slash command named gend, description Pick the giveaway winner. Give it Manage Server too, and turn on Only the user sees the reply.
Pre-hook:
entries = SlashMongo("giveaway")
picked = await entries.aggregate([{"$sample": {"size": 1}}])
if not picked:
set_error("Nobody has joined yet.")
winner = picked[0]["_id"]
prize = server_var("giveaway_prize", "the prize")
send_message(channel, f"🎉 Congratulations <@{winner}>! You won **{prize}**!")
await entries.delete_many({})
set_content("Winner picked.")$sample picks one random row. The database does the picking, so it stays fast with thousands of entries.
4. Test it#
- Run
/giveawaywith prizeNitro. - Press Join. It says "You are in! 1 entries so far."
- Press Join again. Still 1 entry.
- Run
/gend. You win.
Errors from your code show in Logs → Error Logs on the dashboard.
Ideas#
- Reroll. Remove the
delete_manyline from/gend. Entries then stay until the next/giveaway, so running/gendagain picks a new winner. - Only members with a role can join. In the event, check
has_role(user, "Member")before saving. When it isFalse, answer withrespond_interactionand skip the save. - End on its own.
schedulecan run a built-in action later, but it cannot run your own code. A Clock event withschedule_clockcan. See Scheduling. - Show the count on the message. Edit the giveaway message with
edit_messageafter each join. See Messages.