NFT Watcher Bot is a Node.js + Discord bot that tracks Ethereum NFT activity (ERC721 and ERC1155) in real time.
It receives Alchemy Custom Webhook payloads, classifies events heuristically, and sends structured Discord embed notifications.
- Heuristic Event Classification: Detects and classifies events into
MINT,BUY,SELL, andSWEEP. - Anti-Spam Sweep Deduplication: Multiple NFTs swept in the same transaction context are summarized into a single embed.
- In-Discord Wallet Labeling: Manage labels directly from Discord with
/wallet-label add,/wallet-label remove, and/wallet-label list. - Admin-Only Wallet Label Commands: Slash commands require the
ManageGuildpermission. - Global Event Filters: Control which event types are sent via
TX_EVENT_FILTERSin.env.
Alchemy Custom Webhook -> Express endpoint (/webhook/nft) -> Normalization + Classification + Filtering -> Discord Embed Notification
Wallet labels are stored locally at:
path.join(__dirname, 'data', 'wallet-labels.json')The data/ directory is auto-created at runtime if it does not exist.
- Node.js LTS (
>=18recommended) - A Discord application and bot token
- Bot added to your target Discord server
- An Alchemy app with Custom Webhooks configured
- Linux VPS (optional, for PM2 deployment)
git clone https://github.com/your-org/nft-watcher.git
cd nft-watcher
npm install
cp .env.example .envEdit .env with your values, then run:
node index.jsWhen the bot is online and DISCORD_CLIENT_ID + GUILD_ID are valid, slash commands are registered automatically for the target guild.
| Variable | Required | Description | Example |
|---|---|---|---|
DISCORD_TOKEN |
Yes | Discord bot token | MTAx... |
CHANNEL_ID |
Yes | Target Discord channel ID for embeds | 123456789012345678 |
DISCORD_CLIENT_ID |
Yes | Discord application client ID (for slash command registration) | 123456789012345678 |
GUILD_ID |
Yes | Discord server ID where slash commands are registered | 123456789012345678 |
TX_EVENT_FILTERS |
No | Comma-separated event types to send | mint,sweep,buy,sell |
PORT |
No | HTTP server port for webhook receiver | 3000 |
Notes:
TX_EVENT_FILTERSvalid values:mint,sweep,buy,sell.- Invalid or empty filter values fall back to default:
mint,sweep,buy,sell. - Restart the process after changing environment variables.
- Add or update wallet label:
/wallet-label add address:0xYourWalletAddress owner:Whale A
- Remove wallet label:
/wallet-label remove address:0xYourWalletAddress
- List wallet labels:
/wallet-label list
- Method:
POST - Path:
/webhook/nft - Source: Alchemy Custom Webhooks
Behavior summary:
- Non-NFT activities are ignored.
- Unknown or non-matching events are skipped.
- Events not included in
TX_EVENT_FILTERSare not sent.
Install PM2 globally:
npm i -g pm2Start the bot:
pm2 start index.js --name nft-watcher-botPersist process list:
pm2 saveEnable startup on reboot:
pm2 startupRun the command generated by PM2, then save again:
pm2 saveCommon PM2 operations:
pm2 status
pm2 logs nft-watcher-bot
pm2 restart nft-watcher-bot
pm2 stop nft-watcher-bot
pm2 delete nft-watcher-botOptional log rotation:
pm2 install pm2-logrotate- Slash commands not appearing
- Verify
DISCORD_CLIENT_IDandGUILD_ID. - Confirm bot is online and invited to the correct guild.
- Check logs for command registration errors.
- Verify
- Invalid channel ID / no notifications
- Verify
CHANNEL_IDpoints to a channel accessible by the bot. - Ensure the bot has permission to send messages and embeds.
- Verify
- Webhook requests received but no output
- Confirm payload uses Alchemy
event.activity. - Check whether events are filtered out by
TX_EVENT_FILTERS.
- Confirm payload uses Alchemy
- Never commit
.envor any credentials. - Keep Discord tokens and webhook-related secrets private.
- Rotate tokens immediately if they are exposed.
Contributions are welcome.
Open an issue for bugs or feature proposals, then submit a focused pull request with clear context and reproduction steps when relevant.
This project is licensed under the ISC License. See package.json for the current license metadata.