Duolingo Scraper
Pricing
from $1.60 / 1,000 language courses
Duolingo Scraper
Get public Duolingo language courses, learner profiles, weekly league standings, and vocabulary as structured rows. Pick a result type, enter your targets, and run it. No Duolingo sign-in needed.
Pricing
from $1.60 / 1,000 language courses
Rating
0.0
(0)
Developer
Maxime Dupré
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
20 days ago
Last modified
Categories
Share
🦉 Collect public Duolingo courses, learners, and vocabulary as structured data
This Actor helps language teachers, course designers, researchers, and developers collect public Duolingo data without signing in. It returns structured rows about Duolingo languages. Rows cover courses, learner profiles, weekly league standings, and vocabulary. You can compare courses, review learner streaks and XP, or build word lists for a language pair, without copying each page by hand.
Use it to:
- Compare Duolingo language courses by learner count, source language, and release phase.
- Filter learner profiles by total XP, streak, or Super status, starting from usernames or profile links.
- Track weekly league standings for a list of learners, including tier, wins, and placement history.
- Build a Duolingo Spanish vocabulary list with translations, skills, and units for a language pair, such as Spanish taught in English.
- Recheck a monitored lookup and receive only the new or changed records.
🧩 Four kinds of public Duolingo data
- Courses: language courses with their teaching and learning languages, learner counts, and release phase.
- Learner profiles: public names, streaks, total XP, languages, and current course. Enrolled courses and achievements are included when the source shows them.
- League summaries: each learner's weekly league tier, wins, podium finishes, and placement history.
- Vocabulary: words and phrases for one language pair, with translations, skills, and units.
Each row is public data that was read and checked successfully. Failed, private, invalid, or unreadable targets go to the warning log, not the dataset.
▶️ Run a Duolingo data collection
- Open this Actor in Apify Console, or call it through the Apify API.
- Choose one result type, then fill in only the fields for that type.
- Start the run. When it finishes, open the Output tab to see the rows.
⚙️ Input
Choose one result type first. Fields for other result types are ignored.
Input fields
| Field | Type | What it does |
|---|---|---|
Result type (resultType) | string | Choose one result type for the run: Courses, Learner profiles, Learner league summaries, or Vocabulary. The form starts with Courses. |
Course name or code (courseNameOrCode) | string | For Courses, narrow the results by a course name or code. |
Minimum learners (minLearners) | integer | For Courses, keep only courses with at least this many learners. |
Course order (courseSort) | string | For Courses, sort by most learners first (default) or by language name, A to Z. |
Find profiles by (findProfilesBy) | string | For Learner profiles, choose whether the Learners field holds usernames (default) or profile links. |
Minimum XP (minXp) | integer | For Learner profiles, keep learners with at least this much total XP. |
Minimum streak (minStreak) | integer | For Learner profiles, keep learners with a current streak of at least this many days. |
Super status (subscription) | string | For Learner profiles, keep learners with Super (super) or without Super (notSuper). Leave blank to include either. |
Learners (learners) | array of strings | Required for Learner profiles and Learner league summaries. For league summaries, enter usernames only. For profiles, enter usernames or profile links, as chosen in Find profiles by. Use one kind of value per run. Profile links can use a username or a numeric user ID. |
Source language code (sourceLanguage) | string | For Courses, filter by the language used to teach the course, such as en for English. Required for Vocabulary. |
Learning language code (learningLanguage) | string | For Courses, filter by the language being learned, such as es for Spanish. For Learner profiles, filter by their learning language. Required for Vocabulary. |
Return unchanged records (changeOutput) | string | Choose changes only (default) or all items and changes. Change tracking runs automatically. A record counts as missing only after a full successful scan. |
Monitoring campaign (monitoringCampaign) | string | Leave blank to keep history separate for this lookup. Use the same name in another run to share its history. |
Maximum results (maxItems) | integer | Stop after this many results. Leave blank to collect all available results until the source has no more. The form starts at 10. |
Continue collection from (resumeFrom) | string | Enter an earlier Apify run ID or dataset ID to continue its saved progress. Keep the same result type and lookup settings. Leave blank to start a new collection. |
Example input
This is the default input. It returns up to 10 course rows.
{"resultType": "courses","courseSort": "popularity","findProfilesBy": "usernames","changeOutput": "changes","maxItems": 10}
🧾 Output
Each run saves its rows to the run's default dataset. Open the Output tab in Apify Console to see an overview table, or download the rows as JSON, CSV, or Excel. Every row has resultType, changeType, firstObservedAt, and latestObservedAt fields. The tables below list the fields for each result type.
Course rows
| Field | Type | What it does |
|---|---|---|
resultType | string | Always courses for this row type. |
changeType | string | How this read compares with saved history: new, updated, reappeared (seen again after it was counted as missing), or unchanged. |
firstObservedAt | string | Date and time this course was first read and checked successfully in its history. |
latestObservedAt | string | Date and time this course was most recently read and checked successfully. |
courseId | string | Duolingo course ID, used to match course records. |
sourceLanguage | string | Code for the language used to teach the course, such as en. |
sourceLanguageName | string | Name of the teaching language, such as English. |
learningLanguage | string | Code for the language being learned, such as es. |
learningLanguageName | string | Name of the language being learned, such as Spanish. |
title | string | Course title reported by Duolingo. |
learners | integer | Number of learners reported for the course. |
releasePhase | string | Release phase reported by Duolingo. |
developmentProgress | number | Course development progress, on the scale Duolingo reports. |
courseUrl | string | Public link to the course. |
Example course row
{"resultType": "courses","courseId": "DUOLINGO_ES_EN","sourceLanguage": "en","sourceLanguageName": "English","learningLanguage": "es","learningLanguageName": "Spanish","title": "Spanish","learners": 41971541,"releasePhase": "3","developmentProgress": 200,"courseUrl": "https://www.duolingo.com/course/es/en","changeType": "new","firstObservedAt": "2026-10-10T00:34:31.308Z","latestObservedAt": "2026-10-10T00:34:31.308Z"}
Learner profile rows
| Field | Type | What it does |
|---|---|---|
resultType | string | Always profiles for this row type. |
changeType | string | How this read compares with saved history: new, updated, reappeared (seen again after it was counted as missing), or unchanged. |
firstObservedAt | string | Date and time this profile was first read and checked successfully in its history. |
latestObservedAt | string | Date and time this profile was most recently read and checked successfully. |
username | string | Public username. |
displayName | string | Public name shown on the profile. |
joinedAt | string | Date and time the account joined. |
location | string | Public location, when the learner shares one. |
avatarUrl | string | Public link to the profile picture. |
sourceLanguage | string | Code for the source language on the profile, such as en. |
learningLanguage | string | Code for the language the learner is studying, such as fr. |
currentCourseId | string | ID of the course the learner is on now. Use it to match course rows. |
streak | integer | Current streak length, in days. |
currentStreak | object | Current streak period, when Duolingo reports one. |
currentStreak.startDate | string | Start date of the current streak. |
currentStreak.endDate | string | End date of the current streak. |
longestStreak | object | Longest streak period, when Duolingo reports one. |
longestStreak.startDate | string | Start date of the longest streak. |
longestStreak.endDate | string | End date of the longest streak. |
totalXp | integer | Total XP reported for the learner. |
hasSuper | boolean | Whether the public source reports an active Super subscription. |
roles | array of strings | Public account roles reported by Duolingo. |
courses | array of objects | Enrolled courses shown on the profile. |
courses.courseId | string | Course ID, used to match course rows. |
courses.sourceLanguage | string | Code for the teaching language of the course. |
courses.sourceLanguageName | string | Name of the teaching language, when Duolingo reports it. |
courses.learningLanguage | string | Code for the language being learned. |
courses.learningLanguageName | string | Name of the language being learned, when Duolingo reports it. |
courses.title | string | Course title reported by Duolingo. |
courses.xp | integer | XP earned in that course. |
courses.crowns | integer | Crown progress in that course. |
achievements | array of objects | Achievements shown on the profile, when the source exposes them. |
achievements.name | string | Achievement name. |
achievements.description | string | What the achievement is for. |
achievements.tier | integer | Achievement tier. |
achievements.count | integer | Count reported for the achievement. |
achievements.badgeUrl | string | Link to the achievement badge image. |
Example learner profile row
{"resultType": "profiles","username": "tsannifer","displayName": "Jennifer","joinedAt": "2016-06-10T01:58:31.000Z","avatarUrl": "https://d3gq3s1iyyx31w.cloudfront.net/static/render/bg/BackgroundColor-3/Body-1/ClothingColor-9/Expression-23/EyeColor-1/FacialHair-0/FacialHairColor-1/Glasses-2/GlassesColor-8/Headwear-0/HeadwearColor-1/MainHair-1/MainHairColor-14/Nose%20Piercing-0/Piercings-0/SkinTone-2/Wrinkles-2","sourceLanguage": "en","learningLanguage": "fr","currentCourseId": "DUOLINGO_FR_EN","streak": 0,"longestStreak": {"startDate": "2023-06-28","endDate": "2026-05-08"},"totalXp": 173178,"hasSuper": false,"roles": ["users"],"courses": [{"courseId": "DUOLINGO_FR_EN","sourceLanguage": "en","sourceLanguageName": "English","learningLanguage": "fr","learningLanguageName": "French","title": "French","xp": 138622,"crowns": 0},{"courseId": "DUOLINGO_RU_EN","sourceLanguage": "en","sourceLanguageName": "English","learningLanguage": "ru","learningLanguageName": "Russian","title": "Russian","xp": 370,"crowns": 0},{"courseId": "DUOLINGO_ES_EN","sourceLanguage": "en","sourceLanguageName": "English","learningLanguage": "es","learningLanguageName": "Spanish","title": "Spanish","xp": 12806,"crowns": 0},{"courseId": "DUOLINGO_DE_EN","sourceLanguage": "en","sourceLanguageName": "English","learningLanguage": "de","learningLanguageName": "German","title": "German","xp": 3610,"crowns": 0},{"courseId": "DUOLINGO_IT_EN","sourceLanguage": "en","sourceLanguageName": "English","learningLanguage": "it","learningLanguageName": "Italian","title": "Italian","xp": 1548,"crowns": 0},{"courseId": "DUOLINGO_EL_EN","sourceLanguage": "en","sourceLanguageName": "English","learningLanguage": "el","learningLanguageName": "Greek","title": "Greek","xp": 12179,"crowns": 0},{"courseId": "DUOLINGO_GA_EN","sourceLanguage": "en","sourceLanguageName": "English","learningLanguage": "ga","learningLanguageName": "Irish","title": "Irish","xp": 436,"crowns": 0},{"courseId": "DUOLINGO_SV_EN","sourceLanguage": "en","sourceLanguageName": "English","learningLanguage": "sv","learningLanguageName": "Swedish","title": "Swedish","xp": 80,"crowns": 0},{"courseId": "DUOLINGO_RO_EN","sourceLanguage": "en","sourceLanguageName": "English","learningLanguage": "ro","learningLanguageName": "Romanian","title": "Romanian","xp": 583,"crowns": 0},{"courseId": "DUOLINGO_UK_EN","sourceLanguage": "en","sourceLanguageName": "English","learningLanguage": "uk","learningLanguageName": "Ukrainian","title": "Ukrainian","xp": 109,"crowns": 0},{"courseId": "DUOLINGO_DA_EN","sourceLanguage": "en","sourceLanguageName": "English","learningLanguage": "da","learningLanguageName": "Danish","title": "Danish","xp": 555,"crowns": 0},{"courseId": "DUOLINGO_NO-BO_EN","sourceLanguage": "en","learningLanguage": "no-BO","title": "Norwegian (Bokmål)","xp": 219,"crowns": 0},{"courseId": "DUOLINGO_TR_EN","sourceLanguage": "en","sourceLanguageName": "English","learningLanguage": "tr","learningLanguageName": "Turkish","title": "Turkish","xp": 36,"crowns": 0},{"courseId": "DUOLINGO_ZH-CN_EN","sourceLanguage": "en","learningLanguage": "zh","title": "Chinese (Simplified)","xp": 1055,"crowns": 0},{"courseId": "DUOLINGO_LA_EN","sourceLanguage": "en","sourceLanguageName": "English","learningLanguage": "la","learningLanguageName": "Latin","title": "Latin","xp": 180,"crowns": 0},{"courseId": "DUOLINGO_AR_EN","sourceLanguage": "en","sourceLanguageName": "English","learningLanguage": "ar","learningLanguageName": "Arabic","title": "Arabic","xp": 302,"crowns": 0},{"courseId": "DUOLINGO_NL-NL_EN","sourceLanguage": "en","learningLanguage": "nl-NL","title": "Dutch","xp": 60,"crowns": 0},{"courseId": "DUOLINGO_HI_EN","sourceLanguage": "en","sourceLanguageName": "English","learningLanguage": "hi","learningLanguageName": "Hindi","title": "Hindi","xp": 28,"crowns": 0}],"achievements": [{"name": "Photogenic","description": "Add a profile picture","tier": 1,"count": 1,"badgeUrl": "https://d35aaqx5ub95lt.cloudfront.net/images/achievements/39ac3b013faeeba3d0afb91f7230a43f.svg"}],"changeType": "new","firstObservedAt": "2026-10-10T00:41:06.286Z","latestObservedAt": "2026-10-10T00:41:06.286Z"}
League summary rows
| Field | Type | What it does |
|---|---|---|
resultType | string | Always leagues for this row type. |
changeType | string | How this read compares with saved history: new, updated, reappeared (seen again after it was counted as missing), or unchanged. |
firstObservedAt | string | Date and time this summary was first read and checked successfully in its history. |
latestObservedAt | string | Date and time this summary was most recently read and checked successfully. |
username | string | Public username of the learner. |
leagueTier | string | Current league tier reported by Duolingo. |
highestLeague | string | Highest league tier the learner has reached. |
wins | integer | League wins reported by Duolingo. |
podiumFinishes | integer | Podium finishes reported by Duolingo. |
firstPlaceFinishes | integer | First-place finishes reported by Duolingo. |
secondPlaceFinishes | integer | Second-place finishes reported by Duolingo. |
weeksInTier | integer | Weeks spent in the current tier. |
lastWinDate | string | Date of the most recent league win. |
Example league summary row
{"resultType": "leagues","username": "Luis","leagueTier": "9","highestLeague": "9","wins": 7,"firstPlaceFinishes": 3,"secondPlaceFinishes": 5,"podiumFinishes": 18,"weeksInTier": 2,"lastWinDate": "2026-08-10T03:00:00Z","changeType": "new","firstObservedAt": "2026-10-10T00:34:51.107Z","latestObservedAt": "2026-10-10T00:34:51.107Z"}
Vocabulary rows
| Field | Type | What it does |
|---|---|---|
resultType | string | Always vocabulary for this row type. |
changeType | string | How this read compares with saved history: new, updated, reappeared (seen again after it was counted as missing), or unchanged. |
firstObservedAt | string | Date and time this entry was first read and checked successfully in its history. |
latestObservedAt | string | Date and time this entry was most recently read and checked successfully. |
sourceLanguage | string | Code for the language used to teach the entry, such as en. |
learningLanguage | string | Code for the language being learned, such as es. |
text | string | Word or phrase in the language being learned. |
translations | array of strings | Translations into the teaching language. |
skill | string | Skill name attached to the word or phrase. |
unit | string | Unit name attached to the word or phrase. |
pathPosition | object | Position of the entry in the learning path, as reported by the source. |
pathPosition.unitIndex | integer | Index of the unit in the learning path. |
audioUrls | array of strings | Direct links to pronunciation audio from the source. |
Example vocabulary row
{"resultType": "vocabulary","sourceLanguage": "en","learningLanguage": "es","text": "Un vaso de agua, por favor.","translations": ["A glass of water, please."],"skill": "Cafe","unit": "Order at a café","pathPosition": {"unitIndex": 0},"audioUrls": ["https://d1vq87e9lcf771.cloudfront.net/miguel/439c80f8627350ea006f0537b759da1a"],"changeType": "new","firstObservedAt": "2026-10-10T00:34:49.599Z","latestObservedAt": "2026-10-10T00:34:49.599Z"}
💳 Pricing
This Actor uses pay-per-event pricing. You pay for each row below that is read successfully and saved to your dataset:
- Language course: each course read successfully and saved to your dataset.
- Learner profile: each learner profile read successfully and saved, including any public course details.
- League summary: each learner's league summary read successfully and saved.
- Vocabulary word: each word or phrase read successfully and saved.
Prices can differ by Apify plan tier, so check the Store page for current prices.
🔌 Integrations
- Call this Actor through the Apify API from scripts, apps, or internal tools.
- Export the dataset as JSON, CSV, or Excel from Apify Console.
- Schedule repeat runs with the same settings to follow changes over time.
❓ FAQ
Can I get only Duolingo English courses?
Yes. For Courses, set Learning language code to en to see courses for learning English. Use Source language code to filter by the language a course is taught in, such as en for English.
Can I look up learners by display name?
No. Learner lookups need public usernames or public profile links.
Does it return followers, following lists, or user reviews?
No. It does not return follower or following lists, learner cohort rankings, or Duolingo user reviews.
Does it return course descriptions?
No. Course rows include public catalog details, such as titles, language codes, learner counts, and release phase. Course page descriptions are not included. Vocabulary rows return the available words and phrases from one selected course, with translations, skills, and units.
Does a failed lookup mean a learner or course was deleted?
No. A failed lookup does not prove that anything was removed. A record counts as missing only after a full, successful scan.
Can I continue a large run that stopped early?
Yes. Enter the earlier run ID or dataset ID in Continue collection from. Keep the same result type and lookup settings, and the run picks up from its saved progress.
How do I track changes over time?
Run the Actor again with the same lookup settings. Each row's changeType field shows how it compares with saved history. Use the same Monitoring campaign name in each run to share history. Leave it blank to keep each lookup's history separate.
How many results can one run return?
There is no fixed maximum. Leave Maximum results blank to collect all available results until the source has no more. Set a number to stop earlier.
What am I charged for?
You are charged for each successful row saved to the dataset, as listed in Pricing.
Is this the official Duolingo app or website?
No. This is an independent Actor that reads public Duolingo data. You do not need a Duolingo account or sign-in to run it.
📝 Changelog
v0.0 (11-10-2026)
- Initial release.
🆘 Support
For issues, questions, or feature requests, file a ticket and I'll fix or implement it in less than 24h 🫡
🔗 Related Actors
- Duolingo Scraper: Get a Duolingo course catalog with learner counts, progress phases, and source languages.
- Duolingo Scraper - Profiles, Leaderboards, Courses & Vocabulary: Get learner profiles with streaks, XP, and achievements, plus weekly league standings.
- Duolingo Language Data Scraper: Pull words with translations, skills, and units for one language pair to build study lists.
- Tatoeba Sentence Corpus Scraper: Collect example sentences and their translations for a language pair.
- Free Dictionary Scraper: Look up definitions, phonetics, audio pronunciation, and examples for a word list, with multi-language support.
Made with ❤️ by Maxime Dupré