Toggle Theme

AI Keyword Clustering: Turn Search Queries into Content Series and Internal Links

Easton editorial illustration: one large rounded CLUSTER MAP board with grouped query chips and visible intent separation

"Google Search Central: Creating helpful, reliable, people-first content"

You have a keywords.csv file with 300 queries spanning Astro, Docker, and Cloudflare. The model produces 42 clusters, but a manual review finds astro seo and astro vs next.js for seo in cluster #1. The first query calls for a tutorial; the second calls for a comparison. One page is unlikely to satisfy both jobs.

That is the practical failure mode in keyword clustering: a model can merge phrases that are semantically close but carry different intent. The result increases the risk of content cannibalization, with several near-duplicate pages competing for the same demand. A list of “keyword groups” also does not tell you which groups need a new article, an update to an old post, an FAQ, or an internal link.

The workflow below starts by combining GSC queries, topic cards, and your content inventory. It normalizes and deduplicates the rows, keeps human review after the model’s first pass, and maps every cluster to an action: new article, old-post refresh, FAQ, internal link, or discard. The deliverables are the input schema, normalization logic, method comparison, AI prompt, cluster map, action framework, and internal-link structure.

1. Start the Keyword-Clustering Workflow with the Right Inputs

The input is not a list of phrases invented by AI. It is your own query/page data, candidate-topic cards, and content inventory. Together, these sources show which topics are worth covering, which already have a page, and which reflect real community questions.

Use this source checklist:

SourceFieldsHow to get itWhat to watch
GSC query/page dataquery, page, clicks, impressions, CTR, positionSearch Console UI / Search Analytics APIAPI rowLimit defaults to 1,000 and allows up to 25,000 per request; internal limits mean it returns top rows rather than a guaranteed complete set
Topic cardstitle, intent, source (Reddit/GitHub/competitor), evidenceTopic-research agent outputReview source quality manually
Content inventoryarticle title, URL, series, publication date, traffic, ranking queriesSite database / CMSMark matching old posts and series ownership
quickWins metricshigh-impression low-CTR queries, refresh opportunitiesGSC quickWins analysisUse them to support the refresh decision

Steps:

  1. Export GSC query/page data. The Performance report defaults to the last three months, but you can choose a range that fits the task.
  2. Merge the topic cards produced by the research agent.
  3. Extract the content inventory: existing articles, series, and performance.
  4. Flag quick wins: high-impression low-CTR queries and old-post refresh opportunities.
  5. Produce a combined table where every row includes the query, initial intent, source, matching old post, and quick-win flag.

2. Normalize Keywords Before You Cluster Them

The merged table will contain duplicates, close variants, and spelling differences. If you skip normalization, the model can treat them as separate keywords and split one intent into several clusters.

Deduplication checklist:

  • Exact duplicate: astro seo vs astro seo → keep one row
  • Spelling or configuration variants: docker host.docker.internal vs docker host-gateway vs docker 127.0.0.1 → mark as a same-intent candidate and wait for human confirmation
  • Synonyms: cloudflare pricing vs cloudflare 价格 vs cloudflare cost → mark as one intent
  • Entity inflection: astro blog vs astro blogs → mark as one intent

Normalization rules:

  • Standardize terms: nextjs → next.js, cloudflare workers → Cloudflare Workers
  • Standardize casing: Astro vs astro → astro
  • Standardize punctuation: astro, seo vs astro seo → astro seo

Initial intent labels:

  • Informational: how to, what is, guide, tutorial
  • Navigational: brand name, product name, specific URL
  • Comparative: vs, compare, alternative
  • Transactional: pricing, cost, buy, download

Steps:

  1. Remove exact duplicates from the combined table.
  2. Detect spelling variants and synonyms, and flag them as same-intent candidates.
  3. Normalize terminology, casing, and punctuation.
  4. Give every query an initial intent label: informational, navigational, comparative, or transactional.
  5. Output a normalized table with query, normalized_query, intent_tag, source, and old_post_match.

3. Compare Three Keyword-Clustering Methods

The method needs to balance cost, accuracy, and risk. The three common approaches fit different stages of a content operation.

MethodCostAccuracyBest fitRisk
SERP-basedHigh: many SERP queries and possible anti-bot limitsHigh: uses actual results and helps evaluate whether pages should be combinedLive content, page-overlap decisions, and a SERP API budgetExpensive; changing SERPs reduce stability
SemanticLow: only embedding API callsMedium: can miss real search intent and merge different jobsEarly topic maps, limited budgets, and a fast first passMay merge phrases that are related in meaning but different in intent
HybridMedium: semantic first pass + SERP/GSC validation + human reviewHigh: balances cost and accuracyOngoing content operations with GSC data and review timeRequires human-review capacity

Recommended workflow:

  • Small team / early site: semantic first pass + GSC/page validation + human review of risky clusters
  • Larger team / established content: hybrid clustering with semantic grouping, SERP/GSC validation, and human review
  • Sufficient budget + page-overlap decision: SERP-based clustering + human review

I use the hybrid option: semantic similarity creates the first grouping, GSC page data shows which queries already have a landing page, and a reviewer resolves intent conflicts.

4. Run AI-Assisted Clustering with a Defined Output

When you send the normalized keywords to a model, the prompt needs explicit fields and intent rules. This is the prompt structure I use.

AI prompt example:

You are an SEO content planner. Group the normalized keywords below into clusters by search intent. For each cluster, provide:
1. primary_intent
2. canonical_page (recommended target type: new article / old post refresh / FAQ / discard)
3. suggested_action
4. internal_link_targets (existing articles or series that should receive links)
5. risk_notes (possible cannibalization or required human review)

Keywords:
- astro seo
- astro vs next js for seo
- cloudflare pricing
- docker host.docker.internal
- docker host-gateway
...

Return a JSON array. Each cluster must follow:
{
  "cluster_id": 1,
  "keywords": ["astro seo", ...],
  "primary_intent": "informational - tutorial",
  "canonical_page": "new article",
  "suggested_action": "Create an Astro SEO tutorial",
  "internal_link_targets": ["astro-guide series", "cloudflare-bindui series"],
  "risk_notes": "Human review required: astro vs next js for seo has comparison intent and should not be merged"
}

Example cluster map:

cluster_idkeywordsprimary_intentcanonical_pagesuggested_actioninternal_link_targetsrisk_notes
1astro seo, astro blog seoInformational - tutorialnew articleCreate an Astro SEO tutorialastro-guide series, cloudflare-bindui seriesNone
2astro vs next js for seoComparativenew articleCreate an Astro vs Next.js SEO comparisonastro-guide series, nextjs-blog-seriesNone
3cloudflare pricing, cloudflare cost, cloudflare 价格Transactionalold post refreshRefresh the existing Cloudflare pricing articlecloudflare-bindui seriesExisting /cloudflare-pricing post; refresh it
4docker host.docker.internal, docker host-gateway, docker 127.0.0.1Informational - configurationFAQAdd an FAQ to a Docker-series articledocker-practice seriesSame-intent variants; merge into an FAQ

Human-review checklist:

  • Mixed intent: a cluster contains both tutorial and comparison queries → split it
  • Existing page conflict: a cluster maps to “new article,” but a related page already exists → change the action to old-post refresh or FAQ
  • Over-splitting: one intent appears in several clusters → merge them
  • Over-merging: the model puts different intents in one cluster → split it

Steps:

  1. Send the normalized table to the AI clustering tool: Claude, ChatGPT, or an internal model workflow.
  2. Run the prompt above for the first pass.
  3. Export the cluster map.
  4. Review intent conflicts, old-post matches, over-splitting, and over-merging.
  5. Correct the map and flag high-risk clusters.

5. Map Every Cluster to One Content Action

A finished cluster needs an operational action, not another list of keywords. This is the decision table I use.

Decision factorNew articlePillar pageOld-post refreshFAQInternal-link updateDiscard
Query countMany (5+)Many (5+)Few (1–3)Few (1–3)Few (1–3)One
Intent variationHighHighLowLowLowLow
Matching old postNoneNoneYesYesYesYes
CompetitionHighHighMediumMediumLowLow
Topical fitHighHighHighMediumMediumLow
Room for original valueHighHighLowLowLowNone
Exampleastro seo tutorialastro seriescloudflare pricingdocker host.docker.internallinks between related postsbrand-name variant

Action definitions:

  • New article: create one page that covers every same-intent query in the cluster.
  • Pillar page: create a series hub that links to the other pages in the cluster.
  • Old-post refresh: extend an existing page to cover the new queries.
  • FAQ: add a focused answer to an existing article.
  • Internal-link update: add contextual links that point to the canonical page.
  • Discard: do not create content; mark the query as low value or outside the target audience.

Steps:

  1. Score each cluster against the decision factors.
  2. Map the score to an action.
  3. Export an action list in the form cluster_id → suggested_action.
  4. Manually review high-risk actions: new articles and pillar pages.

The query counts in the table are example signals, not hard thresholds. The final action still depends on intent, existing inventory, original value, and maintenance cost.

Relationships between clusters should become executable internal links, not a generic “related reading” block. This is the link-planning structure I use.

Internal-link principles:

  • Bidirectional pillar/cluster links: the pillar links to every cluster page, and every cluster page links back to the pillar.
  • Descriptive anchor text: describe the target intent instead of writing “click here.”
  • Canonical targets: do not link to duplicate or near-duplicate pages; point links to the preferred canonical page.
  • No orphaned articles: plan at least one contextual inbound link for every article, then add more routes when the site structure and reader journey support them.
  • internal_link_targets in the cluster map: record which existing articles or series should receive a link.

Internal-link plan:

cluster_idpillar_pagecluster_pagesinternal_link_targetsSuggested anchor text
1Complete Astro SEO guideastro seo tutorial, astro blog seoastro-guide series, cloudflare-bindui series“Astro SEO optimization,” “Cloudflare performance optimization”
2-astro vs next.js for seoastro-guide series, nextjs-blog-series“Astro vs Next.js comparison”
3-cloudflare pricingcloudflare-bindui series“Cloudflare pricing explained”

Steps:

  1. Identify the pillar and cluster pages.
  2. Design the bidirectional link structure.
  3. Choose descriptive anchor text for every link.
  4. Check for orphaned articles.
  5. Export the internal-link plan to the content task table.

Google currently treats redirects and rel="canonical" as strong canonicalization signals and sitemap inclusion as a weaker signal. The signals can reinforce one another, but Google still chooses the canonical. Internal links should consistently point to the URL you prefer as canonical.

7. Set Quality Gates Before Clustering Becomes a Page Generator

Keyword clustering should not become a bulk page generator. That pattern can quickly diverge from people-first content principles.

Risk boundaries:

  • Do not create one page per keyword variant. Queries with the same intent should converge on one page or canonical target.
  • Require an original-value decision. Every cluster must map back to a reader problem, the site’s focus, and a meaningful addition rather than a rewrite of existing material.
  • Consolidate same-intent queries around a canonical. For duplicate or very similar pages, redirects, rel="canonical", and sitemaps can express a preference, but the signals have different strengths and do not guarantee Google’s selection.
  • Avoid search-engine-first content. The main purpose must be helping readers rather than manipulating rankings.
  • Reduce cannibalization risk. Publishing many pages for nearly identical keywords can cause several URLs to compete for the same intent.
  • Flag risky clusters. Use the cluster map’s risk_notes field to require human review.

Quality red lines:

  • When a matching old post exists, prefer a refresh or FAQ over another near-duplicate page.
  • Every clustering output must include topical fit and original-value judgments.
  • Internal links should point to the canonical article rather than duplicate or near-duplicate pages.

8. Walk Through Astro SEO, Cloudflare Pricing, and Docker Examples

Three scenarios make the workflow concrete.

Example 1: astro seo vs astro vs next.js for seo (different intent, so split them)

  • Raw queries: astro seo, astro vs next.js for seo, astro blog seo
  • Normalized: astro seo, astro vs next js for seo, astro blog seo
  • AI first pass: cluster_id=1, keywords=[astro seo, astro vs next js for seo, astro blog seo]
  • Human review: astro seo has tutorial intent; astro vs next js for seo has comparison intent, so they must be separated.
  • Final cluster map:
    • cluster_id=1: [astro seo, astro blog seo] → create an Astro SEO tutorial
    • cluster_id=2: [astro vs next js for seo] → create an Astro vs Next.js SEO comparison

Example 2: cloudflare pricing (an old page exists, so refresh it)

  • Raw queries: cloudflare pricing, cloudflare cost, cloudflare 价格
  • Normalized: cloudflare pricing, cloudflare pricing, cloudflare pricing
  • AI first pass: cluster_id=3, keywords=[cloudflare pricing, cloudflare pricing, cloudflare pricing]
  • Inventory match: an existing /cloudflare-pricing article
  • Final cluster map:
    • cluster_id=3: [cloudflare pricing, cloudflare cost, cloudflare 价格] → refresh /cloudflare-pricing

Example 3: docker host.docker.internal (normalize related technical queries)

  • Raw queries: docker host.docker.internal, docker host-gateway, docker 127.0.0.1
  • Normalized: flag them as a candidate group for the same configuration intent.
  • AI first pass: cluster_id=4, keywords=[docker host.docker.internal, docker host-gateway, docker 127.0.0.1]
  • Inventory match: an existing Docker series
  • Final cluster map:
    • cluster_id=4: [docker host.docker.internal, docker host-gateway, docker 127.0.0.1] → after human intent validation, add an FAQ or section to a Docker-series article

9. Hand the Content Map to the Next Workflow

Once clustering is complete, move the cluster map into the content task table and define its fields, scoring, state machine, and publishing schedule. The next article in the series, “Designing a Content Task Table: Fields, Scores, States, and Publishing Plans,” covers that step.

For turning a cluster map into a usable outline, continue with “AI Outline Generation: From Cluster Map to Draftable Outline.” The later article “Automated Internal Linking: Batch Link Generation and Common Traps” covers link insertion in detail.

Old-post refresh logic has its own guide: “GSC Content Refresh Strategy: From Quick Wins to Updates.”

Related articles already published:

Turn Keywords into an Actionable Content Map

A minimal workflow from multi-source inputs to a cluster map, content actions, and an internal-link plan.

⏱️ Estimated time: 60 min

  1. 1

    Step 1: Combine the three input sources

    Put GSC query/page data, topic cards, and your existing article inventory in one table. Keep the source, matching post, and quick-win flag for each row.
  2. 2

    Step 2: Normalize the keywords

    Resolve duplicates, spelling variants, synonyms, casing, and punctuation, then label each query as informational, navigational, comparative, or transactional.
  3. 3

    Step 3: Run the semantic first pass

    Ask the model to group queries by intent and return primary_intent, canonical_page, suggested_action, internal_link_targets, and risk_notes for every cluster.
  4. 4

    Step 4: Validate high-risk clusters

    Use GSC page data, selected SERP results, and human judgment to catch mixed tutorial/comparison intent, conflicts with old posts, over-merging, and over-splitting.
  5. 5

    Step 5: Assign one primary action

    Map each cluster to a new article, pillar page, old-post refresh, FAQ, internal-link update, or discard, and record the reason.
  6. 6

    Step 6: Produce the internal-link plan

    Define pillar-to-cluster links, canonical targets, and descriptive anchor text, then check for orphaned articles and duplicate-page risk.

FAQ

Should keyword clustering group similar phrases or shared search intent?
Group by search intent, not similarity alone. A head term and long-tail variants with the same intent can share a page. Tutorial, comparison, navigational, and transactional intents usually need separate treatment.
When does a keyword deserve its own article instead of an H2 or FAQ in an existing post?
Check the intent gap, matching old content, topical fit, and room for original value. If an existing page already serves the intent, update it, add an H2 or FAQ, or improve its links. Create a new article only when the query represents a distinct job and no suitable page exists.
Can GSC queries, Reddit questions, GitHub issues, and competitor titles live in one clustering table?
Yes, as long as the source remains visible and each source has a different role. GSC shows existing search demand, community questions add natural phrasing, and competitor titles are only competitive research. Normalize and review all of them before clustering.
Why does AI merge semantically similar keywords with different intent?
Semantic models are good at recognizing related entities and wording, but they do not always infer the page format a searcher expects. `astro seo` suggests a tutorial, while `astro vs next.js for seo` suggests a comparison, so the workflow still needs intent labels, GSC or SERP checks, and human review.
How should I choose between SERP-based, semantic, and hybrid clustering?
For an early project or a limited budget, start with semantic grouping and correct it with GSC page data and human review. Use a hybrid workflow when you have an established site and recurring data. Add SERP-based checks when result overlap is important and you can afford the queries.
Should I create a new page when an older post already covers the topic?
First decide whether the old post can naturally serve the same intent. If it can, update the body, add an FAQ, or improve internal links. Create a separate page only when the target intent and page job are clearly different and you can add substantial original value.
Can keyword clustering turn into low-value programmatic page generation?
Yes. Every cluster therefore needs a reader problem, topical-fit check, original-value judgment, and human approval. Do not create a page for every keyword variant, and do not treat an AI-generated cluster map as an automatic publishing queue.

12 min read · Published on: Nov 13, 2026

Comments

Sign in with GitHub to leave a comment

Easton BlogEaston Blog