Developer docs

List keyword gaps

GET/sites/{siteId}/competitors/gaps
Scope
search:read

Keyword gaps across the competitor set Per keyword each competitor's Google position and ranking page next to ours. Views: gaps (they rank, we do not), content (gaps with 1,000+ searches), lost (we rank below 10, one of them in the top 3), lead (we rank above all of them). Off-topic and competitor-brand keywords are left out (counts.hidden); include=offtopic lists them with hidden: true. Also accepted in snake_case (min_volume for minVolume).

Parameters

NameInDetails
siteIdRequiredpathstringWebsite id, from GET /sites.
viewquerygapscontentlostleaddefault gapsWhich keywords to list.
qquerystringat most 100 charactersPart of the keyword.
domainsquerystringComma-separated competitor domains, each in the set. Default: the ones the Keyword gaps table compares (the competitors that drive gaps and have data, at most three).
includequeryofftopicofftopic also lists off-topic and competitor-brand keywords.
sortqueryopportunityvolumedefault opportunityopportunity (0–100: relevance × demand × winnable difficulty) or monthly searches.
minVolumequeryintegermin 0, max 10000000Only keywords with at least this many monthly searches. Also accepted in snake_case (min_volume for minVolume).
maxDifficultyqueryintegermin 0, max 100Only keywords at most this hard (0–100; 0 = no limit).
pagequeryintegerdefault 1, min 1Page number, from 1.
perqueryintegerdefault 50, min 1, max 200Rows per page, 1 to 200.

Response

200 · application/json

FieldDetails
domainslist of string · required; The competitors compared
viewgaps | content | lost | lead · required; The view listed
sortopportunity | volume · required; The order
includeofftopic | · required; Hidden keywords included
filtersobject · required; The filters applied to the rows
filters.qstring or null · required; Search
filters.minVolumeinteger or null · required; Minimum monthly searches
filters.maxDifficultyinteger or null · required; Maximum difficulty
countsobject · required; Keywords per tab, as the screen counts them: before q, minVolume and maxDifficulty
counts.gapsinteger · required; Keywords in gaps
counts.contentinteger · required; Keywords in content
counts.lostinteger · required; Keywords in lost
counts.leadinteger · required; Keywords in lead
counts.hiddeninteger · required; Off-topic and competitor-brand keywords this view leaves out
totalinteger · required; Rows that match, over all pages
pageinteger · required; This page, from 1
perinteger · required; Rows per page
hasMoretrue or false · required; More rows after this page
rowslist of values · required
rows[].keywordstring
rows[].keywordId
rows[].locationCodenumber
rows[].locationstring
rows[].languageCodestring
rows[].device
rows[].volumenumber
rows[].difficultynumber
rows[].ourPosition
rows[].positionsobject
rows[].positions.bikeworld.examplenumber
rows[].positions.cyclehub.examplenumber
rows[].pagesobject
rows[].pages.bikeworld.examplestring
rows[].pages.cyclehub.example
rows[].opportunitynumber
rows[].relevancenumber
rows[].relevanceStatusstring
rows[].offTopictrue or false
rows[].topicstring
rows[].reasonstring
rows[].brand
rows[].hiddentrue or false
rows[].action
notestring · required; How to read the numbers
linkaddress (URL) · required; The Competitors screen in the app

Errors

StatusMeaning
400Bad request. Codes: bad_view, unknown_competitor, bad_include, bad_sort, bad_minVolume, bad_maxDifficulty, bad_page, bad_per.
401Missing, unknown or revoked key. Codes: missing_key, invalid_key.
403The key lacks the scope, covers another website, or its owner lost access. Codes: missing_scope, other_site, owner_left, no_owner, forbidden.
404Not found. Codes: not_found.
429Too many requests this hour for this key. Codes: rate_limited.

Example request

curl \
  -H "Authorization: Bearer mr_ws_…" \
  "https://app.monoranks.com/api/v1/sites/SITE_ID/competitors/gaps"

Example response

{
  "domains": [
    "bikeworld.example",
    "cyclehub.example"
  ],
  "view": "gaps",
  "sort": "opportunity",
  "include": null,
  "filters": {
    "q": null,
    "minVolume": null,
    "maxDifficulty": null
  },
  "counts": {
    "gaps": 318,
    "content": 42,
    "lost": 17,
    "lead": 64,
    "hidden": 23
  },
  "total": 318,
  "page": 1,
  "per": 50,
  "hasMore": true,
  "rows": [
    {
      "keyword": "tubeless gravel tires",
      "keywordId": null,
      "locationCode": 2840,
      "location": "United States",
      "languageCode": "en",
      "device": null,
      "volume": 1900,
      "difficulty": 28,
      "ourPosition": null,
      "positions": {
        "bikeworld.example": 4,
        "cyclehub.example": 9
      },
      "pages": {
        "bikeworld.example": "https://bikeworld.example/tires/tubeless/",
        "cyclehub.example": null
      },
      "opportunity": 74,
      "relevance": 90,
      "relevanceStatus": "reviewed",
      "offTopic": false,
      "topic": "Tires",
      "reason": "Acme Bikes sells tubeless gravel tires.",
      "brand": null,
      "hidden": false,
      "action": null
    }
  ],
  "note": "Views: gaps (they rank, we do not), content, lost, lead.",
  "link": "https://app.monoranks.com/sites/3f6c2a1e-8b4d-4c7a-9e21-5d0b7a6f4c13/competitors"
}

The MCP server does the same with the tool competitor_gaps.