Developer docs

List content ideas

GET/sites/{siteId}/competitors/content-ideas
Scope
search:read

Content ideas: keyword gaps grouped by topic The keyword gaps (competitors rank, we do not; off-topic and competitor-brand keywords left out) grouped by topic, most opportunity first; topic null holds keywords not reviewed yet. suggestion: new_page (no page of ours ranks in the topic), expand (ourPages already rank in it) or review. Reads the stored monthly gap refresh: no new lookups. Also accepted in snake_case (min_volume for minVolume).

Parameters

NameInDetails
siteIdRequiredpathstringWebsite id, from GET /sites.
domainsquerystringComma-separated competitor domains, each in the set. Default: the competitors that drive gaps.
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).
keywordsqueryintegerdefault 5, min 1, max 50Top keywords listed per topic.
pagequeryintegerdefault 1, min 1Page number, from 1.
perqueryintegerdefault 20, min 1, max 200Topics per page, 1 to 200.

Response

200 · application/json

FieldDetails
domainslist of string · required; The competitors compared
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
gapKeywordsinteger · required; Gap keywords over all topics
hiddenKeywordsinteger · required; Off-topic and competitor-brand keywords left out
topicslist of object · required
topics[].topicstring or null · required; The topic; null: keywords not reviewed yet
topics[].keywordsinteger · required; Gap keywords in the topic
topics[].volumeinteger · required; Monthly searches summed (estimate)
topics[].opportunityinteger · required; Sum of the keywords' opportunity
topics[].bestOpportunityinteger · required; The highest keyword opportunity, 0–100
topics[].avgDifficultyinteger or null · required; Average difficulty, 0–100
topics[].suggestionnew_page | expand | review · required; What to do
topics[].ourPageslist of object · required; Our pages already ranking in the topic (at most 5)
topics[].ourPages[].urlstring · required; Page address
topics[].ourPages[].pathstring · required; Path of the address
topics[].ourPages[].keywordsinteger · required; Keywords of the topic it ranks for
topics[].competitorPageslist of object · required; Competitor pages ranking for most of the topic (at most 5)
topics[].competitorPages[].urlstring · required; Page address
topics[].competitorPages[].pathstring · required; Path of the address
topics[].competitorPages[].keywordsinteger · required; Keywords of the topic it ranks for
topics[].toplist of object · required; The best keywords of the topic
topics[].top[].keywordstring · required; The search phrase
topics[].top[].volumeinteger or null · required; Monthly searches (estimate)
topics[].top[].difficultyinteger or null · required; How hard it is to rank, 0–100
topics[].top[].opportunityinteger · required; 0–100
topics[].top[].relevanceinteger or null · required; Fit with the website, 0–100
topics[].top[].positionsobject · required; Each competitor's Google position, by domain
topics[].top[].positions.bikeworld.examplenumber
topics[].top[].positions.cyclehub.examplenumber
topics[].top[].pagesobject · required; Each competitor's ranking page, by domain
topics[].top[].pages.bikeworld.examplestring
topics[].top[].pages.cyclehub.example
notestring · required; How to read the numbers
linkaddress (URL) · required; The Competitors screen in the app

Errors

StatusMeaning
400Bad request. Codes: unknown_competitor, bad_keywords, 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/content-ideas"

Example response

{
  "domains": [
    "bikeworld.example",
    "cyclehub.example"
  ],
  "total": 12,
  "page": 1,
  "per": 20,
  "hasMore": false,
  "gapKeywords": 318,
  "hiddenKeywords": 23,
  "topics": [
    {
      "topic": "Tires",
      "keywords": 24,
      "volume": 18400,
      "opportunity": 1210,
      "bestOpportunity": 74,
      "avgDifficulty": 31,
      "suggestion": "expand",
      "ourPages": [
        {
          "url": "https://acmebikes.com/tires/gravel/",
          "path": "/tires/gravel/",
          "keywords": 6
        }
      ],
      "competitorPages": [
        {
          "url": "https://bikeworld.example/tires/tubeless/",
          "path": "/tires/tubeless/",
          "keywords": 9
        }
      ],
      "top": [
        {
          "keyword": "tubeless gravel tires",
          "volume": 1900,
          "difficulty": 28,
          "opportunity": 74,
          "relevance": 90,
          "positions": {
            "bikeworld.example": 4,
            "cyclehub.example": 9
          },
          "pages": {
            "bikeworld.example": "https://bikeworld.example/tires/tubeless/",
            "cyclehub.example": null
          }
        }
      ]
    }
  ],
  "note": "Keyword gaps grouped by topic, most opportunity first.",
  "link": "https://app.monoranks.com/sites/3f6c2a1e-8b4d-4c7a-9e21-5d0b7a6f4c13/competitors"
}

The MCP server does the same with the tool content_ideas.