Sports & Fitness — entry 028 of 34

Squiggle

Verified Jul 2026

Squiggle is a free JSON API for AFL fixtures, results, ladders, and its signature aggregated margin predictions pooled from multiple tipping models. Its own docs require setting a descriptive `User-Agent` containing a contact email rather than an API key, and since v1.11.0 the API actively refuses requests carrying common scraper user-agent strings, so `auth: None -> User-Agent` is corrected. A live Origin-header probe of the real host returned an explicit `{"error":"forbidden_origin"}` rejection for a cross-origin browser request -- reachable directly, but not CORS-open to arbitrary origins -- correcting `cors: yes -> no`.

Squiggle is a single-endpoint JSON API for AFL fixtures, results, ladders, and its signature aggregated margin predictions: every call hits the same root path with a `q=` parameter selecting the resource (`teams`, `games`, `tips`, `ladder`, and more). No API key is required, but the API actively rejects requests that don't self-identify with a descriptive `User-Agent`, and it refuses cross-origin browser calls outright regardless of UA.

aflaustralian-footballfixturespredictionsresults
AuthenticationUser-AgentSign up with the provider to obtain credentials.
HTTPSSupportedTraffic is encrypted in transit.
CORSDisabledBrowser calls need a server-side proxy.
PricingFreeNo paid tier — free for the documented use case.
FormatsJSONResponses can be requested as JSON.

GreatAPIs Score

Score71out of 100
Authentication22/25Only a User-Agent header
Pricing20/20Free to use
Docs0/20No docs or spec available
Formats9/15Single response format
Freshness20/20Verified within 6 months

Embed this badge

Scored 71 on greatapis.com
<a href="https://greatapis.com/api/squiggle/"><img src="https://greatapis.com/badge/squiggle.svg" alt="Scored 71 on greatapis.com"></a>

Auth quickstart

  1. No API key or signup, but every request must carry a descriptive `User-Agent` naming your app and a contact method. A live GET this run with the default `curl/7.88.1` UA still returned HTTP 403, and the response body nests the rejection inside the requested resource's own key: `{"teams":[{"api_version":"1.13.2","your_user_agent":"curl/7.88.1","error":"bad_UA","warning":"Your UserAgent has not been set correctly. To avoid bans, please see https://api.squiggle.com.au/#section_bots"}]}` -- swapping in a UA like `greatapis.com quickstart (contact: hello@greatapis.com)` returns the real data instead, confirmed live this run.
Stored keyNo key stored

Your key is stored only in this browser (localStorage) and sent directly to the API — never to greatapis.

List AFL teams

GEThttps://api.squiggle.com.au/?q=teams

User-Agent: greatapis.com quickstart (contact: hello@greatapis.com)

200 application/json; charset=UTF-8

{"teams":[{"retirement":9999,"logo":"/wp-content/themes/squiggle/assets/images/Adelaide.png","abbrev":"ADE","id":1,"debut":1991,"name":"Adelaide"},{"retirement":9999,"logo":"/wp-content/themes/squiggle/assets/images/Brisbane.png","abbrev":"BRI","id":2,"debut":1987,"name":"Brisbane Lions"},{"...":"16 more teams, same shape"}]}

Try it

Developer reference

Base URLhttps://api.squiggle.com.au
Key endpoints
  • GET/?q=teams
  • GET/?q=games&year={year}&round={round}
  • GET/?q=tips&year={year}&round={round}

Gotchas & limits

  • A rejected request due to a bad User-Agent is HTTP 403, but the error payload is nested inside the requested resource's own array key (`teams`/`games`/etc.), not a top-level `error` field -- see the authSteps transcript above; a naive client that only checks `response.ok` before reading `data.teams[0].name` will silently render the error object as if it were a team.
  • Cross-origin browser calls are refused outright, independent of the User-Agent check: a live GET with a correct UA plus `Origin: https://greatapis.com` this run still returned HTTP 403 with `{"teams":[{"api_version":"1.13.2","message":"Cross-origin browser access from this origin is not allowed.","error":"forbidden_origin"}]}` -- server-side or same-origin calls only, no CORS workaround exists client-side.
  • `q=tips` returns one row per tipster source per game, not one row per game: a live `GET /?q=tips&year=2024&round=1` this run returned multiple entries sharing the same `gameid` (e.g. `35704`), each from a different `source` (`"Squiggle"`, `"Matter of Stats"`, `"Punters"`, ...) with its own `margin`/`confidence` -- summing or averaging without grouping by `gameid` double-counts games.
  • The documented query syntax uses semicolons between parameters (`?q=games;year=2024;round=1`), but a live test this run confirmed standard `&`-separated query strings (`?q=games&year=2024&round=1`) return byte-identical results -- either separator works against the real host.