Thanks for reading! I like making interactive visualisations for my programming blog. Sometimes I do projects too. Oh, and before you go, sign the guestbook! See you around! —Lean
How to fetch your Duolingo streak using an unconfirmed API on duolingo.com:
function getDuolingoStreak(username) {
const res = await fetch(
`https://www.duolingo.com/2017-06-30/users?username=${username}&fields=streak,streakData%7BcurrentStreak,previousStreak%7D%7D`
);
const data = await res.json();
const userData = data.users[0];
// I didn't know which of these fields matter, so I just get the max of them.
const streak = Math.max(
userData?.streak ?? 0,
userData?.streakData?.currentStreak?.length ?? 0,
userData?.streakData?.previousStreak?.length ?? 0
);
return streak;
}
I can then render this data into a card like that. I put one of these cards in the /misc/ section.
Let’s look at the API itself. www.duolingo.com/2017-06-30
seems to be the API prefix, which is a bit weird. What is 2017-06-30
? What happened on that date? Maybe the Duolingo team used a date-based versioning at the time?
In any case, big thanks to the Duolingo team for keeping this apparently-6-year-old public API alive and accessible.
The query parameters for the /users
endpoint are interesting. It’s similar to GraphQL where you can specify exactly which fields you want in the response. You can even specify specific sub-fields within objects, using some kind of a DSL in the fields
parameter.
The fields
parameter in the above query, when decoded, is fields=streak,streakDate{currentStreak,previousStreak}}
. Fields are comma-delimited and objects are enclosed in braces. This could actually be GraphQL! There is an extra closing brace at the end which seems necessary for the request to be successful.
Thanks for reading! I like making interactive visualisations for my programming blog. Sometimes I do projects too. Oh, and before you go, sign the guestbook! See you around! —Lean