Documentation

Everything you need to use keywordclusters.com — product guide and full REST API reference.

Getting Started

keywordclusters.com turns a seed keyword into an organised, clustered keyword list in seconds. Here's how to run your first research:

  1. Create an account (Free plan, no credit card).
  2. From the Search page, type a seed keyword (e.g. "keyword research tools").
  3. Choose one or more search engines: Google, Bing, YouTube, or Amazon.
  4. Select your locale (e.g. en-US) and click Search.
  5. Review the autocomplete suggestions with volume, CPC, competition, and keyword difficulty (KD) metrics.
  6. Keyword clusters are generated automatically — use them to plan content or ad groups.
  7. Export results as CSV or XLSX, or save keywords to a Project.

API Reference

The REST API lets Agency plan subscribers run keyword searches programmatically and poll for results. All requests go to https://keywordclusters.com.

Base URL

https://keywordclusters.com

Authentication

Every API request must include your API key in the x-api-key header. Keys are tied to an Agency plan account and have a 500-request daily limit.

Getting an API key

  1. Upgrade to the Agency plan on the Billing page ($149/month).
  2. Go to Settings and find the API Keys section.
  3. Click Create API Key. Your new token is shown once — copy and store it securely.
  4. To revoke a key, return to Settings → API Keys and click Delete.

Tokens are shown once. If you lose a key, delete it and create a new one. The platform never stores the plaintext token.

Sending the header

Pass the header on every request:

x-api-key: kc_your_token_here

Requests without a valid key — or with a key that has exceeded its daily limit — return 401 or 429.

Full examples by language

curl

curl -X POST https://keywordclusters.com/api/v1/search \
  -H "x-api-key: kc_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{"term":"keyword research","locale":"en-US","engines":["google"]}'

JavaScript / fetch

const response = await fetch("https://keywordclusters.com/api/v1/search", {
  method: "POST",
  headers: {
    "x-api-key": "kc_your_token_here",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    term: "keyword research",
    locale: "en-US",
    engines: ["google"],
  }),
});
const { jobId } = await response.json();

Python (requests)

import requests

resp = requests.post(
    "https://keywordclusters.com/api/v1/search",
    headers={"x-api-key": "kc_your_token_here"},
    json={
        "term": "keyword research",
        "locale": "en-US",
        "engines": ["google"],
    },
)
data = resp.json()
job_id = data["jobId"]

POST /api/v1/search

Starts a keyword research job. The job runs asynchronously — this endpoint returns immediately with a jobId you can poll. One request consumes one unit of your 500/day API limit.

Request

FieldTypeRequiredDescription
termstringYesSeed keyword or phrase to research.
localestringNoIETF locale tag. Default: en-US. E.g. en-GB, de-DE.
languagestringNoISO 639-1 language code. Default: en.
enginesstring[]NoWhich engines to query. Default: ["google"]. Allowed values: "google", "bing", "youtube", "amazon".
POST /api/v1/search
x-api-key: kc_your_token_here
Content-Type: application/json

{
  "term": "seo tools",
  "locale": "en-US",
  "language": "en",
  "engines": ["google", "bing"]
}

Response — 200 OK

{
  "jobId": 1842,
  "status": "pending",
  "message": "Search started"
}

Error responses

StatusBodyCause
401{ "message": "Invalid or missing API key" }Key absent, malformed, or revoked.
400{ "message": "Missing required fields" }term missing or engines is empty.
429{ "message": "API key daily limit reached", "limit": 500, "used": 500 }Daily limit exhausted. Resets at midnight UTC.

GET /api/v1/search/:jobId

Polls the status of a search job. When query.status is "completed", the keywords, clusters, and trendPredictions fields are populated. While pending they return as empty arrays / objects. Polling does not consume your daily limit.

Request

GET /api/v1/search/1842
x-api-key: kc_your_token_here

Response — pending

{
  "query": {
    "id": 1842,
    "term": "seo tools",
    "locale": "en-US",
    "language": "en",
    "engines": ["google", "bing"],
    "status": "pending",
    "createdAt": "2026-04-22T09:00:00.000Z",
    "completedAt": null
  },
  "keywords": [],
  "clusters": [],
  "trendPredictions": {}
}

Response — completed

{
  "query": {
    "id": 1842,
    "term": "seo tools",
    "locale": "en-US",
    "language": "en",
    "engines": ["google", "bing"],
    "status": "completed",
    "createdAt": "2026-04-22T09:00:00.000Z",
    "completedAt": "2026-04-22T09:00:04.123Z"
  },
  "keywords": [
    {
      "id": 9001,
      "queryId": 1842,
      "phrase": "best seo tools",
      "engine": "google",
      "volume": 14800,
      "cpc": 3.2,
      "competition": 72,
      "kd": 58,
      "trend": "up",
      "clusterId": 201,
      "createdAt": "2026-04-22T09:00:04.000Z"
    }
  ],
  "clusters": [
    {
      "id": 201,
      "queryId": 1842,
      "label": "SEO Tool Comparisons",
      "keywordCount": 12,
      "createdAt": "2026-04-22T09:00:04.000Z"
    }
  ],
  "trendPredictions": {
    "9001": {
      "id": 55,
      "phrase": "best seo tools",
      "locale": "en-US",
      "engine": "google",
      "currentVolume": 14800,
      "predictedVolume": 16200,
      "growthRate": 946,
      "trendDirection": "up",
      "confidence": 78,
      "predictionPeriod": 30
    }
  }
}

Error responses

StatusCause
401Key absent, malformed, or revoked.
404No job with that ID exists.
403The job belongs to a different account.

Polling Pattern

Searches typically complete in 3–10 seconds. Poll every 2 seconds until status is "completed" or "failed".

JavaScript — full round-trip

const API_KEY = "kc_your_token_here";
const BASE = "https://keywordclusters.com";

async function search(term, engines = ["google"], locale = "en-US") {
  // 1. Create the job
  const createRes = await fetch(`${BASE}/api/v1/search`, {
    method: "POST",
    headers: { "x-api-key": API_KEY, "Content-Type": "application/json" },
    body: JSON.stringify({ term, engines, locale }),
  });
  if (!createRes.ok) throw new Error(`Create failed: ${createRes.status}`);
  const { jobId } = await createRes.json();

  // 2. Poll until completed
  while (true) {
    await new Promise((r) => setTimeout(r, 2000));
    const pollRes = await fetch(`${BASE}/api/v1/search/${jobId}`, {
      headers: { "x-api-key": API_KEY },
    });
    if (!pollRes.ok) throw new Error(`Poll failed: ${pollRes.status}`);
    const data = await pollRes.json();
    if (data.query.status === "completed") return data;
    if (data.query.status === "failed") throw new Error("Search failed on server");
  }
}

// Usage
const result = await search("seo tools", ["google", "bing"]);
console.log(result.keywords.length, "keywords,", result.clusters.length, "clusters");

Python — full round-trip

import time
import requests

API_KEY = "kc_your_token_here"
BASE = "https://keywordclusters.com"
HEADERS = {"x-api-key": API_KEY}

def search(term, engines=None, locale="en-US"):
    engines = engines or ["google"]
    # 1. Create the job
    r = requests.post(
        f"{BASE}/api/v1/search",
        headers={**HEADERS, "Content-Type": "application/json"},
        json={"term": term, "engines": engines, "locale": locale},
    )
    r.raise_for_status()
    job_id = r.json()["jobId"]

    # 2. Poll until completed
    while True:
        time.sleep(2)
        r = requests.get(f"{BASE}/api/v1/search/{job_id}", headers=HEADERS)
        r.raise_for_status()
        data = r.json()
        status = data["query"]["status"]
        if status == "completed":
            return data
        if status == "failed":
            raise RuntimeError("Search failed on server")

result = search("seo tools", engines=["google", "bing"])
print(len(result["keywords"]), "keywords,", len(result["clusters"]), "clusters")

Rate Limits

LimitValueNotes
Requests per key per day500Each POST /api/v1/search counts as 1. Poll requests don't count.
Reset cadenceDaily, midnight UTCCounter resets to 0 each day.
Keys per accountUnlimitedEach key gets its own 500/day limit.

When a key is exhausted the API returns:

HTTP/1.1 429 Too Many Requests

{
  "message": "API key daily limit reached",
  "limit": 500,
  "used": 500
}

Your app should check for 429, surface an informative error, and retry after reset.

Response Shapes

Field-by-field reference for every object returned by GET /api/v1/search/:jobId.

query

FieldTypeNotes
idnumberNumeric job ID.
termstringThe seed keyword you submitted.
localestringIETF locale, e.g. "en-US".
languagestringISO 639-1 code, e.g. "en".
enginesstring[]Engines queried: google, bing, youtube, amazon.
statusstring"pending" | "processing" | "completed" | "failed"
errorMessagestring | nullSet if status is "failed".
createdAtISO 8601 stringWhen the job was created.
completedAtISO 8601 string | nullWhen the job finished.

keywords[]

FieldTypeNotes
idnumberUnique keyword ID.
phrasestringThe keyword string.
enginestringWhich engine returned this keyword.
volumenumber | nullMonthly search volume.
cpcnumber | nullCost-per-click in local currency, as a decimal (e.g. 3.2 = $3.20).
competitionnumber | nullCompetition score 0–100.
kdnumber | nullKeyword difficulty 0–100.
trendstring | null"up" | "down" | "stable"
clusterIdnumber | nullReferences clusters[].id, or null if unclustered.

clusters[]

FieldTypeNotes
idnumberCluster ID referenced by keywords[].clusterId.
labelstringHuman-readable cluster name (ML-generated).
keywordCountnumberNumber of keywords in this cluster.

trendPredictions

A map of keyword_id → prediction. Only present when a prediction exists for that keyword.

FieldTypeNotes
currentVolumenumber | nullCurrent monthly search volume.
predictedVolumenumber | nullPredicted volume after predictionPeriod days.
growthRatenumberGrowth percentage × 100 (e.g. 946 = +9.46%).
trendDirectionstring"up" | "down" | "stable" | "emerging"
confidencenumberConfidence score 0–100.
predictionPeriodnumberDays ahead the prediction covers (default 30).

Product Docs

Search & Metrics
  • Enter a seed keyword and choose engines
  • Volume: monthly average searches
  • CPC: cost-per-click in local currency
  • Competition: paid ad competition 0–100
  • KD: organic ranking difficulty 0–100
  • Trend: up / down / stable vs prior period
Keyword Clustering
  • Clusters are generated automatically using ML
  • Each cluster groups semantically related keywords
  • Use clusters to plan content topics or ad groups
  • View clusters in the Results page, tab-separated
  • Export clusters as separate sheets in XLSX
SERP Analysis
  • View top 10 results for a keyword
  • See title, URL, snippet, and domain
  • Understand what content is currently ranking
  • Identify content gaps and opportunities
  • Available on Starter, Pro, and Agency plans
Projects & Export
  • Create projects to organise keywords by campaign
  • Save keywords from any search to a project
  • Export as CSV for Excel/Google Sheets
  • Export as XLSX for multi-sheet workbooks
  • Export as PDF for client-ready reports

Plans & Billing

PlanPriceCredits/monthKeywords/searchAPI
Free$05050No
Starter$29/mo200500No
Pro$79/mo4002,500No
Agency$199/mo7005,000Yes — 500 req/day per key

Upgrade, downgrade, or cancel anytime from Settings → Billing. Stripe handles all payment processing — we never store card details.

Account settings, API key management, and password changes are available at Settings.

Need help?

Something unclear or missing from this doc? Open a support ticket and we'll get back to you.