Search Results Clustering
Use cases
Clusters keywords by shared organic URLs, either from uploaded SERP export CSVs or by fetching live SERPs from the DataForSEO Google organic endpoint (top 10 results, estimated at $0.002 per keyword).
The CLI script offers three algorithm options: connected components (DFS grouping), cliques (all members pairwise connected), or core-based (seed queries with configurable connectivity threshold), and scores clusters 0-100 using shared URLs + connectivity bonus + size bonus minus overlap penalty.
The hosted Streamlit app implements connected components only.
Platform
Browser-based (no installation required)
Input
SERP export CSVs (query and URL columns), or a keyword list plus DataForSEO login and password for live fetching
Output
CSV with clusters and consolidation scores
Features
- Hosted app: connected components clustering with shared URLs slider (1-10, default 4)
- CSV upload or live SERP fetching via DataForSEO (top 10 results per keyword)
- CLI script: three strategies (connected, cliques, core) or all at once
- Consolidation scoring 0-100 with recommendation bands
- Core strategy connectivity threshold (default 0.7, CLI only)
- Overlap detection and scoring penalty across clusters (CLI only)
- Clusters named after the shortest query; unclustered keywords kept as NO_CLUSTER
How to use
- 1 Export SERP data as query and URL pairs, or prepare a keyword list plus DataForSEO credentials for live fetching
- 2 Hosted app: upload CSVs (first column is read as the query, second as the URL) or fetch live SERPs
- 3 CLI script: place Batch_Results_*.csv files (with search.q and result.organic_results.link columns) in the serp_exports folder, or pass --keywords-file with credentials
- 4 Set the minimum shared URLs threshold (default 4)
- 5 Run clustering and review clusters sorted by consolidation score
- 6 Download the results CSV
Frequently asked questions
- What exact input format is required?
- In CSV mode the Python script reads CSVs named Batch_Results_*.csv from a serp_exports folder and requires two columns with the exact headers 'search.q' and 'result.organic_results.link' (the format SERP batch exports use). The hosted Streamlit app is more forgiving: it takes whatever files you upload and uses the first column as the query and the second as the URL, ignoring header names. Both the script and the app can instead fetch live SERPs from DataForSEO when you supply a keyword list and credentials.
- Are all three clustering strategies available in the hosted app?
- No. The Streamlit app implements connected components only, with a shared URLs slider (1 to 10, default 4). The cliques and core strategies, the CLUSTERING_STRATEGY setting and the overlap penalty exist only in the downloadable Python script.
- What does live SERP fetching cost?
- Live mode calls the DataForSEO Google organic endpoint once per keyword, fetching the top 10 results, at an estimated $0.002 per keyword. Credentials go in via the sidebar (app) or the --login and --password flags or DATAFORSEO_LOGIN and DATAFORSEO_PASSWORD environment variables (script). CSV mode uses no API at all.
- Why does the same keyword appear in several rows of the script output?
- With CLUSTERING_STRATEGY = 'all' (the default) the script runs all three strategies and outputs every cluster from each, so one keyword can appear up to three times under different cluster_type values. Set the strategy to 'connected', 'cliques' or 'core' if you want one row per keyword.
- How is the 0-100 consolidation score calculated?
- Base score of up to 40 from average shared URLs (average x 4, capped), plus connectivity x 30 (the share of keyword pairs in the cluster that actually meet the URL threshold), plus a size bonus of 5 points per keyword beyond two (capped at 20), minus an overlap penalty of 5 per query that sits in multiple clusters (capped at 10, script only). 80+ is a strong consolidation candidate, under 20 means keep separate.
- How are clusters named and what does NO_CLUSTER mean?
- Each cluster takes the shortest query in it as its name. Queries that share fewer than the threshold number of URLs with every other query are still included in the output, assigned to NO_CLUSTER with a score of 0 and the recommendation 'Keep separate', so the output always contains your full keyword list.
Want me to run this for you?
I run this tool as a managed service, or build something custom around your data. You get the insights without touching the code.
Related Tools
Automatically group keywords by semantic similarity using Python and ML.
Remove near-duplicate keywords, keeping the first occurrence in file order.
Extract MPNs, keyphrases, and calculate optimal bid adjustments from Google Ads data.
Group similar keywords using PolyFuzz TF-IDF fuzzy matching at scale.
Discover new category opportunities by extracting n-grams from product titles.
Calculate percentage changes between two values quickly.
Need something built for your business?
This tool started as bespoke client work. I build custom scripts, data pipelines, and full apps for SEO and product data problems that off-the-shelf tools don't solve.
Book a Call