Dates are inclusive UTC days
start_date and end_date are YYYY-MM-DD and both are included. September is 2026-09-01 to 2026-09-30, not 2026-10-01.
- Answer reports (visibility, citations, sentiment, answers) file each answer under the UTC day it was collected.
- Traffic reports (AI crawlers, AI referrals) take an optional
timezone(an IANA name such asAsia/Karachi, defaultUTC) for the day boundaries and thedatebuckets. - An answer report covers at most 92 days, a traffic report at most 400 days. For a longer history, make one call per quarter.
Know the scale of each number
Multiply a fraction by 100 to show a percentage. Report a change in a rate as percentage points (0.42 → 0.47 is +5 pp), not as a percentage of a percentage.
Don’t average daily rows to get a period score
A monthly Visibility Score is computed from every answer in the month. The average of thirty daily scores is a different number: it gives a day with three answers the same weight as a day with forty, andprompt_coverage in particular does not average at all (a prompt named on one day of the month counts as covered for the month).
Ask for the period in one call without date in group_by. Use daily rows for the trend line only. The same applies to weeks and months: there are no week or month buckets, so make one call per week or per month. See Headline and daily together.
Counts are different: answers and citations add up across days.
Changes are computed client-side
No endpoint returns a delta. Make two calls with windows of equal length and subtract. See Visibility Score with change.Rows have named fields
Every row is an object with named fields, so you never read a value by position. Grouped dimensions appear on the row under their own names:date, platform, category, and prompt as { id, text }. Visibility rows always carry brand: { name, owned } and rank.
citation_share is computed after the filter
In the citations report, citation_share is each row’s share of the citations that pass your filter, within its group. Filter on owner = own and your own domains will always add up to 1. To get the share of all citations that went to you, request the report unfiltered and sum the rows where owner is own. See Owned citation share.
Ordering
- Visibility rows are sorted by the grouped dimensions (dates ascending), then by
rank. Passsort: { field, dir }to sort by a metric instead. - Citation rows are sorted by the grouped dimensions, then by
rank: most answers citing it first. - Within each group,
rankrestarts at 1.
Pagination
Reports return at most 100 rows a page (traffic reports 500, answers 50).info.next_cursor is null on the last page; otherwise pass it back as cursor with the same query. A cursor is bound to its query, so changing a date or a filter with an old cursor is refused with 400 invalid_cursor.
The SDKs handle this for you:
A leaderboard or a top-N list usually fits on one page. Anything you sum or join across rows, such as an owned share, needs every page.
Google pages with no AI Overview are left out
About three in ten Google result pages show no AI Overview at all. Those are a finding about the question, not answers that failed to name you, so they are excluded from every rate and fromanswers on ai_overviews and ai_mode. A day with few answers on those engines is usually this, not a broken scan.
Engines and prompts start on different days
An engine added to the site, or a prompt switched on, produces data from its first scan. Checkanswers before reading a rate: a rate over two answers is noise. Engine IDs are listed by GET /v1/platforms.
Rate limits
120 requests a minute per key, 20 of them writes. A429 carries Retry-After; the SDKs wait exactly that long and retry. Cache anything that changes rarely, such as your site list and competitors. See Rate limits.