Skip to main content
Cluster keywords by SERP similarity, detect search intent, and track rankings — all programmatically.
Full endpoint reference available on Swagger.

Quick Start

Create a clustering order with the minimum required parameters:
import os
import requests

API_KEY = os.environ["KWI_API_KEY"]
BASE_URL = "https://api.keywordinsights.ai"
HEADERS = {"X-API-Key": API_KEY}

payload = {
    "project_name": "My first cluster",
    "keywords": ["keyword clustering", "keyword grouping", "cluster keywords"],
    "search_volumes": [2300, 1200, 900],
    "language": "en",
    "location": "United States",
    "insights": ["cluster", "context"],
    "folder_id": "<your_folder_id>",
}

response = requests.post(
    f"{BASE_URL}/api/keywords-insights/order/",
    headers=HEADERS,
    json=payload,
)

data = response.json()
print(data)
# {"status": true, "order_id": "2879fa0b-...", "cost": 150}

Endpoints

MethodPathDescription
POST/api/keywords-insights/order/Create a clustering order
GET/api/keywords-insights/order/?order_id={id}Check order status
GET/api/keywords-insights/order/json/{order_id}/Get results as JSON (paginated)
GET/api/keywords-insights/order/xlsx/{order_id}/Export results as XLSX
GET/api/keywords-insights/orders/?n_orders={n}List recent orders
GET/api/keywords-insights/order/cost/?n_keywords={n}&insights=clusterEstimate cost
GET/api/keywords-insights/languages/Supported languages
GET/api/keywords-insights/locations/Supported locations

Parameters

Required

ParameterTypeDescription
project_namestringName shown in the dashboard
keywordsstring[]List of keywords to cluster (min 5, max 200,000)
search_volumesnumber[]Search volume per keyword (same length as keywords)
languagestringLanguage code (e.g. en). See /api/keywords-insights/languages/
locationstringLocation name (e.g. United States). See /api/keywords-insights/locations/
insightsstring[]Insight types: cluster, context, rank
folder_idstringDashboard folder ID to save the project into. Retrieve from the browser URL in the KWI dashboard

Optional

ParameterTypeDefaultDescription
clustering_methodstringvolumevolume or agglomerative
grouping_accuracyinteger4SERP overlap threshold (1–7). Higher = stricter clusters
hub_creation_methodstringmediumTopical cluster similarity: soft, medium, hard
devicestringdesktopSERP device: desktop, mobile, tablet
mobile_typestringiphone or android (when device is mobile)
tablet_typestringipad or android (when device is tablet)
urlstringDomain URL for ranking. Required when rank is in insights

Insight Types

The insights array controls what analysis runs:
  • cluster — Groups keywords by SERP similarity. Required for all clustering orders.
  • context — Detects search intent (informational, commercial, transactional, navigational).
  • rank — Tracks your domain’s ranking for each keyword. Requires the url parameter.
Full clustering order:
"insights": ["cluster", "rank", "context"]
Intent-only order (no clustering, just intent classification):
"insights": ["context"]

Customizations

Clustering Method

  • volume (default) — Groups keywords based on shared SERP URLs. Controlled by grouping_accuracy (1 = loose, 7 = strict). Best for most use cases.
  • agglomerative — Uses hierarchical clustering for larger keyword sets. Better for discovering broader topic relationships.

Topical Clusters

The hub_creation_method controls how tightly related keywords must be to form a topical cluster:
  • soft — Broad grouping, more keywords per topical cluster
  • medium — Balanced (recommended)
  • hard — Strict grouping, fewer but more focused clusters

Checking Order Status

Orders process asynchronously. Poll the status endpoint until status is "done":
import os
import requests

API_KEY = os.environ["KWI_API_KEY"]
BASE_URL = "https://api.keywordinsights.ai"
HEADERS = {"X-API-Key": API_KEY}

order_id = "2879fa0b-deae-4aab-ad87-fd8fb8db9717"

response = requests.get(
    f"{BASE_URL}/api/keywords-insights/order/",
    headers=HEADERS,
    params={"order_id": order_id},
)

data = response.json()
print(data["status"])    # "confirmed", "processing", or "done"
print(data["progress"])  # 0.0 to 1.0
When the order is complete, the response includes download links:
{
  "status": "done",
  "progress": 1.0,
  "order_id": "2879fa0b-...",
  "results_files": {
    "xlsx": "https://api.keywordinsights.ai/api/keywords-insights/order/xlsx/2879fa0b-.../",
    "google_sheets": "https://docs.google.com/spreadsheets/d/.../copy"
  }
}

Retrieving Results as JSON

Get paginated cluster data:
import os
import requests

API_KEY = os.environ["KWI_API_KEY"]
BASE_URL = "https://api.keywordinsights.ai"
HEADERS = {"X-API-Key": API_KEY}

order_id = "2879fa0b-deae-4aab-ad87-fd8fb8db9717"

response = requests.get(
    f"{BASE_URL}/api/keywords-insights/order/json/{order_id}/",
    headers=HEADERS,
    params={
        "page_size": 50,
        "page_number": 1,
        "sort_by": "search_volume",
        "ascending": False,
    },
)

data = response.json()
clusters = data["result"]["payload"]["clusters"]

for cluster in clusters:
    print(f"{cluster['name']}{cluster['number_of_keywords']} keywords, vol: {cluster['search_volume']}")
JSON results query parameters:
ParameterTypeDefaultDescription
page_sizeinteger50Results per page (max 1,000)
page_numberinteger1Page number
sort_bystringsearch_volumeSort field (e.g. search_volume, keyword, cluster_id)
ascendingbooleanfalseSort direction
filter_idstringFilter ID from the filters endpoint

Exporting as XLSX

Download results as an Excel file:
import os
import requests

API_KEY = os.environ["KWI_API_KEY"]
BASE_URL = "https://api.keywordinsights.ai"
HEADERS = {"X-API-Key": API_KEY}

order_id = "2879fa0b-deae-4aab-ad87-fd8fb8db9717"

response = requests.get(
    f"{BASE_URL}/api/keywords-insights/order/xlsx/{order_id}/",
    headers=HEADERS,
)

# Save the XLSX file
with open("clusters.xlsx", "wb") as f:
    f.write(response.content)

Estimating Cost

Check how many credits an order will cost before creating it:
response = requests.get(
    f"{BASE_URL}/api/keywords-insights/order/cost/",
    headers=HEADERS,
    params={"n_keywords": 500, "insights": ["cluster", "context"]},
)

print(response.json())  # {"cost": 1000}
Cost per keyword by insight combination:
InsightsCost per keyword
cluster only1 credit
cluster + context2 credits
cluster + rank2 credits
cluster + context + rank3 credits

Complete Example

End-to-end workflow: create an order, wait for completion, and download results.
import os
import time
import requests

API_KEY = os.environ["KWI_API_KEY"]
BASE_URL = "https://api.keywordinsights.ai"
HEADERS = {"X-API-Key": API_KEY}


def create_order(keywords, volumes):
    """Create a clustering order."""
    response = requests.post(
        f"{BASE_URL}/api/keywords-insights/order/",
        headers=HEADERS,
        json={
            "project_name": "API automation example",
            "keywords": keywords,
            "search_volumes": volumes,
            "language": "en",
            "location": "United States",
            "insights": ["cluster", "context"],
            "folder_id": "<your_folder_id>",
            "clustering_method": "volume",
            "grouping_accuracy": 4,
            "hub_creation_method": "medium",
        },
    )
    response.raise_for_status()
    return response.json()


def wait_for_completion(order_id):
    """Poll until the order is done."""
    while True:
        response = requests.get(
            f"{BASE_URL}/api/keywords-insights/order/",
            headers=HEADERS,
            params={"order_id": order_id},
        )
        data = response.json()
        print(f"Status: {data['status']} ({data['progress']:.0%})")

        if data["status"] == "done":
            return data

        time.sleep(30)


def get_results(order_id):
    """Fetch all clusters as JSON."""
    response = requests.get(
        f"{BASE_URL}/api/keywords-insights/order/json/{order_id}/",
        headers=HEADERS,
        params={"page_size": 100, "page_number": 1},
    )
    response.raise_for_status()
    return response.json()


# --- Run ---

keywords = ["best running shoes", "running shoes review", "top sneakers for running"]
volumes = [12000, 8500, 3200]

result = create_order(keywords, volumes)
order_id = result["order_id"]
print(f"Order created: {order_id} (cost: {result['cost']} credits)")

wait_for_completion(order_id)

data = get_results(order_id)
for cluster in data["result"]["payload"]["clusters"]:
    print(f"  {cluster['name']}{cluster['number_of_keywords']} kw, vol: {cluster['search_volume']}")