How to Manage Query Complexity in the Motorsport API
β Included in All Plans
Query complexity management applies to all plans.
Plans differ only in leagues and API call limits.
This guide explains how query complexity works in the Motorsport API, how to read the complexity score on each endpoint, and how to restructure requests that exceed the threshold.
When to use this
Read this guide when you:
Receive a
422error with a complexity-related messageWant to understand why a particular include combination is rejected
Are planning a heavy live-race request and want to avoid hitting the threshold
Need to decide between one large request versus several smaller ones
What query complexity Is
Every include you add to a request has a complexity score. The API sums these scores and rejects the request if the total exceeds the endpoint's threshold, returning a 422 status.
This is separate from your plan's rate limit (hourly call count). A complexity error means a single request is too expensive to process - it has nothing to do with how many requests you've made.
The complexity score for each include is listed on the individual endpoint documentation page, alongside the "Include depth" and "Include options" sections.
Reading the complexity score
On each endpoint's documentation page, the include options section shows the allowed includes. The complexity score for each appears either inline or via the linked type reference. The GET Laps by Fixture ID endpoint, for example, lists fixture, participant, and details as its includes - each has a score that contributes to the total.
Before building a complex request, check:
The endpoint's maximum include depth
The complexity score of each include you intend to use
Whether your combination stays below the threshold
Common motorsport include combinations
These are practical combinations tested against typical use cases, ordered from lightest to heaviest:
Live session - minimal (low complexity)
Just the fixture state. Very light. Suitable for a session status indicator that only needs to know if a race is live or finished.
Live session - race order (moderate complexity)
Adds driver positions, lap times, gaps, and tyre data via the results include. Good balance for a leaderboard display.
Live session - full timing (heavier)
Adds the latest lap for each driver on top of the race order. Use this when you need lap-by-lap timing in your live display. Poll at a sensible interval (15+ seconds).
Live session - maximum enrichment (heaviest)
Full live picture: positions, latest lap, latest pit stop, and current stint. This is the heaviest practical combination for a live race display. If this approaches or exceeds the threshold, split into two requests - one for results and a separate one for latestLaps;latestPitstops.
Standings with driver details (moderate)
Driver name, image, and the most recent race weekend context. Standard for a championship table display.
Fixture with lineup and driver details (moderate)
Driver names and headshots for each car in the session. One level of nesting.
Fixture with lineup and nationality (heavier)
Two nested includes on the same base entity. Adds nationality flag data per driver. Only do this once at session start and cache the result - driver nationalities do not change during a race.
Reducing Complexity
If a request returns a 422 complexity error, try these strategies in order:
Remove includes one at a time to find which one tips you over. Start with the deepest or heaviest include.
Use field selection to reduce payload without removing the include entirely. include=lineups.driver:display_name,image_path requests only two fields from the driver entity instead of the full profile:
Split into two requests for enrichment data you only need once. Fetch lineup driver details at session start and cache them. During the live race, only poll for results and latestLaps - you already have the driver names.
Cache stable data aggressively. Driver names, team logos, venue details, and country flags do not change during a race. Fetch them once and store locally. Your live poll only needs the data that actually changes: positions, lap times, pit stops.
Use the dedicated endpoints for granular data instead of piling includes on the livescores endpoint. Rather than include=laps on a livescores call, use GET Laps by Fixture ID separately after you have the fixture ID.
Practical caching strategy for a live race
This keeps live polls light while still having rich driver data available for display.
Common errors
422
Query too complex
Remove includes or split into multiple requests
400
Parameter not allowed
The include is not supported on this endpoint
429
Rate limit exceeded
Reduce polling frequency; you have hit the hourly call limit
See also
Reference
Related tutorials
FAQ
Is query complexity the same as rate limiting? No. Rate limiting counts how many requests you make per hour against your plan's limit. Query complexity is per-request - it measures how expensive a single request is to process. A complexity error means the request itself is too heavy, regardless of how many other calls you have made.
Does query complexity apply to all endpoints? Yes, but the threshold and scores vary by endpoint. A lighter endpoint like GET Driver by ID has a higher tolerance for includes than a heavier one like GET All Livescores.
If I split a heavy request into two lighter requests, does that hurt my rate limit? It counts as two requests instead of one against your hourly limit. For most plans this is negligible - the trade-off is nearly always worth it to avoid complexity errors during a live race.
Does caching the response locally help with query complexity? Caching does not change whether a single request exceeds the complexity threshold - it either does or it doesn't. But caching stable data means you can use lighter includes on your polling requests, which reduces the chance of hitting the threshold in the first place.
Last updated
Was this helpful?