Never miss a day. Get a phone call or WhatsApp message if you haven't solved a LeetCode problem by the end of the day — automatically, every day, via GitHub Actions.
Three scheduled GitHub Actions jobs run at 9:00 PM, 11:00 PM, and 11:30 PM GMT each day.
Each job:
- Checks your LeetCode profile for any accepted submission today (via the public GraphQL API — no login needed).
- Skips silently if you've already solved a problem.
- Calls or messages you via Twilio if you haven't.
Once a solve is detected, the result is cached so subsequent jobs that day are instant no-ops.
9:00 PM → check → not solved → 📞 call / 💬 WhatsApp
11:00 PM → check → not solved → 📞 call / 💬 WhatsApp
11:30 PM → check → not solved → 📞 call / 💬 WhatsApp
(or) → solved ✅ → skip (cached)
| Requirement | Notes |
|---|---|
| GitHub account | Free — for Actions |
| Twilio account | Free trial gives ~$15 credit (~1500 minutes of calls) |
| Public LeetCode profile | Your recent accepted submissions must be publicly visible |
Click Fork at the top right of this page.
- Sign up at twilio.com/try-twilio.
- From the Twilio Console, note your:
- Account SID
- Auth Token
- Get a Twilio phone number (free with trial).
For WhatsApp (optional): Enable the WhatsApp Sandbox in the Twilio Console under Messaging → Try it out → Send a WhatsApp message and follow the one-time opt-in step on your phone.
Go to your forked repo → Settings → Secrets and variables → Actions → New repository secret.
Add the following secrets:
| Secret | Required | Description |
|---|---|---|
LEETCODE_USERNAME |
✅ | Your LeetCode username |
TWILIO_ACCOUNT_SID |
✅ | From Twilio Console |
TWILIO_AUTH_TOKEN |
✅ | From Twilio Console |
TWILIO_FROM_NUMBER |
✅ | Your Twilio number in E.164 format, e.g. +12015551234 |
TO_PHONE_NUMBER |
✅ | Your personal number in E.164 format, e.g. +919876543210 |
NOTIFICATION_CHANNEL |
✅ | call, whatsapp, or both |
LEETCODE_TIMEZONE |
optional | IANA timezone, e.g. Asia/Kolkata. Defaults to UTC |
REMINDER_MESSAGE |
optional | Custom TTS / WhatsApp message. Uses default if blank |
ERROR_ALERT_MESSAGE |
optional | Message sent when script errors. Uses default if blank |
REMINDER_TIMES |
optional | UTC times to notify, e.g. 21:00,23:00,23:30. Defaults to 9 PM, 11 PM, 11:30 PM UTC |
NOTIFY_ON_ERROR |
optional | true / false. Defaults to true |
Tip: E.164 format means a
+followed by country code and number, no spaces or dashes. E.g.+14155552671.
Go to the Actions tab in your forked repo and click "I understand my workflows, go ahead and enable them" if prompted.
Go to Actions → LeetCode Streak Reminder → Run workflow → Run workflow.
Check the logs — it should either report a solve found (and skip) or fire a notification.
The reminder times are defined in .github/workflows/reminder.yml. Edit the cron expressions to your preferred times (all times are UTC):
schedule:
- cron: "0 21 * * *" # 9:00 PM UTC
- cron: "0 23 * * *" # 11:00 PM UTC
- cron: "30 23 * * *" # 11:30 PM UTCUse crontab.guru to build custom cron expressions.
Note: GitHub Actions has ~1 minute of scheduling latency, so jobs may fire slightly after the scheduled time.
Set the REMINDER_MESSAGE secret to any text you like. For voice calls, the text is read aloud twice using Amazon Polly's Joanna voice. Keep it under ~200 characters for best results.
Default message:
"Hey! You haven't solved a LeetCode problem today. Don't break your streak! Open LeetCode now and keep that green dot alive."
# Clone your fork
git clone https://github.com/dotenv-live/LeetcodeAlarmer.git
cd LeetcodeAlarmer
# Install dependencies
pip install -r requirements.txt
# Copy and fill in the env file
cp .env.example .env
# Edit .env with your credentials
# Load env vars and run
export $(grep -v '^#' .env | xargs)
python main.pyExit codes:
| Code | Meaning |
|---|---|
0 |
Problem solved today — no reminder sent |
1 |
No solve found — reminder sent successfully |
2 |
Error occurred |
leetcode-streak-reminder/
├── main.py # Orchestrator — entry point
├── config.py # Env var loading & validation
├── leetcode.py # LeetCode GraphQL scraper
├── notifier.py # Twilio voice call & WhatsApp sender
├── requirements.txt
├── .env.example # Copy to .env for local dev
└── .github/
└── workflows/
└── reminder.yml # Scheduled GitHub Actions workflow
Q: Will this work if my LeetCode profile is private? The recent accepted submissions endpoint is public and does not require authentication. However, if LeetCode ever changes this behaviour, the script will fail gracefully and (optionally) notify you of the error.
Q: Does this count Easy/Medium/Hard equally? Yes — any accepted submission counts towards keeping your streak alive, regardless of difficulty.
Q: What if I solve a problem after the 9 PM reminder but before 11 PM? The 11 PM job will detect your solve and skip the notification. The result is also cached so the 11:30 PM job skips instantly without even calling the LeetCode API.
Q: Is my Twilio Auth Token safe in GitHub Secrets? Yes — GitHub Secrets are encrypted and never exposed in logs. They are only injected into the runner's environment at runtime.
Q: How much will this cost? Twilio's free trial gives ~$15 credit. Outbound calls cost ~$0.014/min and WhatsApp messages cost ~$0.005 each. At 3 reminders/day worst case, expect less than $0.10/day — and usually far less because solved days produce no calls.
MIT — see LICENSE.