A TypeScript bot that automatically shares new OpenSea NFT collection events to Discord and Twitter. Perfect for NFT communities wanting to stay updated on collection activity.
- π Real-time monitoring of OpenSea events (sales, listings, offers, transfers, mints, burns)
- π― Multi-platform support for Discord and Twitter
- βοΈ Flexible configuration with multiple channel/event type combinations
- π Rich embeds with NFT images and metadata
- π‘οΈ Type-safe TypeScript implementation
- Features
- Prerequisites
- Installation
- Configuration
- Environment Variables
- Usage
- Development
- Testing
- Deployment
- Troubleshooting
- Contributing
- Node.js 18+
- Yarn package manager
- OpenSea API key (get one here)
- Discord bot token (for Discord integration)
- Twitter API credentials (for Twitter integration)
# Clone the repository
git clone https://github.com/ryanio/opensea-activity-bot.git
cd opensea-activity-bot
# Install dependencies
yarn install
# Build the project
yarn buildCreate a .env file in the root directory with your configuration:
# Required
TOKEN_ADDRESS=0x...
OPENSEA_API_TOKEN=your_opensea_api_key
# Discord (optional)
DISCORD_TOKEN=your_discord_bot_token
DISCORD_EVENTS=channel_id=event_types
# Twitter (optional)
TWITTER_CONSUMER_KEY=your_consumer_key
TWITTER_CONSUMER_SECRET=your_consumer_secret
TWITTER_ACCESS_TOKEN=your_access_token
TWITTER_ACCESS_TOKEN_SECRET=your_access_token_secret
TWITTER_EVENTS=sale,transfer
# Optional settings
CHAIN=ethereum
OPENSEA_BOT_INTERVAL=60
LOG_LEVEL=infoOriginally developed for @dutchtide's ππππππππ₯ ε€ε£ πΉπ£πππ«π collection.
π‘ Tip: To run multiple instances of this bot, check out bot-runner. Also see discord-nft-embed-bot for additional Discord functionality.
| Variable | Description | Example |
|---|---|---|
TOKEN_ADDRESS |
Contract address of the NFT collection | 0x1234...abcd |
OPENSEA_API_TOKEN |
Your OpenSea API key | Get from OpenSea Account |
| Variable | Description | Example |
|---|---|---|
DISCORD_TOKEN |
Discord bot token | Get from Discord Developer Portal |
DISCORD_EVENTS |
Channel and event type mapping | 662377002338091020=listing,sale |
Discord Setup:
- Create a Discord application
- Create a bot with permissions:
Send MessagesandEmbed Links - Add bot to your server
- Copy the bot token to
DISCORD_TOKEN
DISCORD_EVENTS Format:
- Single channel:
CHANNEL_ID=event1,event2 - Multiple channels:
CHANNEL_ID1=event1&CHANNEL_ID2=event2,event3
| Variable | Description | Example |
|---|---|---|
TWITTER_CONSUMER_KEY |
Twitter API consumer key | Get from Twitter Developer Platform |
TWITTER_CONSUMER_SECRET |
Twitter API consumer secret | |
TWITTER_ACCESS_TOKEN |
Twitter API access token | |
TWITTER_ACCESS_TOKEN_SECRET |
Twitter API access token secret | |
TWITTER_EVENTS |
Event types to tweet | sale,transfer |
Twitter Setup:
- Create an application in the Twitter Developer Platform
- Enable write permissions
- Generate OAuth1 tokens
- The bot uses
twitter-api-v2with v2 API for tweets and v1.1 for media uploads
| Variable | Description | Default | Example |
|---|---|---|---|
CHAIN |
Blockchain network | ethereum |
ethereum, polygon, arbitrum |
OPENSEA_BOT_INTERVAL |
Polling interval (seconds) | 60 |
30 |
MIN_OFFER_ETH |
Minimum offer amount (ETH) | 0 |
0.1 |
TWITTER_PREPEND_TWEET |
Text to prepend to tweets | - | #NFT |
TWITTER_APPEND_TWEET |
Text to append to tweets | - | #OpenSea |
LOG_LEVEL |
Log verbosity | info |
debug, info, warn, error |
The bot automatically groups multiple events from the same transaction or actor for cleaner posts. These settings control the grouping behavior:
| Variable | Description | Default | Example |
|---|---|---|---|
TWITTER_EVENT_GROUP_MIN_GROUP_SIZE |
Min events to group together for Twitter | 2 |
5 |
TWITTER_EVENT_GROUP_SETTLE_MS |
Time to wait for more events (ms) for Twitter | 60000 |
300000 |
DISCORD_EVENT_GROUP_MIN_GROUP_SIZE |
Min events to group together for Discord | 2 |
5 |
DISCORD_EVENT_GROUP_SETTLE_MS |
Time to wait for more events (ms) for Discord | 60000 |
300000 |
Note: Event grouping helps consolidate multiple NFT purchases/mints/burns from the same transaction or actor into a single post. For example, if someone buys 10 NFTs in one transaction, it will be posted as "10 purchased by @user for 5 ETH" instead of 10 separate posts. The default 60-second settle time also allows OpenSea metadata to populate for mint events before posting.
| Event Type | Description |
|---|---|
listing |
New NFT listings |
offer |
New offers/bids |
sale |
NFT sales |
transfer |
NFT transfers |
mint |
New mints (auto-detected from transfers) |
burn |
NFT burns (auto-detected from transfers) |
Note:
mintandburnevents are automatically classified fromtransferevents based on the from/to addresses.
# Start the bot
yarn start
# Development mode (with hot reload)
yarn start:dev# Install dependencies
yarn install
# Run in development mode
yarn start:dev
# Build the project
yarn build
# Format code
yarn format
# Lint code
yarn lintsrc/
βββ index.ts # Main entry point
βββ opensea.ts # OpenSea API integration
βββ types.ts # TypeScript type definitions
βββ platforms/
β βββ discord.ts # Discord bot implementation
β βββ twitter.ts # Twitter integration
βββ utils/
βββ aggregator.ts # Event aggregation logic
βββ constants.ts # Application constants
βββ event-grouping.ts # Event grouping utilities
βββ event-types.ts # Event type definitions
βββ events.ts # Event processing
βββ links.ts # URL generation utilities
βββ logger.ts # Logging utilities
βββ lru-cache.ts # Caching implementation
βββ queue.ts # Event queue management
βββ utils.ts # General utilities
# Run all tests
yarn test
# Run tests with coverage
yarn test:coverage
# Run tests in CI mode
yarn test:ciThe project uses Jest for testing with comprehensive coverage of:
- OpenSea API integration
- Discord message formatting
- Twitter tweet generation
- Event deduplication
- Cache management
- Utility functions
I recommend DigitalOcean over Heroku for improved stability. Heroku servers can restart (cycle) which can lead to duplicate posts since the ephemeral disk is lost.
DigitalOcean Setup ($5/month Basic Droplet):
- Create Ubuntu droplet
- Install Node.js 22 and Yarn
- Clone repository and install dependencies
- Install PM2 for process management
- Configure environment variables
- Start with PM2
# Install PM2 globally
yarn global add pm2
# Start the bot
pm2 start yarn -- start
# Monitor the bot
pm2 list
pm2 logs
# Install log rotation
pm2 install pm2-logrotate
# Auto-start on reboot
pm2 startup
pm2 saveFROM node:22-alpine
WORKDIR /app
COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile
COPY . .
RUN yarn build
CMD ["yarn", "start"]Set your environment variables in your deployment platform:
- DigitalOcean: Add to
/etc/profileor use PM2 ecosystem file - Docker: Use
-eflags or.envfile - Heroku: Use
heroku config:setcommands
Bot not posting messages:
- Verify Discord bot has
Send MessagesandEmbed Linkspermissions - Check that bot is added to the specified channels
- Ensure
DISCORD_TOKENis correct
Twitter posts failing:
- Verify all Twitter API credentials are correct
- Check that Twitter app has write permissions
- Ensure OAuth1 tokens are properly generated
No events detected:
- Verify
TOKEN_ADDRESSis correct for your collection - Check
OPENSEA_API_TOKENis valid - Ensure collection has recent activity
Duplicate posts:
- Check that only one instance is running
- Verify cache is working (check logs for cache hits)
- Consider using
bot-runnerfor multiple instances
Enable debug logging to troubleshoot issues:
LOG_LEVEL=debug yarn startThe bot provides structured logging with different levels:
debug: Detailed information for debugginginfo: General information about bot activitywarn: Warning messages for potential issueserror: Error messages for failures
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Make your changes
- Run tests:
yarn test - Format code:
yarn format - Commit changes:
git commit -m 'Add amazing feature' - Push to branch:
git push origin feature/amazing-feature - Open a Pull Request
- Follow TypeScript best practices
- Write tests for new features
- Use
yarn formatbefore committing - Follow the existing code structure
- Add JSDoc comments for public APIs
When reporting issues, please include:
- Node.js version
- Environment variables (without sensitive values)
- Error logs
- Steps to reproduce
- Expected vs actual behavior
Support this project by using the DigitalOcean referral badge below:
