Duolingo Scraper avatar

Duolingo Scraper

Pricing

from $1.60 / 1,000 language courses

Go to Apify Store
Duolingo Scraper

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é

Maxime Dupré

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

20 days ago

Last modified

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

  1. Open this Actor in Apify Console, or call it through the Apify API.
  2. Choose one result type, then fill in only the fields for that type.
  3. 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

FieldTypeWhat it does
Result type (resultType)stringChoose one result type for the run: Courses, Learner profiles, Learner league summaries, or Vocabulary. The form starts with Courses.
Course name or code (courseNameOrCode)stringFor Courses, narrow the results by a course name or code.
Minimum learners (minLearners)integerFor Courses, keep only courses with at least this many learners.
Course order (courseSort)stringFor Courses, sort by most learners first (default) or by language name, A to Z.
Find profiles by (findProfilesBy)stringFor Learner profiles, choose whether the Learners field holds usernames (default) or profile links.
Minimum XP (minXp)integerFor Learner profiles, keep learners with at least this much total XP.
Minimum streak (minStreak)integerFor Learner profiles, keep learners with a current streak of at least this many days.
Super status (subscription)stringFor Learner profiles, keep learners with Super (super) or without Super (notSuper). Leave blank to include either.
Learners (learners)array of stringsRequired 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)stringFor Courses, filter by the language used to teach the course, such as en for English. Required for Vocabulary.
Learning language code (learningLanguage)stringFor 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)stringChoose 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)stringLeave blank to keep history separate for this lookup. Use the same name in another run to share its history.
Maximum results (maxItems)integerStop 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)stringEnter 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

FieldTypeWhat it does
resultTypestringAlways courses for this row type.
changeTypestringHow this read compares with saved history: new, updated, reappeared (seen again after it was counted as missing), or unchanged.
firstObservedAtstringDate and time this course was first read and checked successfully in its history.
latestObservedAtstringDate and time this course was most recently read and checked successfully.
courseIdstringDuolingo course ID, used to match course records.
sourceLanguagestringCode for the language used to teach the course, such as en.
sourceLanguageNamestringName of the teaching language, such as English.
learningLanguagestringCode for the language being learned, such as es.
learningLanguageNamestringName of the language being learned, such as Spanish.
titlestringCourse title reported by Duolingo.
learnersintegerNumber of learners reported for the course.
releasePhasestringRelease phase reported by Duolingo.
developmentProgressnumberCourse development progress, on the scale Duolingo reports.
courseUrlstringPublic 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

FieldTypeWhat it does
resultTypestringAlways profiles for this row type.
changeTypestringHow this read compares with saved history: new, updated, reappeared (seen again after it was counted as missing), or unchanged.
firstObservedAtstringDate and time this profile was first read and checked successfully in its history.
latestObservedAtstringDate and time this profile was most recently read and checked successfully.
usernamestringPublic username.
displayNamestringPublic name shown on the profile.
joinedAtstringDate and time the account joined.
locationstringPublic location, when the learner shares one.
avatarUrlstringPublic link to the profile picture.
sourceLanguagestringCode for the source language on the profile, such as en.
learningLanguagestringCode for the language the learner is studying, such as fr.
currentCourseIdstringID of the course the learner is on now. Use it to match course rows.
streakintegerCurrent streak length, in days.
currentStreakobjectCurrent streak period, when Duolingo reports one.
currentStreak.startDatestringStart date of the current streak.
currentStreak.endDatestringEnd date of the current streak.
longestStreakobjectLongest streak period, when Duolingo reports one.
longestStreak.startDatestringStart date of the longest streak.
longestStreak.endDatestringEnd date of the longest streak.
totalXpintegerTotal XP reported for the learner.
hasSuperbooleanWhether the public source reports an active Super subscription.
rolesarray of stringsPublic account roles reported by Duolingo.
coursesarray of objectsEnrolled courses shown on the profile.
courses.courseIdstringCourse ID, used to match course rows.
courses.sourceLanguagestringCode for the teaching language of the course.
courses.sourceLanguageNamestringName of the teaching language, when Duolingo reports it.
courses.learningLanguagestringCode for the language being learned.
courses.learningLanguageNamestringName of the language being learned, when Duolingo reports it.
courses.titlestringCourse title reported by Duolingo.
courses.xpintegerXP earned in that course.
courses.crownsintegerCrown progress in that course.
achievementsarray of objectsAchievements shown on the profile, when the source exposes them.
achievements.namestringAchievement name.
achievements.descriptionstringWhat the achievement is for.
achievements.tierintegerAchievement tier.
achievements.countintegerCount reported for the achievement.
achievements.badgeUrlstringLink 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

FieldTypeWhat it does
resultTypestringAlways leagues for this row type.
changeTypestringHow this read compares with saved history: new, updated, reappeared (seen again after it was counted as missing), or unchanged.
firstObservedAtstringDate and time this summary was first read and checked successfully in its history.
latestObservedAtstringDate and time this summary was most recently read and checked successfully.
usernamestringPublic username of the learner.
leagueTierstringCurrent league tier reported by Duolingo.
highestLeaguestringHighest league tier the learner has reached.
winsintegerLeague wins reported by Duolingo.
podiumFinishesintegerPodium finishes reported by Duolingo.
firstPlaceFinishesintegerFirst-place finishes reported by Duolingo.
secondPlaceFinishesintegerSecond-place finishes reported by Duolingo.
weeksInTierintegerWeeks spent in the current tier.
lastWinDatestringDate 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

FieldTypeWhat it does
resultTypestringAlways vocabulary for this row type.
changeTypestringHow this read compares with saved history: new, updated, reappeared (seen again after it was counted as missing), or unchanged.
firstObservedAtstringDate and time this entry was first read and checked successfully in its history.
latestObservedAtstringDate and time this entry was most recently read and checked successfully.
sourceLanguagestringCode for the language used to teach the entry, such as en.
learningLanguagestringCode for the language being learned, such as es.
textstringWord or phrase in the language being learned.
translationsarray of stringsTranslations into the teaching language.
skillstringSkill name attached to the word or phrase.
unitstringUnit name attached to the word or phrase.
pathPositionobjectPosition of the entry in the learning path, as reported by the source.
pathPosition.unitIndexintegerIndex of the unit in the learning path.
audioUrlsarray of stringsDirect 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 🫡

Made with ❤️ by Maxime Dupré