Tutorial · 11 min · endpoints verified 2026-08-16

How to build a cricket app

A batting-form dashboard built on real innings — strike rates, boundaries and dismissals from 421,886 scorecard rows going back to 2001. Two paths: hand it to your AI agent, or write it yourself.

Why this is hard

The problem with cricket data

Cricket is a per-innings game scored in a per-match world. Almost every free cricket source gives you a result and a total, which is precisely the resolution at which cricket stops being interesting — the question is never who won, it is how the innings was built.

  • A total tells you nothing about tempo. 160 off 20 overs built on 5 boundaries is a different innings from the same 160 built on 14, and only ball-and-boundary detail separates them.
  • Strike rate needs balls faced, not just runs — a column most scraped sources drop because it is inside the scorecard table rather than the result header.
  • Cricket has three formats with different arithmetic. A T20 strike rate and a Test strike rate are not comparable, so any real dashboard has to know which competition an innings came from.
  • Scorecard scraping is per-match by construction. Building a career view means fetching hundreds of pages and reconciling player names across them.

Path 1 · recommended

Have your AI agent build it

Our MCP server is live. Point any MCP client — Claude Code, Claude Desktop, Cursor, or your own agent — at it, and the model can read our data directly while it writes your app. You describe the dashboard; it queries, shapes and renders it.

1. Connect the MCP server

Add the server in your MCP client and sign in with your Big Balls account. Your client registers itself and handles the token exchange — there is no key to copy.

MCP client configjson
{
  "mcpServers": {
    "bigballs-sports-data": {
      "url": "https://mcp.bigballsdata.com/mcp"
    }
  }
}

2. Tools your agent gets

  • get_matches

    Live, upcoming or historical matches for a sport or league.

  • get_player_stats

    Per-player career or per-season totals and per-game rates.

  • get_coverage

    Machine-readable map of what we hold and what we do not.

3. Ask for what you want

Paste this at your agent. It is written to make the model check coverage before it designs anything, which is what stops it inventing a field we do not serve.

Prompttext
Build me a cricket batting-analysis dashboard.

Use the Big Balls Sports Data MCP server. Start with get_coverage for
cricket so you know what is actually held before you design anything.

Then, for a competition I pick from GET /v1/cricket/series, pull recent
finished matches and their scorecards, and build a table of batting
innings: player, runs, balls, strike rate, fours, sixes, and which
competition the innings came from.

Rank by strike rate with a minimum-balls filter so a 12-ball cameo does
not top the table. Group the output by format — T20, ODI and Test
strike rates are not comparable.

What the agent cannot reach

The MCP server exposes five read tools and none of them is cricket-scorecard-specific: the scorecard, series and live-state endpoints are REST-only today. An agent can discover coverage, matches and player stats through MCP, then call the REST endpoints below directly for the innings detail. Treat the agentic path as the scaffolding and the REST calls as the data.

Path 2 · hand-coded

Build it yourself

Four calls, no key juggling, no name reconciliation. Every response below was captured from production on 2026-08-16 and trimmed only for length.

  1. 01

    Pick a competition

    Cricket is organised by competition, not by league table. Start here — this endpoint derives its list from matches we actually hold, so a competition with zero games can never appear.

    List the competitions we holdbash
    curl -s "https://api.bigballsdata.com/v1/cricket/series" \
      -H "x-api-key: $BBS_KEY" | jq '.data[:3]'

    Real response, trimmed

    jsonjson
    [
      { "id": "ace09e03-…", "name": "ODI Cricket",  "match_count": 3213,
        "first_match": "2002-06-27T00:00:00.000Z", "latest_match": "2026-12-07T11:30:00.000Z" },
      { "id": "0742154d-…", "name": "IPL",          "match_count": 1263,
        "first_match": "2008-04-18T00:00:00.000Z", "latest_match": "2026-05-31T14:00:00.000Z" },
      { "id": "f9c523c8-…", "name": "Test Cricket", "match_count": 917,
        "first_match": "2001-12-19T00:00:00.000Z", "latest_match": "2026-11-23T08:00:00.000Z" }
    ]
  2. 02

    Fetch recent matches

    Filter the match list to your competition. Results come back most-recent-first, so the first page is the current form window.

    Recent matches in a competitionbash
    curl -s "https://api.bigballsdata.com/v1/cricket/matches?series=IPL&limit=5" \
      -H "x-api-key: $BBS_KEY" | jq '.data[0] | {id, league, home: .home.name, away: .away.name, status, score}'

    Real response, trimmed

    jsonjson
    {
      "id": "6b2e6ed1-…",
      "league": "T20I Cricket",
      "home": "Trent Rockets",
      "away": "Manchester Super Giants",
      "status": "finished",
      "score": { "home": 158, "away": 162 }
    }
  3. 03

    Pull the scorecard

    This is the layer that makes a cricket app worth building: per-innings batting and bowling with balls faced, boundaries and strike rate already computed.

    Per-innings batting and bowlingbash
    curl -s "https://api.bigballsdata.com/v1/cricket/matches/$MATCH_ID/scorecard" \
      -H "x-api-key: $BBS_KEY" | jq '.data.innings[0].batting[0]'

    Real response, trimmed

    jsonjson
    {
      "innings_number": 1,
      "player_id": "3d0212ca-8a81-5ff3-a72a-aeb7e501fd5a",
      "player_name": "LG Pretorius",
      "runs": 52,
      "balls": 28,
      "fours": 5,
      "sixes": 3,
      "strike_rate": "185.71"
    }
  4. 04

    Rank the innings

    Sort by strike rate with a minimum-balls floor, and keep the competition on every row so you never compare a T20 innings against a Test one.

    Build the tabletypescript
    type Innings = {
      player_name: string;
      runs: number;
      balls: number;
      fours: number;
      sixes: number;
      strike_rate: string | null;
    };
    
    const res = await fetch(
      `https://api.bigballsdata.com/v1/cricket/matches/${matchId}/scorecard`,
      { headers: { 'x-api-key': process.env.BBS_KEY! } },
    );
    const { data, meta } = await res.json();
    
    // meta.available is false when we hold no innings for this match — show that,
    // never an empty table that reads as "nobody scored".
    if (!meta.available) return { rows: [], note: meta.note };
    
    const rows = data.innings
      .flatMap((i: { batting: Innings[] }) => i.batting)
      .filter((b: Innings) => b.balls >= 10)
      .map((b: Innings) => ({
        ...b,
        boundaryPct: Math.round(((b.fours * 4 + b.sixes * 6) / b.runs) * 100),
      }))
      .sort((a, b) => Number(b.strike_rate ?? 0) - Number(a.strike_rate ?? 0));

Reference

Every endpoint this tutorial uses

All on the gateway at api.bigballsdata.com. Verified against production on 2026-08-16.

MethodPathReturnsWhy you need itPlan
GET/v1/cricket/series765 competitions with match counts and date rangesThe entry point. Derived from matches we hold, so it cannot advertise a competition with no games.Free
GET/v1/cricket/matchesCricket matches, most-recent-first, filterable by series and dateGets you the match ids the scorecard endpoint needs.Free
GET/v1/cricket/matches/{id}/scorecardPer-innings batting and bowling — runs, balls, fours, sixes, strike rate, dismissalThe spine of this tutorial. 421,886 batting and 293,453 bowling rows across 22,898 finished matches.Free
GET/v1/cricket/matches/{id}/stateLive innings state — overs, runs, wickets, target, run ratesTurns the dashboard live during a match, and says so honestly when it cannot.Recorded only while a match is in progress. Cricket is between fixtures here — the next scheduled match is 2026-11-15 — so this returns available: false today. That is the correct answer, not an outage.Free
GET/v1/cricket/players/{id}Player profile aggregated from real scorecard rowsTurns a player_id from a scorecard into a career view without name matching.Free
GET/v1/teams/{id}/formRecent results with scores, opponents and W/L per competitionThe modelled layer — rolling team form, computed rather than collected.Solo

Pricing, honestly

Where the free tier stops

Everything above runs on a free key: every competition, every scorecard, the full 24-year archive. What the free tier does not give you is the computed layer — the numbers we derive rather than collect. For cricket that layer is team form.

Free key

jsonjson
// Free key — GET /v1/teams/:id/form
{
  "error": { "code": "forbidden",
             "message": "Access to team form requires the Solo plan or higher." },
  "suggested_fix": "Solo unlocks rolling form across recent results, computed per team. …/pricing"
}

Solo

jsonjson
// Solo — GET /v1/teams/:id/form
{
  "date": "2026-08-16T17:00:00.000Z",
  "home": "Trent Rockets",
  "away": "Manchester Super Giants",
  "home_score": 158,
  "away_score": 162,
  "result": "L",
  "competition": "T20I Cricket"
}
  • Rolling team form — recent results with scores, opponent and competition, already sequenced. The column that turns a scorecard browser into an analysis tool.
  • Solo is $19/month and also lifts the free tier’s 1,000 requests/day to 10,000 — which matters here, because a scorecard-per-match build is request-hungry by nature.
  • Honest scope: cricket teams have no Elo rating and cricket players are not tiered yet, so those Solo endpoints return nulls for this sport. They are not part of this build and are not sold as if they were.

More tutorials

Other build guides

Known gaps

What is not here yet

Stated plainly, because finding out mid-build is worse than knowing now.

  • No Elo ratings or model win probabilities for cricket teams — /v1/teams/:id/elo returns a null rating for this sport.
  • No player tiers for cricket — the tier endpoint answers with reason: "sport not yet tiered".
  • Ball-by-ball commentary is not offered at all. The innings-level scorecard is the finest resolution we hold.
  • Live innings state exists and is wired, but cricket is between fixtures until 2026-11-15, so it reports available: false today.

Questions

How far back does the cricket data go?
Twenty-four years, and it varies by competition: Test cricket to 2001, ODI to 2002, IPL to 2008. GET /v1/cricket/series returns first_match and latest_match per competition so you can check the range before you build against it, rather than discovering the edge in production.
Is the scorecard data actually complete, or just recent matches?
421,886 batting innings and 293,453 bowling spells across 22,898 finished matches. It is the deepest layer we hold for cricket. Matches we do not have innings for return meta.available: false rather than an empty innings array, so your code can tell "no data" from "no runs".
Can I build a fantasy cricket app on this?
Partly, and it is worth being direct about the limit. The per-innings scoring data is there and is deep enough to compute fantasy points yourself. What is not there is the modelled layer other fantasy builds lean on — cricket has no Elo ratings and no player tiers today. If you want the projection layer handed to you rather than derived, basketball and hockey are further along.
Why is live match state empty?
Because no cricket match is in progress. Innings state is recorded only while a match is being played, and the next scheduled fixture in our data is 2026-11-15. The endpoint reports available: false with a note rather than returning a zeroed-out innings, so an empty response is never mistaken for a 0/0 score.
Do I need the MCP server, or can I just call the REST API?
Either, but for cricket specifically the REST API is the complete surface. The MCP server exposes five read tools and none of them is cricket-scorecard-specific, so an agent can scaffold from coverage and matches but will call the REST scorecard endpoint for the innings detail.

Build it

Free key, no credit card, 1,000 requests a day. Every scorecard call in this tutorial works on it.