SpyFu SEO Research API API
The SEO Research API API from SpyFu — 17 operation(s) for seo research api.
The SEO Research API API from SpyFu — 17 operation(s) for seo research api.
openapi: 3.0.3
info:
title: Account Account API SEO Research API API
version: v2
servers:
- url: https://api.spyfu.com/apis/accounts_api
security:
- Basic_Authentication_Token: []
- Query_Parameter_Token: []
- HMAC_Authentication_Header: []
tags:
- name: SEO Research API
paths:
/v2/seo/getMostValuableKeywords:
get:
operationId: OrganicSerpApi_GetMostValuableKeywords_GET
summary: Get Most Valuable Keywords
description: 'Returns keywords that generate the highest organic click volume for a domain. This endpoint identifies the most traffic-driving keywords to reveal a domain''s most valuable SEO assets and content opportunities.
[Visualize this API live on SpyFu](https://www.spyfu.com/seo/keywords/domain?includeAnyTerm=true&includeAnyUrl=true&searchType=mostvaluable&sidebarContext=filters&query=example.com)'
parameters:
- name: query
in: query
description: Domain, URL, subdomain, or path to analyze. Accepts full domains (example.com), complete URLs (https://example.com/blog), subdomains (blog.example.com), specific paths (example.com/products/), or individual pages.
required: true
schema:
type: string
example: example.com/blog
example: example.com/blog
- name: compareDomain
in: query
description: Domain to compare against when evaluating where it outranks you and where you outrank it.
schema:
type: string
example: competitor.com
example: competitor.com
- name: includeTerms
in: query
description: Comma-separated list of terms that must be present in the keyword.
schema:
type: string
example: hosting,domain,website
- name: includeAnyTerm
in: query
description: 'Used with includeTerms. If true: match any term (OR). If false: require all terms (AND).'
schema:
type: boolean
default: false
example: false
- name: excludeTerms
in: query
description: Comma-separated list of terms to exclude from results (e.g., branded or irrelevant terms).
schema:
type: string
example: free,cheap,discount
- name: excludeHomepageKeywords
in: query
description: If true, exclude keywords where the domain/URL's homepage (root domain, e.g., example.com) ranks; if false, include all.
schema:
type: boolean
default: false
example: false
example: false
- name: searchVolume.min
in: query
description: Filter to keywords where monthly search volume (Google) is ≥ this value.
schema:
type: number
format: float
example: 1000
example: 1000
- name: searchVolume.max
in: query
description: Filter to keywords where monthly search volume (Google) is ≤ this value.
schema:
type: number
format: float
example: 50000
example: 50000
- name: keywordDifficulty.min
in: query
description: Filter to keywords where the keyword difficulty score is ≥ this value (0-100; higher = harder to rank).
schema:
type: number
format: float
example: 30
example: 30
- name: keywordDifficulty.max
in: query
description: Filter to keywords where the keyword difficulty score is ≤ this value (0-100; higher = harder to rank).
schema:
type: number
format: float
example: 70
example: 70
- name: rank.min
in: query
description: Filter to keywords where the domain/URL rank position is ≥ this value (1 = best/top organic result).
schema:
type: number
format: float
example: 1
example: 1
- name: rank.max
in: query
description: Filter to keywords where the domain/URL rank position is ≤ this value (1 = best/top organic result).
schema:
type: number
format: float
example: 10
example: 10
- name: rankChange.min
in: query
description: Filter to keywords where the domain/URL improved by at least this many positions vs. the previous month (rank_change ≥ value). Positive values mean moved up; negative values mean moved down.
schema:
type: number
format: float
example: 5
example: 5
- name: rankChange.max
in: query
description: Filter to keywords where the month-over-month rank change is at most this many positions (rank_change ≤ value). Positive values mean moved up; negative values mean moved down.
schema:
type: number
format: float
example: 20
example: 20
- name: costPerClick.min
in: query
description: Filter to keywords where the average cost per click (CPC) is ≥ this value.
schema:
type: number
format: float
example: 1
example: 1
- name: costPerClick.max
in: query
description: Filter to keywords where the average cost per click (CPC) is ≤ this value.
schema:
type: number
format: float
example: 10
example: 10
- name: costPerClickOption
in: query
description: Match type for CPC filtering. Broad = includes variations/related terms; Exact = exact keyword only; Phrase = contains the keyword phrase in order (with additional words allowed).
schema:
type: string
enum:
- Broad
- Exact
- Phrase
x-enumDescriptions:
Broad: Includes keyword variations and related terms
Exact: Requires precise keyword match only
Phrase: Includes the keyword phrase in order with additional words
example: Broad
example: Broad
- name: seoClicks.min
in: query
description: Filter to keywords where estimated monthly organic clicks (SEO clicks) to the domain/url are ≥ this value.
schema:
type: number
format: float
example: 100
example: 100
- name: seoClicks.max
in: query
description: Filter to keywords where estimated monthly organic clicks (SEO clicks) to the domain/url are ≤ this value.
schema:
type: number
format: float
example: 1000
example: 1000
- name: seoClicksChange.min
in: query
description: Filter to keywords where the month-over-month change in estimated organic clicks is ≥ this value. Positive values indicate click gains; negative values indicate click losses.
schema:
type: number
format: float
example: 10
example: 10
- name: seoClicksChange.max
in: query
description: Filter to keywords where the month-over-month change in estimated organic clicks is ≤ this value. Positive values indicate click gains; negative values indicate click losses.
schema:
type: number
format: float
example: 500
example: 500
- name: percentMobileSearches.min
in: query
description: Filter to keywords where the mobile search share (%) is ≥ this value (range 0-100).
schema:
type: number
format: float
example: 50
example: 50
- name: percentMobileSearches.max
in: query
description: Filter to keywords where the mobile search share (%) is ≤ this value (range 0-100).
schema:
type: number
format: float
example: 80
example: 80
- name: percentDesktopSearches.min
in: query
description: Filter to keywords where the desktop search share (%) is ≥ this value (range 0-100).
schema:
type: number
format: float
example: 20
example: 20
- name: percentDesktopSearches.max
in: query
description: Filter to keywords where the desktop search share (%) is ≤ this value (range 0-100).
schema:
type: number
format: float
example: 50
example: 50
- name: percentNotClicked.min
in: query
description: Filter to keywords where the percentage of searches with no click is ≥ this value (range 0-100).
schema:
type: number
format: float
example: 10
example: 10
- name: percentNotClicked.max
in: query
description: Filter to keywords where the percentage of searches with no click is ≤ this value (range 0-100).
schema:
type: number
format: float
example: 30
example: 30
- name: percentPaidClicks.min
in: query
description: Filter to keywords where the share of SERP clicks going to paid ads (%) is ≥ this value (range 0-100).
schema:
type: number
format: float
example: 20
example: 20
- name: percentPaidClicks.max
in: query
description: Filter to keywords where the share of SERP clicks going to paid ads (%) is ≤ this value (range 0-100).
schema:
type: number
format: float
example: 60
example: 60
- name: percentOrganicClicks.min
in: query
description: Filter to keywords where the share of SERP clicks going to organic results (%) is ≥ this value (range 0-100).
schema:
type: number
format: float
example: 40
example: 40
- name: percentOrganicClicks.max
in: query
description: Filter to keywords where the share of SERP clicks going to organic results (%) is ≤ this value (range 0-100).
schema:
type: number
format: float
example: 80
example: 80
- name: monthlyCost.min
in: query
description: Filter to keywords where the estimated monthly advertising cost is ≥ this value.
schema:
type: number
format: float
example: 100
example: 100
- name: monthlyCost.max
in: query
description: Filter to keywords where the estimated monthly advertising cost is ≤ this value.
schema:
type: number
format: float
example: 5000
example: 5000
- name: monthlyCostOption
in: query
description: Match type for monthly cost filtering. Broad = includes variations/related terms; Exact = exact keyword only; Phrase = contains the keyword phrase in order (with additional words allowed).
schema:
type: string
enum:
- Broad
- Exact
- Phrase
x-enumDescriptions:
Broad: Includes keyword variations and related terms
Exact: Requires precise keyword match only
Phrase: Includes the keyword phrase in order with additional words
example: Broad
example: Broad
- name: paidCompetitors.min
in: query
description: Filter to keywords where the number of distinct advertisers observed over the last 14 months is ≥ this value.
schema:
type: number
format: float
example: 5
example: 5
- name: paidCompetitors.max
in: query
description: Filter to keywords where the number of distinct advertisers observed over the last 14 months is ≤ this value.
schema:
type: number
format: float
example: 50
example: 50
- name: rankingHomepages.min
in: query
description: Filter to keywords where the number of homepage/root-domain URLs in the top 100 results is ≥ this value.
schema:
type: number
format: float
example: 2
example: 2
- name: rankingHomepages.max
in: query
description: Filter to keywords where the number of homepage/root-domain URLs in the top 100 results is ≤ this value.
schema:
type: number
format: float
example: 10
example: 10
- name: totalMonthlyClicks.min
in: query
description: Filter to keywords where total monthly SERP clicks (all domains) are ≥ this value. Independent of rank; includes both organic and paid clicks.
schema:
type: number
format: float
example: 1000
example: 1000
- name: totalMonthlyClicks.max
in: query
description: Filter to keywords where total monthly SERP clicks (all domains) are ≤ this value. Includes both organic and paid clicks.
schema:
type: number
format: float
example: 10000
example: 10000
- name: adCount.min
in: query
description: Filter to keywords where the number of distinct advertisers observed over the last 14 months is ≥ this value.
schema:
type: number
format: float
example: 3
example: 3
- name: adCount.max
in: query
description: Filter to keywords where the number of distinct advertisers observed over the last 14 months is ≤ this value.
schema:
type: number
format: float
example: 25
example: 25
- name: pageSize
in: query
description: The maximum number of rows returned.
schema:
type: integer
format: int32
default: 5
maximum: 10000
minimum: 1
example: 5
example: 5
- name: countryCode
in: query
description: Country market to search. Specifically, this maps to the Google domain version to query against (e.g., google.com for US, google.de for Germany, etc.). <a href='https://developer.spyfu.com/reference/adhistoryapi_getdomainadhistory_get#/'>All Countries</a>
schema:
type: string
default: US
enum:
- AR
- AT
- AU
- BE
- BR
- CA
- CH
- DE
- DK
- ES
- FR
- IE
- IN
- IT
- JP
- MX
- NL
- 'NO'
- NZ
- PL
- PT
- SE
- SG
- TR
- UA
- UK
- US
- ZA
example: US
example: US
- name: sortBy
in: query
description: Column to sort results by.
schema:
type: string
default: SearchVolume
enum:
- SearchVolume
- KeywordDifficulty
- Rank
- RankChange
- SeoClicks
- SeoClicksChange
- PercentMobileSearches
- PercentDesktopSearches
- PercentNotClicked
- PercentPaidClicks
- PercentOrganicClicks
- BroadCostPerClick
- ExactCostPerClick
- PhraseCostPerClick
- BroadMonthlyCost
- ExactMonthlyCost
- PhraseMonthlyCost
- TotalMonthlyClicks
- PaidCompetitors
- RankingHomepages
x-enumDescriptions:
SearchVolume: Number of searches done this past month on Google (or within selected country). Blended from multiple sources for better snapshot of search activity
KeywordDifficulty: SEO ranking difficulty score (0-100 scale, higher = more difficult to rank). Based on domain strength, on-page signals like 'keyword in title,' and number of .gov/.edu domains
Rank: Organic search result position (1 = top organic result)
RankChange: Change in organic position from previous data update (positive values indicate ranking improvement; negative values indicate moving further down the SERP).
SeoClicks: Estimated number of organic clicks the domain gets from ranking on this keyword
SeoClicksChange: Change in estimated organic clicks from previous data update
PercentMobileSearches: Percentage breakdown of searches from mobile vs desktop devices
PercentDesktopSearches: Percentage breakdown of searches from desktop vs mobile devices
PercentNotClicked: Rate that searchers leave the SERP without clicking any result
PercentPaidClicks: Percentage of SERP clicks that went to paid ads
PercentOrganicClicks: Percentage of SERP clicks that went to organic results
BroadCostPerClick: Average amount advertisers pay per click for broad match ads on this keyword
ExactCostPerClick: Average amount advertisers pay per click for exact match ads on this keyword
PhraseCostPerClick: Average amount advertisers pay per click for phrase match ads on this keyword
BroadMonthlyCost: Estimated monthly advertising spend for broad match bidding
ExactMonthlyCost: Estimated monthly advertising spend for exact match bidding
PhraseMonthlyCost: Estimated monthly advertising spend for phrase match bidding
TotalMonthlyClicks: Total estimated clicks made on this SERP to any paid or organic results
PaidCompetitors: Total number of advertisers seen over the last 6 months for this keyword
RankingHomepages: Number of homepage URLs (vs deeper paths) ranking within first 100 results
example: SearchVolume
example: SearchVolume
- name: sortOrder
in: query
description: Order to sort the results.
schema:
type: string
default: Descending
enum:
- Ascending
- Descending
example: Descending
example: Descending
- name: startingRow
in: query
description: Row number to start the results with.
schema:
type: integer
format: int32
default: 1
maximum: 10000
minimum: 1
example: 1
example: 1
- name: adultFilter
in: query
description: Exclude adult keywords considered unsafe for work.
schema:
type: boolean
default: true
example: true
example: true
- name: onlyAdultKeywords
in: query
description: Only include adult keywords considered unsafe for work.
schema:
type: boolean
default: false
example: false
example: false
- name: exactMatch
in: query
description: "Indicates whether to apply exact match filtering for the query.\r\nThis parameter will result in **only** exact matches,\r\nmeaning protocols (http/https) and trailing slashes **must** be included.\r\nFor example, a query of \"https://example.com/blog\" will not match\r\n- \"example.com/blog\"\r\n- \"https://example.com/blog/\""
schema:
type: boolean
responses:
'200':
description: Successfully retrieved the most valuable keywords by organic click volume. Returns a paginated list of keywords prioritized by traffic value and search data.
content:
application/json:
schema:
description: Response wrapper containing organic SERP keyword results with comprehensive SEO metrics and pagination metadata.
type: object
properties:
resultCount:
description: Number of results returned
type: integer
format: int32
readOnly: true
example: 100
results:
description: Array of organic search keywords with comprehensive SEO metrics including rankings, click estimates, and SERP analysis data.
type: array
items:
type: object
properties:
keyword:
description: The keyword for which this domain ranks organically in the top 100 search results.
type: string
readOnly: true
nullable: true
example: running shoes
topRankedUrl:
description: The highest ranking URL from this domain for this specific keyword.
type: string
readOnly: true
nullable: true
example: https://example.com/best-running-shoes
rank:
description: Current organic search position for this keyword (1 = top position).
type: integer
format: int32
readOnly: true
example: 7
rankChange:
description: Change in ranking position since the previous measurement period (positive values indicate ranking improvement; negative values indicate moving further down the SERP).
type: integer
format: int32
readOnly: true
nullable: true
example: -3
searchVolume:
description: Monthly search volume for this keyword based on Google search data across the selected country/region.
type: integer
format: int64
readOnly: true
nullable: true
example: 700000
keywordDifficulty:
description: SEO difficulty score (1-100) indicating how challenging it would be to rank organically for this keyword, with 100 being most difficult.
type: integer
format: int32
readOnly: true
example: 69
broadCostPerClick:
description: Average cost per click for broad match advertising on this keyword.
type: number
format: double
readOnly: true
nullable: true
example: 0.28
phraseCostPerClick:
description: Average cost per click for phrase match advertising on this keyword.
type: number
format: double
readOnly: true
nullable: true
example: 0.28
exactCostPerClick:
description: Average cost per click for exact match advertising on this keyword. These costs fluctuate depending on many factors, so keep that in mind when you are estimating larger budgets.
type: number
format: double
readOnly: true
nullable: true
example: 0.28
seoClicks:
description: Estimated monthly organic clicks this domain receives from this keyword based on current ranking position.
type: integer
format: int64
readOnly: true
example: 3000
seoClicksChange:
description: Change in estimated organic clicks compared to the previous measurement period.
type: integer
format: int64
readOnly: true
nullable: true
example: -600
totalMonthlyClicks:
description: Total number of clicks (organic and paid combined) on search results for this keyword in the past month.
type: integer
format: int64
readOnly: true
nullable: true
example: 647000
percentMobileSearches:
description: Percentage of searches for this keyword that come from mobile devices.
type: number
format: double
readOnly: true
nullable: true
example: 0.4
percentDesktopSearches:
description: Percentage of searches for this keyword that come from desktop devices.
type: number
format: double
readOnly: true
nullable: true
example: 0.6
percentNotClicked:
description: Percentage of searches where users leave the SERP without clicking any result.
type: number
format: double
readOnly: true
nullable: true
example: 0.075
percentPaidClicks:
description: Percentage of total SERP clicks that go to paid ads.
type: number
format: double
readOnly: true
nullable: true
example: 0.079
percentOrganicClicks:
description: Percentage of total SERP clicks that go to organic search results.
type: number
format: double
readOnly: true
nullable: true
example: 0.921
broadMonthlyCost:
description: 'Estimated monthly advertising cost for broad match bidding on this keyword from the #2 position.'
type: number
format: double
readOnly: true
nullable: true
example: 6043.5
phraseMonthlyCost:
description: 'Estimated monthly advertising cost for phrase match bidding on this keyword from the #2 position.'
type: number
format: double
readOnly: true
nullable: true
example: 5695.5
exactMonthlyCost:
description: 'Estimated monthly advertising cost for exact match bidding on this keyword from the #2 position.'
type: number
format: double
readOnly: true
nullable: true
example: 5392.5
paidCompetitors:
description: Total number of advertisers observed purchasing ads for this keyword over the last 14 months.
type: integer
format: int32
readOnly: true
nullable: true
example: 0
rankingHomepages:
description: Number of domain homepages (vs. deeper pages) ranking in the top 100 organic results for this keyword.
type: integer
format: int32
readOnly: true
nullable: true
example: 10
yourRank:
description: The comparison domain's organic search position for this keyword (1 = top organic result). This field represents the rank of the domain specified in the 'compareDomain' parameter, allowing direct comparison with the primary query domain's rank.
type: integer
format: int32
nullable: true
example: 5
yourRankChange:
description: Change in the comparison domain's organic position from the previous data update. Positive values indicate the comparison domain moved up in rankings; negative values indicate it moved down. This shows how the comparison domain's performance has changed over time.
type: integer
format: int32
nullable: true
example: -3
yourUrl:
description: The specific URL from the comparison domain that ranks for this keyword. This shows which page on the comparison domain is competing for this search term, providing insights into their content strategy.
type: string
readOnly: true
nullable: true
example: https://comparedomain.com/blog
additionalProperties: false
description: Represents an organic search keyword with comprehensive SEO metrics including rankings, click estimates, costs, and SERP analysis data.
readOnly: true
nullable: true
totalMatchingResults:
description: Total number of organic keywords available that match the query criteria, including results not included in the current page.
type: integer
format: int64
readOnly: true
example: 75000
additionalProperties: false
'400':
description: Bad Request - Invalid parameters provided (e.g., invalid domain format, pageSize exceeds maximum, or invalid country code)
'401':
description: Unauthorized - Invalid API credentials or insufficient permissions to access SEO keyword data
'500':
description: Internal Server Error - A server-side error occurred while processing the request
tags:
- SEO Research API
/v2/seo/getNewlyRankedKeywords:
get:
operationId: OrganicSerpApi_GetNewlyRankedKeywords_GET
summary: Get Newly Ranked Keywords
description: 'Returns keywords where a domain recently achieved rankings in the top 100 organic search results. This endpoint identifies fresh ranking opportunities to reveal new content successes and emerging SEO momentum.
[Visualize this API live on SpyFu](https://www.spyfu.com/seo/keywords/domain?includeAnyTerm=true&includeAnyUrl=true&searchType=newlyranked&sidebarContext=filters&query=example.com)'
parameters:
- name: query
in: query
description: Domain, URL, subdomain, or path to analyze. Accepts full domains (example.com), complete URLs (https://example.com/blog), subdomains (blog.example.com), specific paths (example.com/products/), or individual pages.
required: true
schema:
type: string
example: example.com/blog
example: example.com/blog
- name: compareDomain
in: query
description: Domain to compare against when evaluating where it outranks you and where you outrank it.
schema:
type: string
example: competitor.com
example: competitor.com
- name: includeTerms
in: query
description: Comma-separated list of terms that must be present in the keyword.
schema:
type: string
example: hosting,domain,website
- name: includeAnyTerm
in: query
description: 'Used with includeTerms. If true: match any term (OR). If false: require all terms (AND).'
schema:
type: boolean
default: false
example: false
- name: excludeTerms
in: query
description: Comma-separated list of terms to
# --- truncated at 32 KB (402 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/spyfu/refs/heads/main/openapi/spyfu-seo-research-api-api-openapi.yml