Every keyword my agents chase, every SERP they read before writing, every competitor they size up on a Monday morning comes from one place: the DataForSEO API. It has no dashboard my agents need to log into, no monthly plan, and no seat licence. You put money on the account and every call takes a fraction of a cent off it.
It is the best-value tool in my stack. It also spent more than a week, from late September into October, telling my agents everything was fine while it refused to do any work. Here is what it is, what it really costs, and the three ways it will lie to an agent that only reads the top line.
What the DataForSEO API is (and what it costs)
DataForSEO sells raw search data over REST: live Google results, keyword volume and difficulty, backlinks, competitor rankings. There is no SDK to install. It is curl with basic auth and a JSON body, which makes it ideal for an agent.
The pricing is pay-as-you-go against a prepaid balance. Real numbers from my own runs:
- One live Google SERP, top 20 results: $0.0035 (the call I made this morning to write this post)
- One Labs
keyword_overviewcall, with true difficulty and search intent: $0.0148 - A full weekly keyword-research run, 16 calls: $0.165
The account has had $351 put on it in total. This morning’s balance is $76.89. On 5 October it was $97.61. That one account feeds the whole fleet, every brand, so about two dollars a day buys my agents their entire view of Google.
And unlike ScrapeCreators, where reading my own meter costs a credit, DataForSEO gives you a free balance endpoint: GET /v3/appendix/user_data. Remember it, because it is the fix for gotcha #1.
Gotcha #1: “20000 Ok.” does not mean OK
In late September the balance fell to −$0.0003. Every call after that came back like this:
HTTP 200
{"status_code": 20000, "status_message": "Ok.",
"tasks": [{"status_code": 40200, "status_message": "Payment Required.", "result": null}]}
The HTTP status said success and so did the envelope. The refusal sat one level down, inside tasks[0]. Any agent that checked the top-level status saw a green light, then crashed on an empty result or, worse, carried on with nothing. My blog and research skills spent at least eight days falling back to Firecrawl search before anyone topped the account up.

⚡ GET THE AI EDGE
Weekly AI tips that actually save you time and money. No fluff, no hype — just what works.
It’s not only money, either. One run this month got a top-level 50000 Internal Server Error with tasks: null twice in a row. That’s a third failure shape, and it needs its own check.
The rule: check the HTTP code, the envelope status_code, and every task’s status_code. Only 20000 at both levels counts as success.
Gotcha #2: you can only send one task per call
The request body is a JSON array of tasks, so batching looks obviously supported. For live SERP calls, it isn’t. I re-tested it this morning with two keywords in one POST:
task 1: 20000 Ok. cost 0.0035
task 2: 40000 You can set only one task at a time. cost 0
Task 1 runs, gets billed, and returns real data. Every task after it quietly fails. If your agent loops over the results and only processes the ones that worked, it reports “5 keywords researched” when it really did one. Send one keyword per POST, sequentially, with a few seconds between calls.
Gotcha #3: position 13 is really position 10
Every result carries two rank fields, and they mean different things. rank_absolute counts everything on the page, including videos, AI Overviews and “related searches” blocks. rank_group counts only results of the same type.
In this morning’s SERP for claude code tutorial for beginners, a video block, an AI Overview and a related-searches box all sat above the lower organic results. The site in organic tenth place had rank_absolute: 13. An agent quoting rank_absolute would tell you a page is off page one when it’s actually holding the last slot. Use rank_group for organic positions, and filter on type == "organic" first.
Do this today
- Add a balance check to the start of every SEO run. One free call to
user_data. If the balance is under a dollar, skip cleanly and alert. Don’t run the job and log empty results as findings. - Write one status helper and use it everywhere. It checks the HTTP code, the envelope and every task. Any task that isn’t
20000fails the call loudly, with the task’s own message. - Read positions from
rank_group. Then grep your old reports forrank_absolute. You may find you’ve been underselling your own rankings.
The takeaway: a cheap API is only cheap if your agent can tell when it stopped working. DataForSEO costs me about two dollars a day, and its most expensive failure didn’t cost a cent. It was eight days of research built on empty responses that every log called a success.
For the same lesson from other angles, read the Replicate write-up, where my real cost was double my own docs, and the 10-minute billing check that would have caught the empty balance on day one. If you want an SEO research pipeline that checks its own receipts, book a strategy session and we’ll map it to your stack.

📥 FREE: THE AI PLAYBOOK
The exact tools and workflows I use to run a one-person agency. 25 years of marketing experience distilled into an actionable guide. Yours free.
