SERP Clustering API
Use cases
A FastAPI service that clusters keywords based on common organic result URLs from ValueSERP CSV exports.
Builds link and query intersection maps, pairs queries sharing a configurable minimum number of common URLs (default 4), then groups them into numbered clusters sorted by overlap count.
Returns JSON with cluster arrays, total cluster count, and threshold used.
Platform
Python script (requires Python 3.x)
Input
ValueSERP batch export CSV (must contain search.q and result.organic_results.link columns)
Output
JSON object containing serp_clusters array, total_clusters count, and common_urls_threshold.
Features
- REST API with Swagger UI and ReDoc auto-documentation
- Configurable common_urls threshold (default 4)
- Expects ValueSERP columns: search.q and result.organic_results.link
- Deduplicates and lowercases queries before clustering
- JSON response with cluster ID, similar_query, queries array, and common URLs list
- Docker and gunicorn deployment examples included
How to use
- 1 Start the server with uvicorn app:app --reload (runs on port 8000)
- 2 POST a ValueSERP CSV to /cluster-serps with optional common_urls parameter
- 3 Receive JSON response with clustered keyword groups and shared URLs
Frequently asked questions
- Where does the input CSV come from and what must it contain?
- It is built for ValueSERP batch exports, which flatten the JSON into dotted column names. Only two columns are read: search.q (the query) and result.organic_results.link (each ranking URL), one row per query-URL pair. Any other columns in the file are ignored, but those two names must match exactly or the request fails.
- Why does a keyword only ever appear in one cluster?
- Clustering is greedy: once a query has been paired into a cluster it is marked processed and excluded from all later comparisons. A keyword whose SERP overlaps several groups joins whichever it is compared against first, so the result is order-dependent and borderline keywords can land in different clusters if you change or reorder the input set.
- How should I choose the common_urls threshold?
- It is the minimum number of identical organic URLs two queries must share to be clustered, defaulting to 4. Matching is on exact URL strings after deduplication, so with top-10 SERPs the default requires roughly 40 percent overlap. Lower it for looser clusters, raise it if unrelated keywords are being merged, and scale it up if your export contains more than 10 results per query.
- Will it handle very large keyword sets?
- The algorithm compares every query against every other query in memory, so runtime grows quadratically with the number of unique queries. Small and mid-sized exports return quickly; for very large sets expect the request to take noticeably longer rather than fail.
- Is the API safe to expose publicly?
- There is no authentication, rate limiting or file size restriction built in; anyone who can reach the endpoint can upload CSVs. Run it locally, behind a reverse proxy with auth, or on a private network. The README includes Docker and gunicorn examples for deployment.
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
Cluster keywords by semantic similarity using sentence-transformers embeddings.
Convert marketing-heavy H1 headings into clean, natural search queries using Claude.
Suggest a cleaner representative keyword for each keyword using an LLM.
Visualise tagged keyword CSVs as interactive D3.js zoomable circle packing charts.
Tag keywords using substring matching against up to 7 classification columns.
Test if a URL is allowed or blocked by robots.txt rules.
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.
Tell Me What You Need