@flexhd/primeleague-api (0.7.0)

Published 2026-07-14 15:00:05 +00:00 by Flexhd

Installation

@flexhd:registry=
npm install @flexhd/primeleague-api@0.7.0
"@flexhd/primeleague-api": "0.7.0"

About this package

Prime League community API

An experimental, read-only JSON wrapper for public data on primeleague.gg. It discovers seasons, divisions/groups, teams, standings, matches, brackets, rosters, player histories, circuit points, Division 1 coverage, and public match lineups.

This is not an official Prime League API. Prime League currently exposes server-rendered pages plus undocumented /ajax/* routes. Those routes can change without notice, and several JSON responses contain HTML fragments. The site also uses a Bunny Shield browser challenge, so this project uses Playwright's bundled headless Chromium instead of plain fetch/curl. Google Chrome is not required.

Quick start

Requirement: Node.js 22.5 or newer. npm install downloads a compatible Chromium build automatically.

npm install
cp .env.example .env
npm start

The default base URL is http://127.0.0.1:3000. Runtime data is stored in data/primeleague.sqlite and the persistent browser profile stays in data/browser-profile.

Linux hosts may need Chromium's system libraries once:

npx playwright install-deps chromium

The Docker image below already contains these libraries. To override bundled Chromium, set PRIMELEAGUE_BROWSER_EXECUTABLE_PATH.

Install as a module

Install the project folder, a packed .tgz file, or the Forgejo package:

npm config set @flexhd:registry https://forgejo.createaloft.net/api/packages/Flexhd/npm/
npm install @flexhd/primeleague-api
npx primeleague-api

Embed it in an existing Node application:

import { createPrimeLeagueApi } from "@flexhd/primeleague-api";

const api = await createPrimeLeagueApi({
  databasePath: "./data/primeleague.sqlite",
  profileDir: "./data/browser-profile",
});

await api.listen({ host: "0.0.0.0", port: 3000 });

Call await api.close() during application shutdown. This closes Chromium and SQLite cleanly. The package also exports the parsers, loadConfig, AppConfig, and SqliteStore.

Docker

The included multi-stage image bundles Node, Chromium, and its Linux dependencies:

docker build -t primeleague-api .
docker run --rm -p 3000:3000 -v primeleague-data:/app/data primeleague-api

Persist /app/data so the SQLite database, response history, cache, and browser profile survive container replacement.

Forgejo package publishing

The .forgejo/workflows/publish.yml action publishes tags to the Flexhd npm registry. In the repository's Actions secrets, create PACKAGE_TOKEN containing an owner personal access token with package-write permission. Then publish a matching version tag:

git tag v0.7.0
git push origin v0.7.0

The action refuses to publish when the tag and package.json version differ. For local publishing, copy .npmrc.example to .npmrc, provide FORGEJO_TOKEN, and run npm publish; .npmrc is ignored by Git.

Endpoints

Seasons

GET /v1/seasons?page=1&mode=completed&league=prm

Uses the upstream GET /ajax/list_load route. It returns season IDs, slugs, names, start/end Unix timestamps, source URLs, and pagination.

Season structure: divisions/groups and brackets

GET /v1/seasons/3220/spring-split-202526/structure

The response includes stages, every group with its division number, per-division group counts, and playoff bracket links. For season 3220, the inspected data contained 139 numbered groups across Divisions 2–8, three additional calibration/relegation/starter groups, and five playoff/decider brackets.

Division discovery

GET /v1/seasons/3220/spring-split-202526/divisions
GET /v1/seasons/3220/spring-split-202526/divisions/5

The collection route returns every numbered regular-season division, its groups, group count, detail and schedule URLs, plus unnumbered groups and playoff links. The division-specific route returns only the groups belonging to one division. At inspection time, Division 5 contained 31 groups, from Group 5.1 through Group 5.31.

Season 3220 was live-tested across every community division: Division 2 has 2 groups, Division 3 has 4, Division 4 has 12, Division 5 has 31, Division 6 has 40, Division 7 has 37, and Division 8 has 13. A representative group in every division returned both standings and matches. Division 1 remains available through the separate coverage endpoint.

GET /v1/seasons/3220/spring-split-202526/divisions/7/teams?search=serpents
GET /v1/seasons/3220/spring-split-202526/divisions/7/teams?page=1&size=5

The search form is optimized for organizations with several league teams: it searches the season participants, enriches each candidate with its roster, then keeps only teams whose group belongs to the requested division. Every result includes its exact group and a ready-to-use group endpoint. With no search term, the endpoint pages through the division's groups and returns every team plus its standing and group membership.

Division schedule

GET /v1/seasons/3220/spring-split-202526/divisions/5/schedule?page=1&size=5&state=all&times=upcoming

Fetches and combines the schedules for a page of groups. Each match includes its group, playday, teams, score, IDs, logos, and source URL. The group pages do not contain exact dates, so the default times=upcoming enriches unfinished matches from the match-detail endpoint with their Unix start time and status. Use times=all to enrich historical matches too, or times=none for the lightest request. state accepts all, upcoming, or finished; size is capped at 10 groups to keep upstream traffic controlled. Follow pagination.pages to ingest all 31 Division 5 groups.

Broadcast-normalized output

GET /v1/broadcast/seasons/3220/spring-split-202526/divisions/5/schedule?page=1&size=5&state=upcoming&times=upcoming
GET /v1/broadcast/seasons/3220/spring-split-202526/brackets/512/playoffs/1502/playoffs-2-liga

These endpoints provide a stable schemaVersion, ISO and Unix timestamps, explicit home/away teams, score objects, match state, winner side/team ID, round grouping, source links, and pagination. The raw endpoints remain unchanged for backward compatibility. Bracket progression edges are explicitly marked unavailable instead of being guessed.

Season participants/signups

GET /v1/seasons/3220/spring-split-202526/participants?page=1&size=25&search=serpents

Returns teams, IDs, country codes, logos, signup/completion timestamps, and statuses such as Participating, Disqualified, or Not enough players. The optional search query is forwarded to Prime League's participant search.

Group/division detail

Use the IDs and slugs returned by the structure endpoint:

GET /v1/seasons/3220/spring-split-202526/groups/509/group-stage/5498/group-2-1?times=all

Returns standings and all visible group matches, including match IDs, team IDs, abbreviations, logos, rounds, and scores. Add times=upcoming to resolve dates for unfinished matches, or times=all to resolve every public match date/status.

Bracket

GET /v1/seasons/3220/spring-split-202526/brackets/512/playoffs/1502/playoffs-2-liga?times=all

Returns the bracket's complete public match list. Add times=all to resolve every public match date/status. The upstream visual bracket does not expose stable graph edges in its HTML, so the API returns the full match set without inventing winner/loser relationships.

Team and roster

GET /v1/seasons/3220/spring-split-202526/teams/211352/cgn-esports

Returns the team identity, logo, country, creation timestamp, current group/result, remaining roster additions, OP.GG multi-search link, group memberships, and season matches. Roster members include their role, eligibility/status, public Riot ID, and OP.GG link. Match entries now include their scheduled Unix timestamp when the page exposes it.

Player profile and season history

GET /v1/seasons/3220/spring-split-202526/players/380873/agurin

Returns the public player identity, current team, country, role/status when available, Riot accounts, played-match history, and the visible most-played-champion summaries (games, record, and KDA).

Circuit / split points

GET /v1/circuits/460/standings

Returns all ranked teams in the circuit, their per-season point breakdown, total points, logos, country codes, and source links. Circuit 460 is the inspected PRM Liga 2 split-points circuit for 2025/26.

Division 1 coverage

GET /v1/coverages/33286

Division 1 is published through Prime League's separate coverage system rather than the community-league season/group pages. This endpoint returns the coverage title and format description, prize-money distribution, season-point awards, current standings, and the visible playday schedule/results. Coverage 33286 is the inspected 1. Liga Summer Split 2026 page.

Match and submitted lineups

GET /v1/matches/1163509

Combines the public match page with GET /ajax/leagues_match?action=init. It returns status, timestamp, score, teams, best-of format when available, submitted players, readiness/stand-in flags, public Riot IDs, OP.GG links, and multi-search URLs. It also exposes the public scheduling reply window, lineup mode/deadline, ready-up state, hosting platform/status/game, reporting start, workflow steps, and visible match sections.

Operational guidance

  • The SQLite upstream cache has a default TTL of five minutes and survives process restarts.
  • Expired cache records are used as an offline fallback when Prime League is temporarily unreachable. Set PRIMELEAGUE_ALLOW_STALE_CACHE=false to disable this.
  • Keep upstream concurrency at one and do not lower the default 1.2-second request interval without permission from the site owner.
  • Do not mirror private/logged-in fields, comments, admin logs, or write actions.
  • Store stable numeric IDs as primary keys; names and slugs change.
  • Treat upstream HTML and JSON as untrusted input.
  • Pin parser tests to captured, non-sensitive fixtures before production deployment.
  • Contact Prime League/onethreefive gaming for official API access or written scraping permission before operating this at scale.

SQLite persistence

No external database server is required. Node's built-in SQLite driver stores:

  • upstream_cache: persistent read-through cache for upstream HTML and JSON;
  • resource_snapshots: the latest normalized JSON for every successful API request path;
  • resource_history: deduplicated historical versions, added only when the response content changes.

Storage inspection endpoints:

GET /v1/storage/stats
GET /v1/storage/snapshots
GET /v1/storage/snapshots?path=/v1/seasons/3220/spring-split-202526/divisions/5/schedule?page=1%26size=5%26state=all&history=5

Override the database location with PRIMELEAGUE_DATABASE_PATH. Back up the SQLite file together with its -wal file while the API is running, or stop the API before copying just the main database file.

Known limitations

  • Node currently labels its built-in node:sqlite module experimental, so it prints an ExperimentalWarning at startup even though the tested API is stable enough for this local service.
  • No official API contract or published rate limit was found.
  • Plain HTTP clients currently receive a CDN 403 challenge (errorcode 112).
  • /ajax/list_load and some other routes return JSON envelopes containing HTML.
  • Historical seasons can use different stage IDs and layouts. Always discover structure from the season page.
  • The current bracket parser returns the ordered public match list, not explicit dependency edges.
  • Champion detail rows and draft/player performance data are loaded by additional undocumented POST widgets; this version returns the stable summaries visible in the initial page only.
  • Coverage IDs are not the same as community season IDs and must currently be discovered from Prime League's coverage navigation.
  • Public team-finder listings exist, but are intentionally excluded because they aggregate player availability and profile details that are unnecessary for league/bracket ingestion.
  • Language selection is controlled by PRIMELEAGUE_LANGUAGE=en|de; some upstream AJAX links may still use the browser session's language.

Development

npm test
npm run build
npm run dev

Dependencies

Dependencies

ID Version
cheerio ^1.1.2
fastify ^5.6.2
playwright 1.61.1

Development dependencies

ID Version
@types/node ^24.5.2
tsx ^4.20.5
typescript ^5.9.2
Details
npm
2026-07-14 15:00:05 +00:00
0
UNLICENSED
latest
34 KiB
Assets (1)
Versions (1) View all
0.7.0 2026-07-14