# SEO opportunity research

Keyword research tools are priced for a person clicking through a dashboard. They are painful to use as a data source: seat-based, rate-limited on the API tier, and export-capped exactly where the interesting work starts.

If what you want is a scored list of keywords with the SERP that currently owns each one, that is four calls. This guide runs them, and shows what each field is actually good for.

## The pipeline

```
seo.keywords       →  volume, CPC, competition, and related ideas for a seed
seo.serp           →  who ranks today, with SERP features and AI Overview presence
seo.competitors    →  the domains fighting for the same keyword set
seo.ranked_keywords →  everything a competitor already ranks for
```

Run them in that order the first time. After that, `seo.serp` on a saved keyword set is the one you run on a schedule.

## Step 1: expand the seed

```bash
curl -X POST https://api.jell.run/v1/run \
  -H "Authorization: Bearer $JELL_API_KEY" \
  -d '{
    "capability": "seo.keywords",
    "input": {"keyword": "api rate limiting", "location": "United States", "limit": 200}
  }'
```

Back come volume, CPC, competition and a list of related ideas.

CPC is the field most people skim past and it is the best commercial-intent proxy in the response. Advertisers bid real money on queries that convert. A keyword with 400 searches and a $14 CPC is worth more than one with 9,000 searches and a $0.20 CPC, because the second one is research traffic and the first one is someone with a budget and a problem.

Sort by CPC, filter by volume, and you have a shortlist before you look at a single SERP.

## Step 2: read the SERP before you write anything

Volume tells you how many people search. The SERP tells you whether you can have any of them.

```bash
curl -X POST https://api.jell.run/v1/run \
  -H "Authorization: Bearer $JELL_API_KEY" \
  -d '{
    "capability": "seo.serp",
    "input": {"keyword": "api rate limiting", "location": "United States", "engine": "google"}
  }'
```

The response carries the results, the total, the `serp_features` present, and `ai_overview_present`.

Three checks that kill more keyword ideas than any difficulty score:

- **Who holds the top five.** Ten pages from domains with a hundred times your authority is not an opportunity, whatever the difficulty metric says. Mixed results with forums, a Reddit thread and one thin vendor page is an opening.
- **What intent the page shape implies.** If every result is a comparison table, a tutorial will not rank there no matter how good it is. Match the format that is already winning.
- **Whether an AI Overview is present.** `ai_overview_present` is a click-through warning. On queries where it fires, the informational click is often absorbed above the fold. That does not mean skip the keyword. It means the value moved from traffic to being cited, which is a different optimization.

Run this with `engine: "bing"` as well when your audience is enterprise or your product is developer tooling. The result sets diverge more than most teams assume.

## Step 3: find who you are actually competing with

```bash
curl -X POST https://api.jell.run/v1/run \
  -H "Authorization: Bearer $JELL_API_KEY" \
  -d '{"capability": "seo.competitors", "input": {"domain": "yourdomain.com", "limit": 20}}'
```

This returns the domains competing for your keyword set with shared-keyword counts and average positions. It is frequently a different list from your sales competitors: review sites, marketplaces and one unexpected blog that has quietly taken your category.

Then take the two or three that matter and pull their whole ranking footprint:

```bash
curl -X POST https://api.jell.run/v1/run \
  -H "Authorization: Bearer $JELL_API_KEY" \
  -d '{"capability": "seo.ranked_keywords",
       "input": {"domain": "competitor.com", "location": "United States", "limit": 500}}'
```

Position, volume, CPC and estimated traffic for every keyword they rank for. The gap analysis is a set difference: their keywords minus yours, filtered to positions 1 to 10 and CPC above your threshold. That list is a content plan derived from evidence rather than from a brainstorm.

## Step 4: check the page before you rewrite it

```bash
curl -X POST https://api.jell.run/v1/run \
  -H "Authorization: Bearer $JELL_API_KEY" \
  -d '{"capability": "seo.page_audit", "input": {"url": "https://yourdomain.com/pricing"}}'
```

Status, title, description, headings, links, timing and on-page issues for a single URL, at a fraction of a cent. Cheap enough to run across every page you publish as a pre-flight check in CI, which catches the boring failures (missing description, a heading hierarchy that skips levels, a 302 that should be a 200) before they cost you a quarter.

For the domain-level view, `seo.domain_overview` returns the organic and paid footprint with estimated traffic and its value, and `seo.backlinks` returns referring domains when you need the authority picture.

## Turning it into a scored list

The list worth acting on has four columns per keyword: volume, CPC, the weakest domain in the top five, and whether an AI Overview fires. Rank by CPC times a winnability estimate, not by volume, and the plan stops being a list of things nobody searches for with intent.

Re-run `seo.serp` on the shortlist monthly. Ranking changes are the only feedback loop that matters, and at these prices tracking a few hundred keywords is a rounding error against a seat license.

## Where it breaks

- **Volume is modelled, not measured.** Treat it as an order of magnitude. The relative ordering is reliable; the absolute number is not.
- **SERPs are personalized and localized.** Always pass `location`, and compare like for like over time.
- **Difficulty scores are opinions.** The domains actually sitting in the top five are the fact. Prefer the fact.
- **`ai_overview_present` is a snapshot.** It fires inconsistently for the same query. Sample over several days before you conclude a keyword is dead.

## Run it as an agent

```bash
jell run -c seo.keywords -i '{"keyword":"api rate limiting","location":"United States"}'
jell run -c seo.serp -i '{"keyword":"api rate limiting","location":"United States"}'
jell run -c seo.competitors -i '{"domain":"yourdomain.com"}'
```

The full DataForSEO live API is also addressable as [raw endpoints](/docs/api/endpoints) when you need a report that has no capability yet, settled on the provider's measured cost after the call.

## FAQ

### Why sort by CPC instead of search volume?

Because CPC is the only field in the response that reflects what the query is worth to someone with a budget. Advertisers bid real money on queries that convert, so a keyword at 400 searches and a $14 CPC represents more commercial intent than one at 9,000 searches and $0.20. Volume tells you how many people search. CPC tells you whether any of them are buying.

### Is keyword difficulty worth using at all?

As a rough sort, yes. As a decision, no. Difficulty is a modelled opinion built from backlink metrics, and it does not know your topical authority or how weak the actual results are. The reliable check is the SERP itself: pull `seo.serp` and look at who holds the top five. A page of forum threads and thin vendor pages is winnable regardless of what the score says.

### What should I do about keywords with an AI Overview?

Change the target, not the keyword. When an overview fires, the informational click shrinks but the query still represents demand, and the overview cites sources. Optimize to be the passage worth quoting: a clear question as a heading, a complete and specific answer immediately under it. Also sample over several days, because `ai_overview_present` fires inconsistently for the same query.

### How often should I re-run the SERP for tracked keywords?

Monthly for the shortlist you are working on. At these prices, tracking a few hundred keywords monthly costs less than one seat on a rank tracker, and ranking movement is the only feedback loop that tells you whether the content work did anything. Daily tracking mostly measures SERP volatility rather than your progress.

### Should I check Bing as well as Google?

If your audience is enterprise or your product is developer tooling, yes. The result sets diverge more than most teams assume, and Bing feeds several other surfaces. Pass `engine: "bing"` on the same keyword and compare. If the top five differ substantially, that is a second, cheaper opportunity nobody in your category is optimizing for.

### Which API returns keyword volume, difficulty and ranked keywords for a domain?

`seo.keywords` returns volume, CPC and competition for a seed keyword and its ideas. `seo.ranked_keywords` returns every keyword a domain ranks for with position, volume, CPC and estimated traffic. Both are DataForSEO data behind one key, priced per call, with no seat license and no monthly minimum.

### What is the cheapest way to get Google search results as JSON for an SEO tool?

`seo.serp` returns the live Google or Bing results page for a keyword and location as JSON, with the organic results in order, the SERP features present and whether an AI Overview appeared. It is priced per search, and `/v1/inspect` returns the exact number before you run it, so you can compare it against a SERP API plan on your actual volume rather than a quota.

### How do I give my Claude Code agent access to SERP, backlink and keyword data?

Point it at the SKILL.md or connect the MCP server. Either way the agent gets `seo.serp`, `seo.keywords`, `seo.ranked_keywords`, `seo.backlinks`, `seo.competitors` and `seo.page_audit` as tools, with the price quoted before each call and one balance behind all of them. The [MCP quickstart](/docs/quickstart-mcp) covers Claude Code, claude.ai, ChatGPT and Cursor.
