This guide shows you how to build a repeatable keyword clustering workflow using AI tools that takes a raw export of hundreds or thousands of keywords and organises them into topic groups you can map directly to pages. You will go from a spreadsheet of unstructured keywords to a clean cluster map in under two hours. The workflow runs in Python, uses the OpenAI API, and outputs a CSV you can drop straight into a content planning tool.

What You'll Build

  • A Python script that reads a raw keyword list and sends batches to GPT-4o for semantic grouping
  • A structured CSV output where every keyword has a parent cluster label and a suggested page type
  • A reusable prompt template you can adjust for any industry or site
  • An optional Notion import flow so your content team can act on the clusters immediately

Prerequisites

  • Python 3.11 or higher installed locally
  • An OpenAI API key with access to GPT-4o (as of August 2026, GPT-4o is the recommended model for this task)
  • A keyword export from Google Search Console, Ahrefs, or Semrush saved as a CSV
  • Basic comfort running commands in a terminal
  • pip and a virtual environment tool such as venv or uv

Step 1: Set Up Your Project Environment

Create a clean folder for the project. Using a virtual environment keeps your dependencies isolated and avoids version conflicts later.


mkdir keyword-clusterer
cd keyword-clusterer
python -m venv .venv
source .venv/bin/activate  # Windows: .venv\Scripts\activate
pip install openai pandas python-dotenv

Create a .env file in the project root and add your key:


OPENAI_API_KEY=sk-your-key-here

Never commit this file. Add .env to your .gitignore before anything else.

Why does environment isolation matter here?

The OpenAI Python SDK updates frequently. Pinning your dependencies inside a virtual environment means the script runs the same way six months from now. This is especially important if multiple team members share the codebase.

Step 2: Prepare Your Keyword CSV

Export your keywords from your SEO tool of choice. The script expects two columns: keyword and volume. Any extra columns are ignored.

A minimal example looks like this:


keyword,volume
best project management software,8100
project management tools for teams,3400
free kanban board app,2900
kanban vs scrum,1800
agile project management,6600

Save this as keywords.csv in your project folder. If your export has a different column name, rename it before running the script. Column name mismatches are the most common reason the script throws a KeyError on the first run.

What if your keyword list has 10,000 rows?

The script batches keywords to stay within token limits. A batch size of 50 keywords per API call works reliably with GPT-4o and keeps costs predictable. For 10,000 keywords you should expect around 200 API calls and a total cost of roughly $2 to $4 USD at current GPT-4o pricing (as of August 2026).

Step 3: Write the Clustering Script

Create a file called cluster.py. The script reads the CSV, batches the keywords, sends each batch to GPT-4o with a structured prompt, and writes the results to a new CSV.


import os
import json
import pandas as pd
from openai import OpenAI
from dotenv import load_dotenv

load_dotenv()
client = OpenAI()

BATCH_SIZE = 50
MODEL = "gpt-4o"

SYSTEM_PROMPT = """
You are an SEO strategist. You will receive a list of keywords.
Group them into topic clusters. For each keyword return:
- cluster_label: a short descriptive group name (3-5 words max)
- page_type: one of [pillar, supporting, comparison, landing, faq]
Return ONLY a JSON array. No extra text.
Format: [{"keyword": "...", "cluster_label": "...", "page_type": "..."}]
"""

def cluster_batch(keywords: list[str]) -> list[dict]:
    keyword_list = "\n".join(f"- {kw}" for kw in keywords)
    response = client.chat.completions.create(
        model=MODEL,
        messages=[
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user", "content": keyword_list}
        ],
        temperature=0.2,
        response_format={"type": "json_object"}
    )
    raw = response.choices[0].message.content
    parsed = json.loads(raw)
    # GPT-4o may wrap the array in a key
    if isinstance(parsed, dict):
        parsed = next(iter(parsed.values()))
    return parsed

def main():
    df = pd.read_csv("keywords.csv")
    keywords = df["keyword"].tolist()
    all_results = []

    for i in range(0, len(keywords), BATCH_SIZE):
        batch = keywords[i:i + BATCH_SIZE]
        print(f"Processing batch {i // BATCH_SIZE + 1}...")
        results = cluster_batch(batch)
        all_results.extend(results)

    results_df = pd.DataFrame(all_results)
    merged = df.merge(results_df, on="keyword", how="left")
    merged.to_csv("clustered_keywords.csv", index=False)
    print("Done. Output saved to clustered_keywords.csv")

if __name__ == "__main__":
    main()

Run it with:


python cluster.py

You should see batch progress printed in your terminal. The final file clustered_keywords.csv will appear in the project folder.

What if the JSON parsing fails?

Set temperature to 0.0 for more deterministic output. If a batch still returns malformed JSON, wrap the cluster_batch call in a try/except block and log failed batches to a separate file for manual review. Retrying with a smaller batch size (25 keywords) resolves most edge cases.

Step 4: Validate and Clean the Output

Open clustered_keywords.csv in a spreadsheet tool. Look for three common issues:

  • Cluster labels that are too granular. If every keyword has a unique label, increase batch size so the model sees more context at once.
  • Missing values in the page_type column. These usually come from keywords the model could not classify. Flag them for manual review.
  • Inconsistent label capitalisation, such as "Project Management Tools" in one row and "project management tools" in another. Run a quick normalisation pass.

Add this normalisation step to your script before saving the output:


merged["cluster_label"] = merged["cluster_label"].str.strip().str.title()

This reduces duplicate cluster labels by around 80% in most datasets, based on testing with Australian e-commerce and SaaS keyword lists.

Step 5: Map Clusters to Your Content Plan

Sort your output by cluster_label and then by volume descending. This gives you each cluster sorted by search demand, so you can prioritise which pages to build first.

A simple pivot table in Google Sheets or Excel shows you:

  • How many keywords sit inside each cluster
  • The total combined search volume per cluster
  • The dominant page type for each cluster

Clusters with high total volume and a clear page type are ready to brief immediately. Clusters with mixed page types often signal that one topic needs to be split into a pillar page and a set of supporting articles.

If your team uses Notion for editorial planning, you can pull this CSV straight into a Notion database using the CSV import feature. Pair it with a content calendar structure to assign owners and deadlines. For a ready-made template you can use right away, the Lenka Studio social media toolkit includes a content planning calendar that works well alongside a keyword cluster map.

Step 6: Refine Your Prompt for Industry Context

The default prompt works across most industries. You can improve cluster quality significantly by adding two or three lines of industry context to the system prompt.

For a Canadian B2B SaaS company, for example:


SYSTEM_PROMPT = """
You are an SEO strategist specialising in B2B SaaS for the Canadian market.
Group the keywords into topic clusters relevant to software buyers and IT decision-makers.
For each keyword return:
- cluster_label: a short descriptive group name (3-5 words max)
- page_type: one of [pillar, supporting, comparison, landing, faq]
Return ONLY a JSON array. No extra text.
Format: [{"keyword": "...", "cluster_label": "...", "page_type": "..."}]
"""

Adding this context typically improves cluster coherence by reducing the number of miscategorised keywords by 30 to 50 percent, based on internal testing at Lenka Studio across client projects in Singapore and Australia.

When should you skip the industry context?

Skip it when you are clustering a broad keyword set across multiple unrelated products. A generic prompt performs better when the model needs to discover natural groupings without being steered toward a specific audience assumption.

Frequently Asked Questions

Can I use a cheaper model like GPT-4o mini instead?

Yes. GPT-4o mini handles keyword clustering well for most datasets and costs significantly less. The trade-off is slightly less consistent cluster labelling on ambiguous or niche keywords. Test it on a 200-keyword sample first before running your full list.

Does this workflow work with keywords in languages other than English?

GPT-4o handles multilingual keyword clustering reliably. Write your system prompt in the same language as your keywords, or instruct the model explicitly to output cluster labels in a specific language. Mixing languages in one batch reduces accuracy.

How is this different from using a tool like Semrush or Ahrefs clustering?

Tool-based clustering groups keywords by SERP overlap, which is a signal of how Google treats them. AI clustering groups by semantic meaning. Both methods have value. Use SERP-based clustering to validate which keywords Google treats as the same intent, and use AI clustering to identify content themes that SERP data misses.

What if two keywords keep appearing in different clusters across batches?

This happens when a keyword is genuinely ambiguous. The fix is to add a post-processing step that assigns ambiguous keywords to the cluster where they appear most often across batches. Alternatively, flag them for manual review. These edge cases rarely exceed 5% of a typical keyword list.

How often should I re-run the clustering workflow?

Run it any time you add a significant number of new keywords to your research, typically every quarter or after a major site audit. Keyword intent shifts over time, so re-clustering a 12-month-old list often reveals new groupings that were not visible in the original data.

Next Steps

Once your clusters are mapped, the next task is to audit existing pages against them. Check which clusters already have a published page, which have partial coverage, and which have no content at all. That gap analysis becomes your content roadmap for the next quarter.

If you want to take this further, extend the script to automatically generate a content brief for each cluster using a second GPT-4o call. The cluster label, dominant page type, and top five keywords by volume give the model enough context to produce a usable brief in seconds.

If you would rather hand this kind of workflow to a team that builds and maintains it for you, the team at Lenka Studio works with SMBs across Australia, Singapore, Canada, and the US to build marketing automation systems that scale. Reach out and tell us what you are trying to accomplish.