ErrorCS2 API errors

CORS error on browser requests: the fix.

The browser blocks the response because the API does not send an Access-Control-Allow-Origin header for your site. Neither the Steam Web API nor the CS2 API allows arbitrary origins, so call them from a server-side proxy, which also keeps the API key out of the page.

  • Browser-side error
  • Fix: a server proxy
  • 500 free requests / month
GET /cs2/matches/live200 OK
$ curl "https://api.citoapi.com/api/v1/cs2/matches/live" \ -H "x-api-key: $CITO_API_KEY"
{  "success": true,  "data": [    {      "id": "cs2-match-2398974",      "eventName": "ROG JOURNEY Autumn 2026",      "bestOf": 3,      "team1Name": "Ninjas in Pyjamas",      "team2Name": "Eternal Fire",      "score": { "team1": 2, "team2": 0 }    },    {      "id": "cs2-match-2398896",      "eventName": "FOX Legacy Season 1",      "bestOf": 3,      "team1Name": "SAW",      "team2Name": "Lazer Cats",      "score": { "team1": 2, "team2": 0 }    }    ...  ]}

The error

What you see
Access to fetch at 'https://api.citoapi.com/api/v1/cs2/matches/live' from origin 'https://your-site.com'
has been blocked by CORS policy: Response to preflight request doesn't pass access control check:
No 'Access-Control-Allow-Origin' header is present on the requested resource.

What does the CORS error mean?

Your page tried to read a response from another origin, and the browser did not find permission for your origin in the response headers. The request may have reached the server; the browser just refuses to hand the response to your JavaScript.

Why does it happen with the Steam and CS2 APIs?

Both are built to be called from servers. The Steam Web API sends no Access-Control-Allow-Origin header and answers a preflight OPTIONS request with 405. The CS2 API only allows its own dashboard origins, on purpose: a key used in browser code is visible to every visitor.

  • A custom header such as x-api-key makes the browser send a preflight OPTIONS request first.
  • Steam: no CORS headers on any response, checked on 2026-10-03.
  • CS2 API: CORS headers only for allow-listed origins. Your production site is not one of them, and should not need to be.

How do I fix it?

Add one server route that calls the API with the key from an environment variable and returns the JSON to your page. Your browser code calls your own origin, so there is no cross-origin request and no exposed key.

Next.js App Router: app/api/cs2/[...path]/route.ts
const ALLOWED = /^(matches\/(live|upcoming|results)|teams\/rankings)$/

export async function GET(req: Request, { params }: { params: Promise<{ path: string[] }> }) {
  const path = (await params).path.join("/")
  if (!ALLOWED.test(path)) return Response.json({ error: "not allowed" }, { status: 404 })

  const search = new URL(req.url).search
  const upstream = await fetch(`https://api.citoapi.com/api/v1/cs2/${path}${search}`, {
    headers: { "x-api-key": process.env.CITO_API_KEY! },
    next: { revalidate: 15 }, // share one upstream call per 15 s across visitors
  })
  return new Response(upstream.body, {
    status: upstream.status,
    headers: { "content-type": "application/json" },
  })
}

// Browser: fetch("/api/cs2/matches/live").then((r) => r.json())
Cloudflare Worker (key stored as a secret: wrangler secret put CITO_API_KEY)
export default {
  async fetch(req, env) {
    const url = new URL(req.url)
    if (!url.pathname.startsWith("/cs2/")) return new Response("not found", { status: 404 })
    const upstream = await fetch("https://api.citoapi.com/api/v1" + url.pathname + url.search, {
      headers: { "x-api-key": env.CITO_API_KEY },
      cf: { cacheTtl: 15, cacheEverything: true },
    })
    const res = new Response(upstream.body, upstream)
    res.headers.set("Access-Control-Allow-Origin", "https://your-site.com")
    return res
  },
}

Why not just allow my origin or use a public CORS proxy?

Allowing your origin would still put the key in every visitor's browser, where anyone can copy it and spend your quota. Public CORS proxies see your key and your traffic. A proxy you own fixes both, and its cache cuts the requests you are billed for.

How does the CS2 API keep this from happening?

By design the key never reaches a browser, so there is nothing for a visitor to steal: put one small proxy between your page and the API and the CORS error cannot occur. Responses are plain JSON that is safe to cache at that proxy, which also keeps your request count down.

Frequently asked questions

Something missing? Email support@citoapi.com.

Does the Steam Web API support CORS?

No. api.steampowered.com sends no Access-Control-Allow-Origin header and rejects preflight requests, so browser JavaScript cannot read its responses. Call it from a server.

Can I call the CS2 API directly from React?

Not from a public site. The CS2 API only allows its own origins, so put a small server route between React and the API; the key stays on the server.

Does a proxy cost extra requests?

No, it usually saves them: cache each response for 15 seconds and every visitor shares one upstream call.

See pricing

Build CS2 live score apps

Free is for building and testing. Paid plans add commercial use, real-time live data and the full archive.