Skip to content
Site updates

GGScore API: Played and Upcoming CS2 Matches Without Scraping

6/9/2026, 1:31:14 PM

Trackers, bots, and widgets need two feeds: match results (who won, maps, scores) and fixtures (what plays next). Scraping usually means two brittle HTML parsers. GGScore is a paid CS2 match data API — both played and upcoming matches over REST, one auth model, JSON you can map to UI.

You need two kinds of match data for a tracker, bot, or dashboard: what already happened (scores, maps, winners) and what is scheduled next (fixtures, events, start times). Scraping two different pages doubles your breakage surface. GGScore is a paid CS2 match data API that returns both played and upcoming matches as JSON over REST — authenticate, fetch, ship.

This guide covers what the API is for, how auth and plans work, and minimal integration patterns for each match type. Verify paths, field names, and quotas on ggscore.net docs before production.


What GGScore Is (and Is Not)

GGScore APIScraping scoreboard sites
DataNormalized JSON: teams, scores, events, countriesHTML + fragile selectors
Match typesPlayed results + upcoming fixturesOften separate pages / formats
AuthX-API-Key headerCookies, captchas, geo blocks
CostPaid tiers (Free to prototype)Your time every layout change
MaintenanceSchema + docsDOM archaeology

GGScore is not a free public dump. It is a developer product: you pay for reliable structure and rate limits you can design against.

Public surface (per docs): countries, played matches, upcoming matches, plans, contact. Interactive reference on the docs page.


Who This Is For

  • Match trackers — recent results + "what's next today"
  • Discord / Telegram bots — /results and /schedule without two scrapers
  • Widgets and landing pages — embed upcoming fixtures for a team or event
  • Analytics side projects — stable IDs across played history

If you only need one Discord command for last results, see the dedicated Discord bot guide — this article is the broader played + upcoming picture.


Authentication

Every request sends your key in the header:

curl -s -H "X-API-Key: YOUR_API_KEY" \
  "https://api.ggscore.net/v1/played-matches?limit=5"

Get keys from the site login / cabinet. Rotate keys if leaked; treat them like SMTP passwords.

Common responses:

  • 401 — missing or invalid key
  • 429 — over quota; back off, cache, upgrade tier
  • 200 — JSON body; shape per docs

Played Matches: Results You Can Show

Use when: final scores, map counts, winner/loser, event name, played-at timestamp.

Typical flow:

  1. GET played matches (filters per docs: limit, team, event, date range).
  2. Map each row to UI: team names, score string (2:1), event, online/offline flag.
  3. Cache 30–120 seconds on hot paths; played data changes slowly after match end.
curl -s -H "X-API-Key: YOUR_API_KEY" \
  "https://api.ggscore.net/v1/played-matches?limit=10"
const BASE = 'https://api.ggscore.net/v1'; // verify in docs

async function fetchPlayed(limit = 10) {
  const res = await fetch(`${BASE}/played-matches?limit=${limit}`, {
    headers: { 'X-API-Key': process.env.GGSCORE_API_KEY },
  });
  if (res.status === 429) throw new Error('Rate limited');
  if (!res.ok) throw new Error(`API ${res.status}`);
  return res.json();
}

Field names (winner, score, played_at, etc.) — copy from live docs, not from this snippet.


Upcoming Matches: Fixtures Before They Start

Use when: schedule views, reminders, "matches today", tournament calendars.

Typical flow:

  1. GET upcoming matches (filters per docs).
  2. Show start time, teams, event, location/online.
  3. Cache 5–15 minutes for schedule UIs; refresh more often only on live tournament days if your plan allows.
curl -s -H "X-API-Key: YOUR_API_KEY" \
  "https://api.ggscore.net/v1/upcoming-matches?limit=10"
import os
import requests

BASE = "https://api.ggscore.net/v1"  # verify in docs

def fetch_upcoming(limit=10):
    r = requests.get(
        f"{BASE}/upcoming-matches",
        params={"limit": limit},
        headers={"X-API-Key": os.environ["GGSCORE_API_KEY"]},
        timeout=15,
    )
    r.raise_for_status()
    return r.json()

Design tip: one screen that tabs Results (played) and Schedule (upcoming) should use two endpoints, not one mega-poll — easier caching and clearer 429 budgeting.


Plans: Free to Prototype, Paid for Production

Copy numbers from the live pricing page when you ship. As of the public site structure:

TierOrient. quotaTypical use
FreeLow daily requests (e.g. 3/day)Key test, local dev, one cron
PremiumHigher daily cap (e.g. 100/day)Small bot or widget with cache
BlackUnlimited-scale positioningProduction traffic, priority support

Free is not a production plan. It is enough to validate JSON shape and your mapping code. When real users poll played + upcoming on a schedule, budget requests:

  • played refresh: every 1–2 min on live day (if tier allows)
  • upcoming refresh: every 10–30 min
  • never call the API on every page view without server-side cache

Caching and Rate Limits (Non-Negotiable)

  1. Server-side cache — Redis, in-memory, or CDN edge; clients hit your backend, not GGScore on every click.
  2. Single-flight — dedupe concurrent identical requests during cache miss.
  3. 429 handling — exponential backoff; surface "try again" in bots, not silent failure.
  4. ETag / If-None-Match — only if docs support it; otherwise TTL cache.

With 3 requests/day on Free, you cannot run a public tracker. That is expected — upgrade when you measure need.


Combining Played + Upcoming in One App

Minimal architecture:

[Your app]
   ├─ cache:played  ← GET played-matches  (TTL 60–120s)
   └─ cache:upcoming ← GET upcoming-matches (TTL 300–900s)
  • Landing page: upcoming today + last 5 played — 2 API calls per cache window, not per visitor.
  • Bot: subcommands map 1:1 to endpoints; hash last payload to skip useless Discord edits.
  • Cron: nightly job refreshes upcoming for the week; played refreshed after known match end windows.

Countries endpoint (per docs) helps filters and flags without scraping Wikipedia.


When Scraping Still Tempts You

Niche stats (player ratings, HLTV-only columns) may sit outside the API. Keep scrapers optional and off the critical path — core loop stays on GGScore for played/upcoming integrity.


Checklist Before Go-Live

  • Paths and query params match current docs
  • API key in env, not in client-side JS
  • Cache layer with TTLs per endpoint
  • 429 and 401 logged with alert
  • Tier matches measured daily request count (played + upcoming + retries)
  • UI labels: data via API, not affiliated with Valve / tournament organizers unless licensed

CTA

  • Get an API key at ggscore.net — start on Free, measure traffic, upgrade when needed.
  • Read the docs for ReDoc reference, TypeScript types, and exact response schemas.
  • Build the weekend project on played + upcoming; move to Premium or Black when users depend on it.

Bottom Line

GGScore sells structured CS2 match data — played results and upcoming fixtures — so you spend complexity on product, not parsers. Treat it as a paid API: prototype free, cache aggressively, scale with the plan that matches your poll pattern.

GGScore API: Played and Upcoming CS2 Matches Without Scraping | GGScore