{
  "openapi": "3.0.1",
  "info": {
    "title": "Duolingo Scraper - Profiles, Leaderboards, Courses & Vocabulary",
    "description": "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.",
    "version": "0.1",
    "x-build-id": "KacK8XRJsmRrCzVWV"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/abotapi~duolingo-learner-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-abotapi-duolingo-learner-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/acts/abotapi~duolingo-learner-scraper/runs": {
      "post": {
        "operationId": "runs-sync-abotapi-duolingo-learner-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor and returns information about the initiated run in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/runsResponseSchema"
                }
              }
            }
          }
        }
      }
    },
    "/acts/abotapi~duolingo-learner-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-abotapi-duolingo-learner-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "inputSchema": {
        "type": "object",
        "required": [
          "mode"
        ],
        "properties": {
          "mode": {
            "title": "Mode",
            "enum": [
              "search",
              "url",
              "courses",
              "vocabulary"
            ],
            "type": "string",
            "description": "How to find data: pick a search type below, paste profile links, list the whole course catalog, or read a course's vocabulary.",
            "default": "search"
          },
          "searchType": {
            "title": "Search type",
            "enum": [
              "profiles",
              "leaderboard"
            ],
            "type": "string",
            "description": "What Search mode reads (Search mode only). Both types work with no account.",
            "default": "profiles"
          },
          "usernames": {
            "title": "Usernames",
            "type": "array",
            "description": "Duolingo usernames to read, one record each (Profiles and League search types). A username that matches nobody is reported, not failed. Public profile data only: whatever the profile owner's privacy settings expose.",
            "items": {
              "type": "string"
            }
          },
          "urls": {
            "title": "URLs",
            "type": "array",
            "description": "Profile page links (URL mode), like https://www.duolingo.com/profile/duolingo. Each link returns one learner record.",
            "items": {
              "type": "string"
            }
          },
          "courseQuery": {
            "title": "Course keyword",
            "type": "string",
            "description": "Only keep courses whose language names or codes contain this keyword, like spanish or ja (Course-catalog mode only; applied to results)."
          },
          "courseLearningLanguage": {
            "title": "Course language being learned",
            "type": "string",
            "description": "Course pair selector (Course-catalog and Vocabulary modes): the learning language code, like es or ja."
          },
          "courseFromLanguage": {
            "title": "Course source language",
            "type": "string",
            "description": "Course pair selector (Course-catalog and Vocabulary modes): the source language code the course is taught from, like en."
          },
          "courseMinLearners": {
            "title": "Minimum learners",
            "minimum": 0,
            "type": "integer",
            "description": "Only keep courses with at least this many learners (0 = no floor; Course-catalog mode only; applied to results).",
            "default": 0
          },
          "courseSort": {
            "title": "Course sort",
            "enum": [
              "learners",
              "name"
            ],
            "type": "string",
            "description": "Order of the course rows (Course-catalog mode only): learners = most learners first, name = course language name A to Z.",
            "default": "learners"
          },
          "vocabSkill": {
            "title": "Vocabulary skill filter",
            "type": "string",
            "description": "Only read lessons whose skill label contains this keyword, like cafe (Vocabulary mode only; applied per lesson)."
          },
          "learningLanguage": {
            "title": "Language being learned",
            "enum": [
              "",
              "ar",
              "ca",
              "cs",
              "cy",
              "da",
              "de",
              "dn",
              "el",
              "en",
              "eo",
              "es",
              "fi",
              "fr",
              "ga",
              "gd",
              "gn",
              "he",
              "hi",
              "ht",
              "hu",
              "hv",
              "hw",
              "id",
              "it",
              "ja",
              "kl",
              "ko",
              "la",
              "nb",
              "nv",
              "pl",
              "pt",
              "ro",
              "ru",
              "sv",
              "sw",
              "tr",
              "uk",
              "vi",
              "yi",
              "zc",
              "zs",
              "zu",
              "zw"
            ],
            "type": "string",
            "description": "Only return profiles learning this language, as a course code like es, fr, de, it, ja (empty = all). The list is the source's own live course catalog codes. Applies to returned profiles in Profiles search type and URL mode; the filter is applied to results, not server-side.",
            "default": ""
          },
          "hasPlusOnly": {
            "title": "Super subscribers only",
            "type": "boolean",
            "description": "Only return profiles with a paid Super subscription. Applied to results in Profiles search type and URL mode.",
            "default": false
          },
          "minTotalXp": {
            "title": "Minimum total XP",
            "minimum": 0,
            "type": "integer",
            "description": "Only return profiles with at least this much total XP (0 = no floor). Applied to results in Profiles search type and URL mode.",
            "default": 0
          },
          "minStreak": {
            "title": "Minimum streak",
            "minimum": 0,
            "type": "integer",
            "description": "Only return profiles with an active streak of at least this many days (0 = no floor). Applied to results in Profiles search type and URL mode.",
            "default": 0
          },
          "fetchAchievements": {
            "title": "Achievements detail",
            "type": "boolean",
            "description": "On by default. Adds each profile's full achievements detail (badge name, tier, count) from the achievements service: one extra read per profile, with per-profile progress in the log. Applies to Profiles search type and URL mode.",
            "default": true
          },
          "maxItems": {
            "title": "Max items",
            "minimum": 0,
            "type": "integer",
            "description": "Stop after this many records in total. Set 0 for no limit. This is the only limit that stops a run early by default.",
            "default": 20
          },
          "resumeFromRunId": {
            "title": "Resume from a previous run",
            "type": "string",
            "description": "Paste a previous run ID or dataset ID to continue a large pull without returning records already collected there."
          },
          "incrementalMode": {
            "title": "Incremental changes for scheduled runs",
            "type": "boolean",
            "description": "Turn this on for daily or recurring monitoring. The first run returns every matching record as NEW. Later runs normally return only NEW, UPDATED and REAPPEARED records. Turn on Emit unchanged or Emit expired only when you also want those rows returned (and billed). State is kept separately for each search, filter and URL setup; use State key to name or deliberately share a monitoring campaign. Live activity flags are excluded from change detection: the source recomputes them constantly, so an activity flip alone never marks a record UPDATED.",
            "default": false
          },
          "stateKey": {
            "title": "State key (optional, incremental mode only)",
            "type": "string",
            "description": "Optional. Name this monitoring campaign to keep its state stable, or deliberately share state across differently configured runs. Leave empty to let the actor derive a key automatically from the search and filter settings."
          },
          "emitUnchanged": {
            "title": "Emit unchanged records (incremental mode only)",
            "type": "boolean",
            "description": "Off by default. Turn on to also return records that have not changed since the last run, marked UNCHANGED. This returns, and bills, extra rows you already have.",
            "default": false
          },
          "emitExpired": {
            "title": "Emit expired records (incremental mode only)",
            "type": "boolean",
            "description": "Off by default. Turn on to also return records that were present in a previous run but are no longer found, marked EXPIRED. Only produced once a run has fully scanned the tracked scope; a run that could not read every requested item skips EXPIRED detection rather than guessing.",
            "default": false
          },
          "mcpConnectors": {
            "title": "Pipe results into your apps (optional)",
            "type": "array",
            "description": "Optionally send results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize one under Apify, Settings, API & Integrations, then select it here. Notion gets a rich page-per-item export; other connectors get a best-effort write or digest. Leave empty to skip; never changes the dataset output."
          },
          "notionParentPageUrl": {
            "title": "Notion parent page (Notion connector only)",
            "type": "string",
            "description": "URL or id of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors."
          },
          "maxNotifyListings": {
            "title": "Max items to export per connector",
            "minimum": 1,
            "maximum": 1000,
            "type": "integer",
            "description": "Cap on items written to each connector per run. Does not affect the dataset.",
            "default": 50
          },
          "proxyConfiguration": {
            "title": "Proxy configuration",
            "type": "object",
            "description": "Apify Proxy settings. The prefilled default uses the standard shared pool and works on every proxy plan. If your plan includes residential or other dedicated groups, name them here."
          }
        }
      },
      "runsResponseSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "actId": {
                "type": "string"
              },
              "userId": {
                "type": "string"
              },
              "startedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "finishedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "status": {
                "type": "string",
                "example": "READY"
              },
              "meta": {
                "type": "object",
                "properties": {
                  "origin": {
                    "type": "string",
                    "example": "API"
                  },
                  "userAgent": {
                    "type": "string"
                  }
                }
              },
              "stats": {
                "type": "object",
                "properties": {
                  "inputBodyLen": {
                    "type": "integer",
                    "example": 2000
                  },
                  "rebootCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "restartCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "resurrectCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "computeUnits": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "options": {
                "type": "object",
                "properties": {
                  "build": {
                    "type": "string",
                    "example": "latest"
                  },
                  "timeoutSecs": {
                    "type": "integer",
                    "example": 300
                  },
                  "memoryMbytes": {
                    "type": "integer",
                    "example": 1024
                  },
                  "diskMbytes": {
                    "type": "integer",
                    "example": 2048
                  }
                }
              },
              "buildId": {
                "type": "string"
              },
              "defaultKeyValueStoreId": {
                "type": "string"
              },
              "defaultDatasetId": {
                "type": "string"
              },
              "defaultRequestQueueId": {
                "type": "string"
              },
              "buildNumber": {
                "type": "string",
                "example": "1.0.0"
              },
              "containerUrl": {
                "type": "string"
              },
              "usage": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "integer",
                    "example": 1
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "usageTotalUsd": {
                "type": "number",
                "example": 0.00005
              },
              "usageUsd": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "number",
                    "example": 0.00005
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}