keyword_positions
Read the SERP positions already measured and stored for a domain's keywords — each reading with its own date, location, language and device. It measures…
Cost: 10 credits.
keyword_positions reads the SERP positions SeoGrep has already measured and stored for a domain's keywords: each reading with its own date, location, language and device. It measures nothing — no search engine is contacted and no new position is read.
What it does
Pass a project_id (or any target domain) and it returns the stored readings, newest first, grouped into series. A series is everything a reading was taken under — not just the keyword, location, language and device you chose, but the search engine, the depth that was requested, and the rule used to decide a result was yours. Those last three fork a series too, and must: "not found in the 10 results examined" and "not found in the 100 results examined" answer different questions, and putting them on one line would turn a change of depth into an apparent movement. Narrow it with keyword, location_name, language_code or device, and bound the answer with limit — the reply always states how many readings match your filter in total, separately from how many are in the window.
A gap is not a decline
Two readings a month apart are two observations, not a trend, and SeoGrep will not draw a line through the days nobody measured. Every comparison between two readings says how far apart they were, and an interval longer than a day says outright that nothing was measured in between. No answer here claims a direction of travel: a movement is printed as #7 → #4, never as a rise or a fall.
This is not Search Console's average position
SeoGrep prints the word "position" in two places, and they are different measurements. Here it is a SERP rank observed at one moment — rank #4 means the fourth organic result on the page that was fetched, and it is a whole number reported by DataForSEO. In find_quick_wins it is Search Console's average position, computed by Google across a reporting window, and it can be a decimal such as 12.3. Reading the difference between the two as a movement would be reading a change nobody measured, so SeoGrep never compares them.
"Not found" and "not measured" are different answers
A reading that searched and found nothing reports the absence and how many results were examined — it is not position 0, and it says nothing about results beyond those examined. A reading that never happened says so instead: the position is unknown, and nothing was examined at all.
A position is never compared across either of them, because there is no second position to compare with.
A reading where the domain was found but the vendor reported no rank is a third case, and it is really two, kept apart. DataForSEO has two rank scales — the organic-only one and the one counting every element on the page — and it may withhold either. A row with neither says so; a row where it gave the all-elements rank and withheld the organic one says exactly that, and prints the number it did send. One sentence for both would have printed "DataForSEO reported no rank" over a row on which DataForSEO had reported one.
Which page ranked, and what else was on the SERP
A rank is #4 of something, so each reading also names the URL that ranked and the SERP features DataForSEO recorded on that page — a featured snippet, a "people also ask" block, an AI Overview — under the vendor's own identifiers. Both were captured by serp_snapshot when the reading was taken; nothing here contacts a search engine to get them.
Readings taken before this was recorded say not recorded rather than reporting an absence. "We did not write it down" and "there was nothing there" are different claims, and this page never prints the first as the second.
An AI Overview here means one thing only — the block was on that results page for that keyword when the snapshot was taken. It does not say whether your site is cited inside it: Google builds its AI features by query fan-out, running further searches across sub-topics and drawing on a wider set of pages than the one keyword measured, so a single reading is not a measure of AI visibility.
If nothing has been measured yet
The tool says so and charges nothing — that refusal is returned before any credits are reserved. It is the only free answer this tool gives: a read that delivers stored readings is charged at the cost above, whether it returns one reading or hundreds.
Positions appear here once a SERP snapshot has been taken for a domain's keywords. track_keywords chooses which keywords to watch — a separate step, and that one is free; serp_snapshot is what takes the readings, and it is priced per keyword.
Example
Ask your MCP client in plain language:
Show me the stored positions for "seo tools" on my example.com project.
Input
| Field | Type | Required | Description |
|---|---|---|---|
target | string | No | The domain to read stored positions for, e.g. "example.com" or "https://example.com" — any public domain, including a competitor's. Pass this OR project_id, not both. |
project_id | string (uuid) | No | One of your projects (from setup_project / list_projects) — the domain is taken from it. Pass this OR target, not both. |
keyword | string | No | One keyword's series. Omit to read every keyword measured for this domain. Matched as stored — trimmed and lower-cased, the same way track_keywords stores it. |
location_name | string | No | Only readings measured in this location. Omit to read every location — the readings are grouped by location either way, and never mixed into one series. |
language_code | string | No | Only readings measured in this search language. Omit to read every language. |
device | string | No | Only readings measured on this device. Omit to read both — desktop and mobile are different SERPs and are never folded into one series. |
limit | integer | No | How many readings this answer may hold (1-200, default 50), newest first. It bounds the ANSWER, not the store: the output always states how many readings match the filter in total, separately. |
Returns
One block per series — keyword, location, language, device, search engine, depth requested and domain-match rule — with what each reading was measured under, each reading's own date, and the elapsed time between them. Ranks are DataForSEO's own rank_group and rank_absolute; SeoGrep adds no score of its own.