npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

discord-giveaways-private

v1.1.7

Published

A complete framework to facilitate the creation of giveaways using discord.js

Readme

Discord Giveaways Private

versionBadge downloadsBadge GitLab

Discord Giveaways Private is a powerful Node.js module that allows you to easily create giveaways with enhanced features!

Features

  • 🌐 Web Dashboard Integration: Manage giveaways through M4t3 web application
  • ⏱️ Easy to use and production-ready!
  • 🔒 Secure: No eval() usage, safe template processing
  • 🔄 Automatic restart after bot crash!
  • 🇫🇷 Support for translations: adapt the strings for your own language!
  • 📁 Support for all databases! (default is json)
  • ⚙️ Very customizable! (prize, duration, winners, ignored permissions, bonus entries, etc...)
  • 🚀 Super powerful: start, edit, reroll, end, delete and pause giveaways!
  • 💥 Events: giveawayEnded, giveawayRerolled, giveawayDeleted, giveawayReactionAdded, giveawayReactionRemoved, endedGiveawayReactionAdded
  • 🕸️ Support for shards!
  • 👤 Dynamic user fetching for hostedBy - always shows current username even after bot restarts!
  • ✅ Full unit test coverage with Vitest (25 tests)
  • 🔄 Automated releases with semantic-release
  • 📦 Optimized package size with .npmignore
  • and much more!

Installation

npm install --save discord-giveaways-private

Usage with M4t3 Bot

This package is designed to work with the M4t3 Discord bot and its web dashboard.

Giveaways are created and managed through the M4t3 web application, not through Discord commands. The bot handles the giveaway execution, reactions, and winner selection automatically.

Integration Setup

Required Discord Intents: Guilds and GuildMessageReactions.
Optional Discord Privileged Intent for better performance: GuildMembers.

const Discord = require('discord.js');
const client = new Discord.Client({
    intents: [
        Discord.IntentsBitField.Flags.Guilds,
        Discord.IntentsBitField.Flags.GuildMessageReactions,
        Discord.IntentsBitField.Flags.GuildMembers // Optional, for better performance
    ]
});

// Requires Manager from discord-giveaways-private
const { GiveawaysManager } = require('discord-giveaways-private');
const manager = new GiveawaysManager(client, {
    storage: './giveaways.json',
    default: {
        botsCanWin: false,
        embedColor: '#FF0000',
        embedColorEnd: '#000000',
        reaction: '🎉'
    }
});
// We now have a giveawaysManager property to access the manager everywhere!
client.giveawaysManager = manager;

client.on('ready', () => {
    console.log('Bot is ready!');
});

client.login(process.env.DISCORD_BOT_TOKEN);

After initialization, the manager will automatically:

  • Resume any active giveaways after bot restarts
  • Handle reaction events and participant tracking
  • Execute winner selection when giveaways end
  • Update giveaway embeds with current information

Manager Configuration Options

  • client: The Discord client instance (required)
  • storage: Path to store giveaway data (default: './giveaways.json')
  • forceUpdateEvery: Interval in ms to force embed updates (optional)
  • default.botsCanWin: Whether bots can win giveaways (default: false)
  • default.embedColor: Color for active giveaway embeds
  • default.embedColorEnd: Color for ended giveaway embeds
  • default.reaction: Emoji for giveaway participation (default: 🎉)
  • default.exemptPermissions: Permissions that prevent winning
  • default.lastChance: Last chance notification settings

Managing Giveaways

Via Web Dashboard

Giveaways are created and managed through the M4t3 web application:

  1. Create Giveaway: Set prize, duration, winner count, and requirements
  2. Edit Giveaway: Modify active giveaways (prize, duration, winners)
  3. End Giveaway: Manually end a giveaway early
  4. Reroll Winners: Select new winners if needed
  5. Delete Giveaway: Remove a giveaway completely

The bot automatically handles all giveaway execution based on the webapp configuration.

Programmatic Usage (Advanced)

While the webapp is the primary interface, you can also interact with giveaways programmatically:

// Start a giveaway programmatically
await client.giveawaysManager.start(channel, {
    duration: 86400000, // 24 hours in ms
    winnerCount: 1,
    prize: 'Discord Nitro',
    hostedBy: interaction.user,
    extraData: {
        description: 'React with 🎉 to enter!',
        winCoins: false
    }
});

// End a giveaway
await client.giveawaysManager.end(messageId);

// Reroll winners
await client.giveawaysManager.reroll(messageId, {
    winnerCount: 1
});

Start Options

When starting a giveaway programmatically:

  • duration: Giveaway duration in milliseconds
  • prize: The prize description
  • winnerCount: Number of winners to select
  • hostedBy: User object of the host
  • extraData: Additional data (description, winCoins, etc.)
  • embedColor: Custom embed color
  • reaction: Custom reaction emoji
  • exemptPermissions: Permissions that prevent winning
  • exemptMembers: Function to filter eligible members
  • bonusEntries: Array of bonus entry configurations
  • lastChance: Last chance notification settings

Events

The manager emits various events you can listen to:

// When a giveaway ends
client.giveawaysManager.on('giveawayEnded', (giveaway, winners) => {
    console.log(`Giveaway ended: ${giveaway.prize}`);
    console.log(`Winners: ${winners.map(w => w.user.tag).join(', ')}`);
});

// When a giveaway is rerolled
client.giveawaysManager.on('giveawayRerolled', (giveaway, winners) => {
    console.log(`Giveaway rerolled: ${giveaway.prize}`);
});

// When someone reacts to a giveaway
client.giveawaysManager.on('giveawayReactionAdded', (giveaway, member, reaction) => {
    console.log(`${member.user.tag} entered giveaway: ${giveaway.prize}`);
});

Advanced Features

Fetch Giveaways

// A list of all the giveaways
const allGiveaways = client.giveawaysManager.giveaways; // [ {Giveaway}, {Giveaway} ]

// A list of all the giveaways on the server with Id "1909282092"
const onServer = client.giveawaysManager.giveaways.filter((g) => g.guildId === '1909282092');

// A list of the current active giveaways (not ended)
const notEnded = client.giveawaysManager.giveaways.filter((g) => !g.ended);

Exempt Members

Filter members who cannot win. If the function returns true, the member is excluded from winning.

client.giveawaysManager.start(channel, {
    duration: 86400000,
    winnerCount: 1,
    prize: 'Free Steam Key',
    // Only members who have the "Nitro Boost" role are able to win
    exemptMembers: (member, giveaway) => !member.roles.cache.some((r) => r.name === 'Nitro Boost')
});

Security Note: For security reasons, only function references are supported. Serialized functions are no longer allowed.

Last Chance

client.giveawaysManager.start(interaction.channel, {
    duration: 60000,
    winnerCount: 1,
    prize: 'Discord Nitro!',
    lastChance: {
        enabled: true,
        content: '⚠️ **LAST CHANCE TO ENTER !** ⚠️',
        threshold: 10_000,
        embedColor: '#FF0000'
    }
});
  • lastChance.enabled: if the last chance system is enabled.
  • lastChance.content: the text of the embed when the last chance system is enabled.
    ^^^ You can access giveaway properties.
  • lastChance.threshold: the number of milliseconds before the giveaway ends when the last chance system will be enabled.
  • lastChance.embedColor: the color of the embed when last chance is enabled.

Pause Options

client.giveawaysManager.start(interaction.channel, {
    duration: 60000,
    winnerCount: 1,
    prize: 'Discord Nitro!',
    pauseOptions: {
        isPaused: true,
        content: '⚠️ **THIS GIVEAWAY IS PAUSED !** ⚠️',
        unpauseAfter: null,
        embedColor: '#FFFF00',
        infiniteDurationText: '`NEVER`'
    }
});
  • pauseOptions.isPaused: if the giveaway is paused.
  • pauseOptions.content: the text of the embed when the giveaway is paused.
    ^^^ You can access giveaway properties.
  • pauseOptions.unpauseAfter: the number of milliseconds, or a timestamp in milliseconds, after which the giveaway will automatically unpause.
  • pauseOptions.embedColor: the color of the embed when the giveaway is paused.
  • pauseOptions.infiniteDurationText: The text that gets displayed next to GiveawayMessages#drawing in the paused embed, when there is no unpauseAfter.
    ^^^ You can access giveaway properties.

Bonus Entries

Give members extra entries based on roles or other criteria:

client.giveawaysManager.start(channel, {
    duration: 86400000,
    winnerCount: 1,
    prize: 'Free Steam Key',
    bonusEntries: [
        {
            // Members who have the "Nitro Boost" role get 2 bonus entries
            bonus: (member, giveaway) => (member.roles.cache.some((r) => r.name === 'Nitro Boost') ? 2 : null),
            cumulative: false
        }
    ]
});
  • bonus: Function that returns the number of additional entries (or null for none)
  • cumulative: If true, bonus entries from multiple sources can be combined

Message Options

Options are available for the following messages:
GiveawayStartOptions#GiveawayMessages#winMessage, GiveawayRerollOptions#messages#congrat, GiveawayRerollOptions#messages#error and client.giveawaysManager.end(messageId, noWinnerMessage).

You can access giveaway properties in all embed or component properties that are a string.

The format, including all currently available options, looks like this:

message: {
    content: '',
    embed: new Discord.EmbedBuilder(),
    components: [new Discord.ActionRowBuilder()],
    replyToGiveaway: true
}

Note: When sending a component, content or embed is required.

Access giveaway properties in messages

You can access any giveaway property inside of giveaway messages with the format: {this.<property>}.
For example:

winMessage: 'Congratulations, {winners}! You won **{this.prize}**!\n{this.messageURL}'

Also, you can write JavaScript code inside of {}.
For example:

winMessage: 'Congratulations, {winners}! You won **{this.prize.toUpperCase()}**!\n{this.messageURL}'

If you want to fill in strings that are not messages of a giveaway, or just custom embeds, then you can use giveaway.fillInString(string) for strings, giveaway.fillInEmbed(embed) for embeds and giveaway.fillInComponents(embed) for components.

🇫🇷 Translation

You can also pass a messages parameter for the start() function, if you want to translate the giveaway texts:

  • options.messages.giveaway: the message that will be displayed above the embeds.
  • options.messages.giveawayEnded: the message that will be displayed above the embeds when the giveaway is ended.
  • options.messages.title: the title of the giveaway embed. Will default to the prize of the giveaway if the value is not a string.
  • options.messages.drawing: the message that displays the drawing timestamp.
  • options.messages.dropMessage: the message that will be displayed for drop giveaways.
  • options.messages.inviteToParticipate: the message that invites users to participate.
  • options.messages.winMessage: the message that will be displayed to congratulate the winner(s) when the giveaway is ended.
    ^^^ Message options are available in this message.
  • options.messages.embedFooter: the message displayed at the bottom of the main (not ended) embed.
    ^^^ An empty string can be used for "deactivation", or iconURL can be set.
  • options.messages.noWinner: the message that is displayed if no winner can be drawn.
  • options.messages.hostedBy: the message to display the host of the giveaway.
  • options.messages.winners: simply the expression "Winner(s):" in your language.
  • options.messages.endedAt: simply the words "Ended at" in your language.

For example:

const duration = interaction.options.getString('duration');
const winnerCount = interaction.options.getInteger('winners');
const prize = interaction.options.getString('prize');

client.giveawaysManager.start(interaction.channel, {
    duration: ms(duration),
    winnerCount,
    prize,
    messages: {
        giveaway: '🎉🎉 **GIVEAWAY** 🎉🎉',
        giveawayEnded: '🎉🎉 **GIVEAWAY ENDED** 🎉🎉',
        title: '{this.prize}',
        drawing: 'Drawing: {timestamp}',
        dropMessage: 'Be the first to react with 🎉 !',
        inviteToParticipate: 'React with 🎉 to participate!',
        winMessage: 'Congratulations, {winners}! You won **{this.prize}**!\n{this.messageURL}',
        embedFooter: '{this.winnerCount} winner(s)',
        noWinner: 'Giveaway cancelled, no valid participations.',
        hostedBy: 'Hosted by: {this.hostedBy}',
        winners: 'Winner(s):',
        endedAt: 'Ended at'
    }
});

You can access giveaway properties in all these messages.

And for the reroll() function:

client.giveawaysManager.reroll(messageId, {
    messages: {
        congrat: ':tada: New winner(s): {winners}! Congratulations, you won **{this.prize}**!\n{this.messageURL}',
        error: 'No valid participations, no new winner(s) can be chosen!'
    }
});
  • options.messages.congrat: the congratulatory message.
  • options.messages.error: the error message if there is no valid participant.

You can access giveaway properties in these messages.
Message options are available in these messages.

Custom Database

You can use your custom database to save giveaways, instead of the json files (the "database" by default for discord-giveaways).
For this, you will need to extend the GiveawaysManager class, and replace some methods with your custom ones.
There are 4 methods you will need to replace:

  • getAllGiveaways: this method returns an array of stored giveaways.
  • saveGiveaway: this method stores a new giveaway in the database.
  • editGiveaway: this method edits a giveaway already stored in the database.
  • deleteGiveaway: this method deletes a giveaway from the database (permanently).

⚠️ All the methods should be asynchronous to return a promise!

SQL examples

NoSQL examples