LangPop API v1

Free. Public. JSON.

Five read endpoints for programming language rankings, history, and our scoring methodology. No auth, open CORS, updated weekly.

Quickstart

Fetch the latest top 5 languages:

$ curl https://langpop.com/api/v1/rankings?limit=5

Returns JSON. Pipe it through jq to slice it: curl … | jq '.data[].language'.

Conventions

  • Base URL: https://langpop.com
  • Versioning: All endpoints live under /api/v1/. Breaking changes ship as /api/v2/; both run in parallel for at least 6 months before sunset.
  • Auth: None. The public surface is free, no API key required.
  • CORS: Access-Control-Allow-Origin: * on every endpoint — fetch directly from browser JavaScript.
  • Caching: Cache-Control: public, max-age=3600, s-maxage=3600. Data refreshes weekly so 1h CDN cache is generous.
  • Version header: Every v1 response carries X-LangPop-Version: v1 so you can detect contract drift.
  • Rate limits: Not enforced today. We're sizing this against real traffic; expect ~60 req/min/IP with X-RateLimit-* headers when limits go live. Be reasonable.
  • Attribution: Free to use with attribution to langpop.com. The license string is in every meta block.

Response envelope

Every successful response follows this shape:

{
  "meta": {
    "source": "LangPop",
    "url": "https://langpop.com",
    "version": "v1",
    "generated_at": "2026-05-24T08:00:00.000Z",
    "license": "Free to use with attribution to langpop.com"
  },
  "data": /* endpoint-specific payload */
}

Endpoints that return a snapshot for a specific week also include meta.week_start (ISO date, always a Monday).

Errors

Errors return a single error object — never a stack trace, never an internal Supabase message.

{
  "error": {
    "code": "invalid_param",
    "message": "limit must be between 1 and 50"
  }
}
HTTPerror.codeWhen
400invalid_paramQuery param failed validation.
404not_foundSlug or week doesn't exist in the dataset.
429rate_limitedRate limit exceeded (when limits ship — see Conventions).
500internal_errorSomething on our side. Please report repeated 500s.
503unavailableDownstream (database) is unreachable.

Endpoints

GET/api/v1/rankings

The latest weekly ranking snapshot. The workhorse endpoint.

Parameters

NameTypeDefaultNotes
weekISO date (YYYY-MM-DD)latestMust be a Monday matching a week in our dataset. 404 if no rows.
limitinteger 1–5020We currently track 20 languages, so 20 is the natural cap.
sourceenumgithub | jobs | stackoverflow | trends | packages | reddit | tutorials. If set, the array is re-sorted by that source's score (composite rank field is unchanged).

Example

$ curl https://langpop.com/api/v1/rankings?limit=3

Sample response

{
  "meta": {
    "source": "LangPop",
    "url": "https://langpop.com",
    "version": "v1",
    "generated_at": "2026-05-24T08:00:00.000Z",
    "license": "Free to use with attribution to langpop.com",
    "week_start": "2026-05-19"
  },
  "data": [
    {
      "rank": 1,
      "language": "Python",
      "slug": "python",
      "composite_score": 48.64,
      "github_score": 100.0,
      "jobs_score": 92.4,
      "stackoverflow_score": 88.1,
      "trends_score": 95.2,
      "packages_score": 84.7,
      "reddit_score": 0,
      "tutorials_score": 76.5,
      "previous_rank": 1,
      "week_start": "2026-05-19"
    },
    {
      "rank": 2,
      "language": "JavaScript",
      "slug": "javascript",
      "composite_score": 39.70,
      "github_score": 91.3,
      "jobs_score": 88.0,
      "stackoverflow_score": 81.2,
      "trends_score": 78.9,
      "packages_score": 96.1,
      "reddit_score": 0,
      "tutorials_score": 72.4,
      "previous_rank": 2,
      "week_start": "2026-05-19"
    },
    {
      "rank": 3,
      "language": "TypeScript",
      "slug": "typescript",
      "composite_score": 33.21,
      "github_score": 85.4,
      "jobs_score": 79.7,
      "stackoverflow_score": 60.1,
      "trends_score": 64.2,
      "packages_score": 71.8,
      "reddit_score": 0,
      "tutorials_score": 55.0,
      "previous_rank": 4,
      "week_start": "2026-05-19"
    }
  ]
}

previous_rank is null when this is the first week the language appeared in the dataset.

reddit_score: 0 in the sample above is real: the Reddit collector is awaiting API credentials, so all 20 languages currently get 0 for that source. The composite weighting effectively drops Reddit until the collector backfills.

GET/api/v1/language/:slug

A single language: metadata, current rank with all seven source scores, optional history.

Parameters

NameTypeDefaultNotes
slug*path, lowercasee.g. python, javascript, rust. Must match languages.slug. 404 if not tracked.
historyinteger 0–5212Number of historical weeks to include (oldest -> newest). 0 omits history.

Example

$ curl https://langpop.com/api/v1/language/python?history=3

Sample response

{
  "meta": {
    "source": "LangPop",
    "url": "https://langpop.com",
    "version": "v1",
    "generated_at": "2026-05-24T08:00:00.000Z",
    "license": "Free to use with attribution to langpop.com",
    "week_start": "2026-05-19"
  },
  "data": {
    "slug": "python",
    "name": "Python",
    "description": "High-level, general-purpose, dynamically typed.",
    "paradigms": ["multi-paradigm", "object-oriented", "functional"],
    "created_year": 1991,
    "creator": "Guido van Rossum",
    "website": "https://www.python.org",
    "current": {
      "rank": 1,
      "language": "Python",
      "slug": "python",
      "composite_score": 48.64,
      "github_score": 100.0,
      "jobs_score": 92.4,
      "stackoverflow_score": 88.1,
      "trends_score": 95.2,
      "packages_score": 84.7,
      "reddit_score": 0,
      "tutorials_score": 76.5,
      "previous_rank": 1,
      "week_start": "2026-05-19"
    },
    "history": [
      { "week_start": "2026-05-05", "rank": 1, "composite_score": 47.82 },
      { "week_start": "2026-05-12", "rank": 1, "composite_score": 48.10 },
      { "week_start": "2026-05-19", "rank": 1, "composite_score": 48.64 }
    ]
  }
}
GET/api/v1/languages

Every language we track, with current rank. Useful for building dropdowns and filters without fetching the full ranking payload.

Parameters

No parameters.

Example

$ curl https://langpop.com/api/v1/languages

Sample response

{
  "meta": {
    "source": "LangPop",
    "url": "https://langpop.com",
    "version": "v1",
    "generated_at": "2026-05-24T08:00:00.000Z",
    "license": "Free to use with attribution to langpop.com"
  },
  "data": [
    {
      "slug": "python",
      "name": "Python",
      "current_rank": 1,
      "created_year": 1991,
      "creator": "Guido van Rossum",
      "paradigms": ["multi-paradigm", "object-oriented", "functional"]
    },
    {
      "slug": "javascript",
      "name": "JavaScript",
      "current_rank": 2,
      "created_year": 1995,
      "creator": "Brendan Eich",
      "paradigms": ["multi-paradigm", "event-driven", "functional"]
    }
    /* … */
  ]
}
GET/api/v1/weeks

Every week for which we have ranking data, newest first. Use this to build a historical picker.

Parameters

No parameters.

Example

$ curl https://langpop.com/api/v1/weeks

Sample response

{
  "meta": {
    "source": "LangPop",
    "url": "https://langpop.com",
    "version": "v1",
    "generated_at": "2026-05-24T08:00:00.000Z",
    "license": "Free to use with attribution to langpop.com"
  },
  "data": [
    "2026-05-19",
    "2026-05-12",
    "2026-05-05",
    "2026-04-28"
    /* … */
  ]
}
GET/api/v1/methodology

Programmatic methodology — source list, weights, and the composite formula. Lets a determined consumer reproduce our number from raw inputs.

Parameters

No parameters.

Example

$ curl https://langpop.com/api/v1/methodology

Sample response

{
  "meta": {
    "source": "LangPop",
    "url": "https://langpop.com",
    "version": "v1",
    "generated_at": "2026-05-24T08:00:00.000Z",
    "license": "Free to use with attribution to langpop.com"
  },
  "data": {
    "sources": [
      { "code": "github",        "name": "GitHub",         "weight": 0.25, "frequency": "daily",  "description": "Active repos, stars, forks, commits." },
      { "code": "jobs",          "name": "Job Postings",   "weight": 0.20, "frequency": "weekly", "description": "Aggregated job listings." },
      { "code": "stackoverflow", "name": "Stack Overflow", "weight": 0.15, "frequency": "weekly", "description": "Questions, answers, tag activity." },
      { "code": "trends",        "name": "Google Trends",  "weight": 0.15, "frequency": "weekly", "description": "Search interest, normalized." },
      { "code": "packages",      "name": "Package Mgrs",   "weight": 0.10, "frequency": "weekly", "description": "npm / PyPI / crates.io downloads." },
      { "code": "reddit",        "name": "Reddit",         "weight": 0.10, "frequency": "weekly", "description": "Subreddit activity." },
      { "code": "tutorials",     "name": "Tutorials",      "weight": 0.05, "frequency": "weekly", "description": "Course enrollment data." }
    ],
    "formula": "weighted_sum / total_weight"
  }
}

Full prose methodology with caveats and known limitations lives on /methodology. The endpoint is the machine-readable version of that page.

Stability + license

v1 is a frozen contract. Adding new optional fields to a response is fine; removing or renaming anything is a breaking change and ships as /api/v2/.

License: free to use with attribution. If you publish a chart, table, or article using LangPop data, credit langpop.com and link back. Suggested phrasing lives on /press.

Bugs: Email hello@langpop.com with the request URL and what you expected. We're a small team — replies in days, not minutes.

Changelog

v1.0 — Launch

2026-05-24

Current
  • Five read endpoints: /rankings, /language/:slug, /languages, /weeks, /methodology.
  • Open CORS, no auth, 1h cache headers.
  • Response envelope: { meta, data }. Errors: { error: { code, message } }.