Duolingo Scraper - Profiles, Leaderboards, Courses & Vocabulary avatar

Duolingo Scraper - Profiles, Leaderboards, Courses & Vocabulary

Pricing

from $1.80 / 1,000 learner records

Go to Apify Store
Duolingo Scraper - Profiles, Leaderboards, Courses & Vocabulary

Duolingo Scraper - Profiles, Leaderboards, Courses & Vocabulary

Scrape public Duolingo data without login. Extract learner profiles with streaks, XP and achievements, weekly league standings, course catalogs with learner counts, and vocabulary words from lessons in clean structured data.

Pricing

from $1.80 / 1,000 learner records

Rating

0.0

(0)

Developer

Abot API

Abot API

Maintained by Community

Actor stats

1

Bookmarked

2

Total users

2

Monthly active users

4 days ago

Last modified

Categories

Share

Duolingo Scraper: Profiles, Leagues, Courses & Vocabulary

Duolingo Scraper turns Duolingo into structured learning data. Get learner profiles by username (streak, total XP, per-course XP and crowns, achievements), weekly league standings, the full public course catalog with learner counts, or word and translation rows from a course's lessons. Search by username, paste profile links, browse the catalog, or walk a course's vocabulary, then export to JSON, CSV or Excel, or pull the results straight into your app through the API. Every surface this actor reads works with no Duolingo account at all.

Why This Scraper?

  • Four ways to read the platform. Search by username (profiles or weekly league), paste profile links, browse the full course catalog, or read a course's vocabulary lesson by lesson.
  • No account needed anywhere. Profiles, leagues and the course catalog read anonymously; achievements detail and the vocabulary walk use a viewer session the actor mints for itself. You never paste a login or a token.
  • Deep learner profiles. Streak, total XP, per-course XP and crowns, join date, Super subscription flag, location, motivation, roles and full achievement badge detail.
  • The whole course catalog. 300+ language pairs with learner counts, release maturity and progress, filterable by keyword, language pair or learner floor, sorted by popularity or name.
  • Vocabulary reading. Walk a course's active lessons and collect word and translation pairs with their skill, unit and level context.
  • Built for schedules. Incremental mode returns only new and changed learners on recurring runs, and a refused run fails loudly instead of returning an empty dataset.
  • Resume large pulls. Continue an interrupted run from its run or dataset ID without paying twice for records you already have.

Use Cases

  • Language-learning coaches and classrooms: track streaks, XP and course progress for a roster of learners over time.
  • Community and leaderboard tools: build league standing dashboards or streak leaderboards from public profiles.
  • Course research and content teams: compare learner counts, release maturity and language pairs across the full catalog.
  • Vocabulary and curriculum builders: extract word and translation lists from specific lessons for flashcards or study guides.
  • Product and market research: watch which language pairs are growing by learner count over time with incremental mode.

Data You Get

Sample shape: values are illustrative placeholders, not from a live profile.

FieldExample
kind"profile" (also "league_summary", "course", "vocabulary")
recordId"200000042"
username"sample_learner"
name"Jordan Learner"
userId200000042
profileUrl"https://www.duolingo.com/profile/sample_learner"
joinedAt1700000000
streak42
totalXp8500
learningLanguage / fromLanguage"es" / "en"
hasPlusfalse
location"Sample City"
bio"Learning one language at a time."
courses[{"title": "Spanish", "xp": 8000, "crowns": 45}]
coursesCount2
achievements[{"name": "sample_badge", "tier": 2, "count": 15}]
achievementsDetail[{"name": "sample_badge", "tier": 2, "count": 15, "rewards": {}, "tierCounts": [5, 15, 50]}] (null when switched off)
achievementsCount2
motivation"CAREER"
roles[]
changeType"NEW"

League runs emit kind: "league_summary" rows with tier, highestLeague, numWins, numberOneFinishes, numberTwoFinishes, topThreeFinishes, streakInTier and lastWinContestEnd. Course-catalog runs emit kind: "course" rows with learningLanguageName, fromLanguageName, numLearners, releaseStatus and courseUrl. Vocabulary runs emit kind: "vocabulary" rows with word, translation, skillName, unitIndex and sectionIndex.

How to Use

  1. Pick a mode: search (profiles or weekly league by username), url (paste profile links), courses (the full catalog) or vocabulary (word rows from one course).
  2. Fill in the fields for that mode, and switch on the profile filters or achievements detail you need.
  3. Set Max items to control run size and cost, then click Start.
  4. Download the dataset as JSON, CSV or Excel, or read it through the API.

Read a set of public profiles:

{
"mode": "search",
"searchType": "profiles",
"usernames": ["sample_learner", "another_sample"]
}

Read weekly league standings for a set of learners:

{
"mode": "search",
"searchType": "leaderboard",
"usernames": ["sample_learner"]
}

List the course catalog (Spanish courses only here, most learners first):

{
"mode": "courses",
"courseQuery": "spanish",
"courseSort": "learners",
"maxItems": 50
}

Read vocabulary from a course pair:

{
"mode": "vocabulary",
"courseLearningLanguage": "es",
"courseFromLanguage": "en",
"maxItems": 100
}

Run it from your code

Python:

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/duolingo-learner-scraper").call(run_input={"mode": "search", "searchType": "profiles", "usernames": ["sample_learner"]})
for profile in client.dataset(run["defaultDatasetId"]).iterate_items():
print(profile["username"], profile["streak"], profile["totalXp"])

JavaScript:

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('abotapi/duolingo-learner-scraper').call({ mode: 'search', searchType: 'profiles', usernames: ['sample_learner'] });
const { items } = await client.dataset(run.defaultDatasetId).listItems();

Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.

Achievements, vocabulary and the self-minted session

Achievements detail (on by default) and the vocabulary walk both need a viewer session. The actor mints its own automatically: a short, one-time onboarding step with no captcha, no email and no signup form, then every read replays over plain HTTP. The session is reused across runs and refreshed when stale; a failed mint fails the run loudly instead of shipping empty rows. You never paste a credential, and Profiles search, League search and Course-catalog mode never need this step at all.

Resume and recurring updates

  • Resume (resumeFromRunId) continues one interrupted run: paste its run or dataset ID and the actor skips everything already collected there, so you don't pay twice.
  • Incremental mode (incrementalMode) is for scheduled runs over the same search. Each record is classified NEW, UPDATED (with changedFields), UNCHANGED (suppressed and not billed unless emitUnchanged is on), REAPPEARED or EXPIRED (only after a run that scanned the whole tracked scope, and only with emitExpired). stateKey names or shares the stored state; if you share one state across runs that each cover only part of the tracked learners, leave emitExpired off, or the learners a run did not cover come back as EXPIRED. Streak and XP are part of change detection, so a learner who practised since the last run comes back UPDATED; that is the progress signal. With incremental mode off, output is exactly as before.

Send results into your apps (MCP connectors)

Optionally pipe the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step after the scrape: the Apify dataset is never changed.

What gets written to the connector: a condensed, human-readable summary of each record, not the full JSON. Each item becomes one entry with a title and its key fields flattened to plain text. The complete record always stays in the Apify dataset.

  1. Authorize a connector once under Apify, Settings, Integrations (Notion, Linear, Airtable, or Apify).
  2. Select it in the "Pipe results into your apps" input field. (If the picker is empty, you haven't authorized a connector yet.)
  3. For Notion, also set notionParentPageUrl to the page where items should be created.

The connection is mediated by Apify's MCP proxy, so this actor never sees your third-party credentials. Leave the field empty to skip.

Input Parameters

ParameterTypeDefaultDescription
modestringsearchsearch, url, courses, or vocabulary.
searchTypestringprofilesprofiles (by username) or leaderboard (weekly league, by username). Search mode only.
usernamesarray["duolingo"]Usernames to read (Profiles and League search types). A username nobody matches is reported, not failed.
urlsarrayone profile linkProfile page links, like https://www.duolingo.com/profile/duolingo (URL mode).
courseQuerystringemptyOnly keep courses whose language names or codes contain this keyword (Course-catalog mode).
courseLearningLanguagestringemptyCourse pair selector: the learning language code (Course-catalog and Vocabulary modes).
courseFromLanguagestringemptyCourse pair selector: the source language code the course is taught from (Course-catalog and Vocabulary modes).
courseMinLearnersinteger0Only keep courses with at least this many learners (0 = no floor; Course-catalog mode).
courseSortstringlearnersCourse row order: most learners first, or language name A to Z (Course-catalog mode).
vocabSkillstringemptyOnly read lessons whose skill label contains this keyword (Vocabulary mode).
learningLanguagestringemptyOnly return profiles learning this language code (empty = all; applied to results).
hasPlusOnlybooleanfalseOnly return profiles with a paid Super subscription.
minTotalXpinteger0Only return profiles with at least this much total XP (0 = no floor).
minStreakinteger0Only return profiles with an active streak of at least this many days (0 = no floor).
fetchAchievementsbooleantrueAdd each profile's full achievements detail: one extra read per profile.
maxItemsinteger20Stop after this many records in total. Set 0 for no limit.
resumeFromRunIdstring(none)Paste a previous run ID or dataset ID to continue a large pull without duplicate records.
incrementalModebooleanfalseTurn this on for daily or recurring monitoring: later runs return only what changed.
stateKeystring(none)Optional. Name a monitoring campaign, or share state across differently configured runs (incremental mode only).
emitUnchangedbooleanfalseAlso return (and bill) unchanged records (incremental mode only).
emitExpiredbooleanfalseAlso return (and bill) records no longer found, after a complete scan (incremental mode only).
mcpConnectorsarray(none)Optional: send a summary of each record to apps you authorized under Integrations.
notionParentPageUrlstring(none)Notion connector only: page under which item pages are created.
maxNotifyListingsinteger50Cap on items written to each connector per run. Does not affect the dataset.
proxyConfigurationobjectApify ProxyApify Proxy settings; the default works on every plan.

Output Example

Sample shape: values are illustrative placeholders, not from a live profile.

{
"kind": "profile",
"recordId": "200000042",
"username": "sample_learner",
"name": "Jordan Learner",
"userId": 200000042,
"profileUrl": "https://www.duolingo.com/profile/sample_learner",
"bio": "Learning one language at a time.",
"joinedAt": 1700000000,
"streak": 42,
"totalXp": 8500,
"learningLanguage": "es",
"fromLanguage": "en",
"currentCourseId": "SAMPLE_ES_EN",
"hasPlus": false,
"location": "Sample City",
"coursesCount": 2,
"courses": [
{"id": "SAMPLE_ES_EN", "title": "Spanish", "learningLanguage": "es", "fromLanguage": "en", "xp": 8000, "crowns": 45},
{"id": "SAMPLE_FR_EN", "title": "French", "learningLanguage": "fr", "fromLanguage": "en", "xp": 500, "crowns": 3}
],
"achievements": [
{"name": "sample_badge", "tier": 2, "count": 15},
{"name": "sample_streak_badge", "tier": 1, "count": 7}
],
"achievementsCount": 2,
"achievementsDetail": [
{"name": "sample_badge", "tier": 2, "count": 15, "rewards": {}, "tierCounts": [5, 15, 50]},
{"name": "sample_streak_badge", "tier": 1, "count": 7, "rewards": {}, "tierCounts": [7, 30, 100]}
],
"motivation": "CAREER",
"roles": []
}

Plan Requirement

The default proxy setting works out of the box for every mode. Profile reads that need achievements detail or the vocabulary walk briefly mint a viewer session using the same connection settings; no extra plan tier is needed for that. For large or frequent runs, the residential proxy group gives more headroom; pick it under Connection.

FAQ

How much does it cost?

You pay a small start fee plus a fee per record returned. Achievements detail adds no separate charge; it only adds one extra read per profile. The Pricing tab shows the current rates. Use Max items to cap the cost of any run.

This actor collects only publicly available learner and course data. You are responsible for how you use it: follow Duolingo's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution.

Can I get only new or changed learners on a schedule?

Yes. Schedule the actor from the Schedules tab and turn on Incremental mode. Each run then returns only new, updated and reappeared records, and unchanged ones are not billed.

Why can't I search for a learner without knowing their username?

The source has no anonymous keyword search for people: profiles are read by exact username, or by pasting a profile link. Course-catalog mode does support a keyword search, since courses (not people) are the thing being searched there.

Why did my run fail instead of returning an empty dataset?

If the site refuses every request, the run stops with a clear message so "no matches" is never confused with "nothing could be read". Run it again in a few minutes. If only some usernames or links could be read, you still get what was found.

Can I use it with AI agents or MCP?

Yes. Call it from any Apify integration or MCP client, and use the connector field to push results into Notion, Linear or Airtable.

πŸ”— More scrapers you might like

Pair this actor with these related scrapers from the same team:

πŸ’Ό Superprof Scraper
Scrape Superprof tutors by subject and location, or paste tutor URLs. One rich record per...
πŸ’Ό Reed.co.uk Scraper
Scrape Reed.co.uk jobs, companies, courses and reviews by keyword, location, filters or...
⚽ OneFootball Scraper
Scrape public OneFootball data including football news, upcoming fixtures, match results...
⚽ FotMob Scraper ⚽ Match Details, Stats, Lineups & Players
From $0.8/1K. Pull structured football data from FotMob: match details with scores, team...
🧩 WEBTOON Scraper
Scrape the WEBTOON catalog into structured data. Extract series, genres, rankings and...
⚽ JioHotstar Scraper
Scrape the JioHotstar catalog by content type or URL. Extract shows, movies, episodes...

πŸ‘‰ Browse all abotapi scrapers

πŸ’¬ Support

  • 🐞 Found a bug or a missing field? Open a ticket on the Issues tab. We usually reply within hours.
  • πŸ› οΈ Need another site, extra fields or a private build? Email contact@abotapi.com.
  • ⭐ Enjoying it? A quick review on the actor page helps other users find it.