Fetch Duolingo user stats via the unofficial Duolingo API. No official API key required — uses the same endpoints the Duolingo web app uses.
Duolingo does not offer an official public API. The tracker uses the cookie-based session token from an active browser session.
One-time setup:
duolingo.comjwt_token cookieexport DUOLINGO_JWT="your_token_here"Alternatively the user can provide their username only — a subset of public stats is available without auth.
text
https://www.duolingo.com/2017-06-30
All requests should include:
text
Accept: application/json
Content-Type: application/json
Authorization: Bearer $DUOLINGO_JWT # omit if unauthenticated
bash
curl -s "https://www.duolingo.com/2017-06-30/users?username=USERNAME&fields=streak,xpGoal,xpGoalMetToday,lingots,totalXp,currentCourse,courses,streakData" \
-H "Authorization: Bearer $DUOLINGO_JWT" \
-H "Accept: application/json"
Key fields to surface:
FieldMeaningstreakCurrent day streakstreakData.currentStreak.lengthDays in current streakstreakData.longestStreak.lengthAll-time longest streaktotalXpLifetime XPxpGoalDaily XP goalxpGoalMetTodayWhether today's goal is met (bool)courses[].xpXP per language coursecourses[].crownsCrowns earned per coursecourses[].titleLanguage name
bash
# Get user ID first from profile, then:
curl -s "https://duolingo-leaderboards-prod.duolingo.com/leaderboards/7d9f5dd1-8423-491a-91f2-2532052038d8/users/USER_ID?get_users_only=true" \
-H "Authorization: Bearer $DUOLINGO_JWT"
League tiers (low → high): Bronze, Silver, Gold, Sapphire, Ruby, Emerald, Amethyst, Pearl, Obsidian, Diamond.
bash
curl -s "https://www.duolingo.com/2017-06-30/users/USER_ID/xp_summaries?startDate=YYYY-MM-DD" \
-H "Authorization: Bearer $DUOLINGO_JWT"
Set startDate to 7 days ago. Returns daily XP totals — use these to show a mini chart or bar summary.
Present stats in this format:
text
🔥 Streak: 47 days (longest: 93 days)
⭐ Today: 150 XP / 100 XP goal ✓
📚 Active course: Spanish (es) — 3,420 XP, 42 crowns
🏆 League: Gold | Weekly XP: 892
Weekly XP:
Mon ████████ 180
Tue ██████ 120
Wed █████ 100
Thu ████████ 160
Fri ██████ 132
Sat ███ 60
Sun ████████ 140
If the daily goal is not yet met, flag it clearly so the user knows to practice today.
For users who don't want to share their JWT, these endpoints work without auth for public profiles:
bash
curl -s "https://www.duolingo.com/users/USERNAME" \
-H "Accept: application/json"
Returns streak, learning_language, level, totalXp, courses. Fewer fields but sufficient for a quick summary.
ProblemFix401 UnauthorizedJWT expired — user needs to re-copy token from browserEmpty streak dataUser hasn't practiced in 7+ days (streak likely 0)Username not foundCheck exact username (case-sensitive) on duolingo.com/profileRate limited (429)Wait 60 seconds before retrying
Always remind the user that their JWT token is sensitive — treat it like a password. Never log it or include it in outputs.