A Twitter bot that counts down from a very large number, posting tweets with the current count in word form. Inspired by Count Von Count from Sesame Street!
- Automatic countdown tweets with random phrases and tags
- Web interface showing current countdown state
- Badge endpoint for displaying countdown in README files
- Health check endpoint for monitoring
- Secure with rate limiting, helmet.js, and input validation
- Comprehensive error handling and retry logic
- Node.js 18+
- AWS Account with DynamoDB access
- Twitter Developer Account with API v2 access
- Clone the repository:
git clone https://github.com/brianfunk/voncountdown.git
cd voncountdown- Install dependencies:
npm install- Copy
.env.exampleto.env:
cp .env.example .env- Configure environment variables in
.env:
# AWS Configuration
AWS_ACCESS_KEY_ID=your_aws_access_key_id
AWS_SECRET_ACCESS_KEY=your_aws_secret_access_key
AWS_REGION=us-east-1
DYNAMODB_TABLE=voncountdown
# Application Configuration
PORT=8080
NODE_ENV=development
# Twitter API Configuration
TWITTER_API_KEY=your_twitter_api_key
TWITTER_API_SECRET=your_twitter_api_secret
TWITTER_ACCESS_TOKEN=your_twitter_access_token
TWITTER_ACCESS_TOKEN_SECRET=your_twitter_access_token_secret
-
Create DynamoDB table:
- Table name:
voncountdown(or setDYNAMODB_TABLEenv var) - Partition key:
number(Number) - No sort key required
- Table name:
-
Start the application:
npm startFor development with auto-reload:
npm run devHome page displaying the current countdown state.
Returns a badge image showing the current countdown number.
- Returns 503 if service is initializing
- Returns 500 on error
Health check endpoint returning JSON:
{
"status": "ok",
"current_number": 1111373357578,
"current_string": "One trillion one hundred eleven billion...",
"current_comma": "1,111,373,357,578",
"uptime": 1234.56,
"timestamp": "2026-01-13T15:30:00.000Z"
}# Run all tests
npm test
# Run tests in watch mode
npm run test:watch
# Run tests with coverage report
npm run test:coverageSee tests/README.md for testing guide.
The application uses simple console logging (stdout/stderr) for compatibility with AWS App Runner and CloudWatch Logs.
Log Levels:
[INFO]- General information and flow tracking[DEBUG]- Detailed debugging information[WARN]- Warnings and non-critical issues[ERROR]- Errors and exceptions
Log Format:
[INFO] [2026-01-13T16:30:00.000Z] Message {"key":"value"}
Features:
- Automatic sanitization of sensitive data (credentials, tokens, keys)
- Timestamped logs for easy debugging
- Structured JSON data for parsing
- Extensive logging throughout countdown flow, Twitter API calls, and DynamoDB operations
Viewing Logs:
- Local: Logs appear in console when running
npm startornpm run dev - AWS App Runner: View logs in CloudWatch Logs console
- Heroku: View logs with
heroku logs --tail
The application consists of:
- Express.js web server
- DynamoDB for persistent storage of countdown state
- Twitter API v2 for posting tweets
- Console logging (stdout/stderr) for CloudWatch compatibility
- Node-cache for in-memory caching
- Handlebars for server-side templating
- On startup, loads the lowest number from DynamoDB (or initializes with start number)
- Decrements the number
- Formats number as words and comma-separated value
- Randomly adds phrase and tag (1 in 5 chance)
- Posts tweet via Twitter API
- Updates DynamoDB with new state
- Schedules next countdown with random delay (14-88 days)
- Twitter rate limits: Automatically waits for rate limit reset
- DynamoDB throttling: Exponential backoff with up to 5 retries
- Other errors: Retries after 1 minute delay
- Negative numbers: Countdown stops gracefully
| Variable | Description | Default |
|---|---|---|
AWS_ACCESS_KEY_ID |
AWS access key | Required |
AWS_SECRET_ACCESS_KEY |
AWS secret key | Required |
AWS_REGION |
AWS region | us-east-1 |
DYNAMODB_TABLE |
DynamoDB table name | voncountdown |
PORT |
Server port | 8080 |
NODE_ENV |
Environment | development |
TWITTER_API_KEY |
Twitter API key | Required |
TWITTER_API_SECRET |
Twitter API secret | Required |
TWITTER_ACCESS_TOKEN |
Twitter access token | Required |
TWITTER_ACCESS_TOKEN_SECRET |
Twitter access token secret | Required |
- Helmet.js for security headers with Content Security Policy (CSP)
- CSP configured to allow external resources (Twitter widgets, jQuery, Wikipedia, YouTube)
- Rate limiting (100 req/15min per IP, 60 req/min for health endpoint)
- Input validation and sanitization
- XSS protection in templates
- Environment variable validation
- Request timeout handling (30 seconds)
- Log sanitization to prevent credential leakage
- Create App Runner service
- Connect to GitHub repository
- Set environment variables in App Runner console:
AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEYAWS_REGIONDYNAMODB_TABLETWITTER_API_KEYTWITTER_API_SECRETTWITTER_ACCESS_TOKENTWITTER_ACCESS_TOKEN_SECRETNODE_ENV=productionPORT=8080
- App Runner automatically:
- Builds and deploys on push to main branch
- Streams logs to CloudWatch Logs
- Handles scaling and health checks
Logging: All logs go to stdout/stderr and are automatically captured by CloudWatch Logs. Use AWS Console to view logs.
- Create Heroku app
- Set environment variables
- Deploy:
git push heroku mainFROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 8080
CMD ["npm", "start"]- Fork the repository
- Create a feature branch
- Make your changes
- Run tests:
npm test - Submit a pull request
Code and documentation copyright 2016 Brian Funk. Code released under the MIT license.