SEO Opportunities
How much more revenue your pages would earn if they ranked higher on Google. Use it to decide which posts to improve first: the list is ranked by money, not by position.
The question it answers: "Which pages bring paying customers from Google but are not #1, and what is ranking higher worth?"
What you get
| Field | What it means |
|---|---|
rows[].organic_new_customer_revenue_cents | Revenue from new customers whose first touch was this page through Organic Search, in the window |
rows[].revenue_per_click_cents | That revenue divided by the page's organic Search Console clicks |
rows[].upside_cents_at_1 … _at_3 | Extra revenue per window if the page's top queries ranked #1, #2 or #3 |
rows[].upside_clicks_at_1 … _at_3 | The same in extra clicks |
rows[].upside_range_at_1 … _at_3 | Low and high bounds for clicks and revenue |
rows[].queries[] | The page's top 5 non-brand queries by impressions, with position and per-target revenue gain (null when the query already ranks there) |
insufficient_data | Pages with no organic click in Search Console: listed, not sized (top 5 by revenue; insufficient_data_total gives the full count) |
currency | The workspace display currency: every *_cents field is integer cents in it |
curve | Click-through rate by position 1-10, with how much of it is your own data (own_weight) |
window | The calculation window: it starts at gsc_data_from when Search Console data begins later than the requested window |
notes | Why something is missing or estimated differently |
How the estimate works
The report blends your own click-through rate at each position with a published benchmark (First Page Sage, September 2026). Each position leans on your data in proportion to your impressions there: 2,000 impressions at a position weigh as much as the benchmark. A better position never gets fewer clicks than a worse one.
For a query with clicks, the gain scales its own clicks by the ratio of the target position's rate to its current one. For a query with no clicks, the gain is impressions times the difference in rates. Gains in revenue use the page's current revenue per organic click.
Brand queries and zero-click queries (500+ impressions, 0 clicks over the window, typical of AI Overview citations and rank-tracking bots) are excluded. Revenue is first-touch Organic Search, new customers only, and assumes today's conversion rate.
Parameters
| Parameter | What it does | When you'd use it |
|---|---|---|
from, to / range | The window. Defaults to the last 90 days | Compare a quarter |
page_search | Keep only pages whose path matches these words | page_search=blog to rank blog posts only |
limit | Pages to return, 1-100, default 20 | limit=5 for a short list |
page_url_scope | marketing (default), product or all | Include product-site pages |
To see every query of one page, call page-report with page_path and gsc_breakdown=query.
API key as Bearer token
In: header
Query Parameters
Pages to return, ranked by revenue upside at #1. Default 20, max 100.
1 <= value <= 100Keep only pages whose path matches these words (page-report's page_search matching).
1 <= length <= 200Which host to scope to. Defaults to marketing. all removes the host predicate entirely (every host in the workspace).
Value in
- "marketing"
- "product"
- "all"
Preset date range. Canonical names (last_30_days, last_7_days, last_3_months, last_6_months, last_year, all_time, …) and dashboard short keys (30d, 7d, 3m, 6m, 1y, all) are both accepted. Mutually exclusive with from/to.
Value in
- "last_7_days"
- "last_14_days"
- "last_28_days"
- "last_30_days"
- "last_90_days"
- "current_month"
- "this_month"
- "last_3_months"
- "last_6_months"
- "last_year"
- "all_time"
- "7d"
- "14d"
- "28d"
- "30d"
- "90d"
- "3m"
- "6m"
- "1y"
- "all"
Custom start date (YYYY-MM-DD). Ignored if range is set.
^\d{4}-\d{2}-\d{2}$Custom end date (YYYY-MM-DD). Ignored if range is set.
^\d{4}-\d{2}-\d{2}$Responses
Pages ranked by the revenue upside of ranking #1, #2 or #3
/seo-opportunitiescurl -X GET "https://d1iwal3igywepk.cloudfront.net/seo-opportunities?limit=5&page_search=blog"{ "range": { "from": "string", "to": "string" }, "window": { "from": "string", "to": "string" }, "gsc_data_from": "string", "currency": "eur", "curve": [ { "position": 0, "ctr": 0, "own_ctr": 0, "own_impressions": 0, "own_weight": 0, "benchmark_ctr": 0 } ], "benchmark": { "source": "string", "url": "string", "published": "string" }, "rows": [ { "page_path": "string", "organic_new_customer_revenue_cents": 0, "organic_new_customers": 0, "organic_clicks": 0, "revenue_per_click_cents": 0, "upside_cents_at_1": 0, "upside_cents_at_2": 0, "upside_cents_at_3": 0, "upside_clicks_at_1": 0, "upside_clicks_at_2": 0, "upside_clicks_at_3": 0, "upside_range_at_1": { "low_cents": 0, "high_cents": 0, "low_clicks": 0, "high_clicks": 0 }, "upside_range_at_2": { "low_cents": 0, "high_cents": 0, "low_clicks": 0, "high_clicks": 0 }, "upside_range_at_3": { "low_cents": 0, "high_cents": 0, "low_clicks": 0, "high_clicks": 0 }, "excluded_zero_click_queries": 0, "queries": [ { "query": "string", "position": 0, "clicks": 0, "impressions": 0, "gain_cents": { "at_1": 0, "at_2": 0, "at_3": 0 } } ] } ], "insufficient_data": [ { "page_path": "string", "organic_new_customers": 0, "organic_clicks": 0, "organic_new_customer_revenue_cents": 0 } ], "insufficient_data_total": 0, "notes": [ "string" ], "is_cached": true, "age_s": 0, "last_refresh": "string"}