Magnus Bot is a lightweight, serverless chess-club assistant written in TypeScript. It runs entirely on Vercel functions and uses the grammY framework to talk to the Telegram Bot API.
It helps a small community track their Chess.com and Lichess progress with:
- personal rating / puzzle statistics (
/stats) from both platforms - monthly leaderboards (
/top) supporting multiple game types - head-to-head comparisons (
/score @user1 @user2) - bilingual support (English/Tajik)
- dynamic user registration with platform choice
- ♟️ Chess.com - Full stats, games, and leaderboards
- ♟️ Lichess - Full stats, games, and leaderboards
- 🔄 Dual Registration - Users can register for one or both platforms
- 📊
/stats- View chess statistics from registered platforms - 🏆
/top [option]- Leaderboards with multiple modes:bugun(default) - Today's top players (earns championship points!)blitz- Monthly blitz leaderboardbullet- Monthly bullet leaderboardrapid- Monthly rapid leaderboard
- 🏆
/standings- Championship standings and recent daily champions - ⚔️
/score @user1 @user2- Head-to-head comparison - 🆕
/start- Register with Chess.com and/or Lichess usernames
- 🥇 Daily Competition: Top 3 players earn points each day
- 🎯 Point Awards: 1st place (300pts), 2nd place (200pts), 3rd place (100pts)
- ⏰ Daily Reset: Championships awarded at 23:55 Tajikistan time
- 📊 Requirements: Minimum 3 games to qualify for daily championship
- 🏆 Ongoing Competition: Track your progress with
/standings - ⚖️ Fair Ranking: Weighted score system rewards both skill and game volume
- 🇺🇸 English
- 🇹🇯 Tajik (Тоҷикӣ)
- Node.js (v18+)
- Telegram Bot Token
- Supabase Account (free tier works)
Create a .env file with your configuration:
# Telegram Bot Token
BOT_TOKEN=123456:ABC‑DEF…
# Supabase Configuration
SUPABASE_URL=https://your-supabase-project.supabase.co
SUPABASE_ANON_KEY=your_supabase_anon_key_here
# Lichess API Token (optional, but recommended)
LICHESS_API_TOKEN=lip_your_personal_token_hereNote about Lichess API Token: While the Lichess API token is optional, it's highly recommended for reliable access to user stats and games. Without a token, some Lichess features may be limited or fail due to rate limiting.
To get a Lichess API token:
- Visit https://lichess.org/account/oauth/token/create
- Create a Personal Access Token with these scopes:
Read preferences(optional)- No other special scopes needed for basic stats
- Add the token to your
.envfile asLICHESS_API_TOKEN
- Create a new Supabase project at https://supabase.com
- Run the SQL commands from
schema.sqlin your Supabase SQL editor - If migrating from an older version, also run
schema_lichess_migration.sql - Copy your project URL and anon key to the
.envfile
# Install dependencies
npm install
# Start TypeScript directly
npm run devLocal bots use long‑polling. When deployed to Vercel, the bot automatically switches to webhooks.
- Import the repo in the Vercel dashboard.
- Environment → Add environment variables:
BOT_TOKEN(your Telegram bot token)SUPABASE_URL(your Supabase project URL)SUPABASE_ANON_KEY(your Supabase anon key)LICHESS_API_TOKEN(your Lichess personal access token - optional but recommended)
- Build Command – leave empty (Vercel auto‑installs & transpiles TS).
- Click Deploy.
- Set the webhook once (replace
<project>and region if needed):
curl \
-X POST "https://api.telegram.org/bot$BOT_TOKEN/setWebhook" \
-d "url=https://<project>.vercel.app/webhook"That's it — Vercel's global edge will now forward Telegram updates to your function.
- Users type
/start - Bot prompts to choose Chess.com or Lichess (or both)
- Bot validates usernames exist on chosen platforms
- User data is stored in Supabase database
- Users can add additional platforms later
- Fetches real-time data from Chess.com and/or Lichess APIs
- Shows ratings for rapid, blitz, bullet, and puzzles
- Displays combined stats if user is registered on both platforms
- Supports multiple time periods and game types
- Uses Tajikistan timezone (GMT+5) for local relevance
- Ranks by win rate with tie-breaking logic
- Works with both Chess.com and Lichess games
- Compares game history between two players
- Prioritizes Chess.com if both players are registered there
- Falls back to Lichess for comparison
- Shows monthly statistics and game links
The bot uses a single user_mappings table:
CREATE TABLE user_mappings (
id BIGSERIAL PRIMARY KEY,
telegram_username VARCHAR(255) NOT NULL UNIQUE,
chess_username VARCHAR(255),
lichess_username VARCHAR(255),
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
CONSTRAINT at_least_one_chess_platform CHECK (
chess_username IS NOT NULL OR lichess_username IS NOT NULL
)
);- Frontend: Telegram Bot (grammY framework)
- Backend: Vercel Serverless Functions
- Database: Supabase PostgreSQL
- APIs: Chess.com Public API, Lichess API
- Language: TypeScript
- Fork the repository
- Create a feature branch
- Make your changes
- Test locally with both Chess.com and Lichess accounts
- Submit a pull request
This project is open source and available under the MIT License.
Built with ❤️ for chess communities everywhere