getDuolingoStreak()

· 2 min read

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;
}
365
This card is live ;)
That’s my current max 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.