A gap analysis answers "what are they getting traffic for that we aren't?" The output should be a prioritized list of topics, not a raw keyword dump.
Steps
-
Confirm the competitor list. If the user hasn't named competitors, ask; don't guess. Search competitors are often not business competitors.
-
Pull each competitor's organic keywords. Call
ahrefs.organic_keywordsfor each competitor domain withmode: "domain", ordered by traffic,limit: 500. Keep the samecountryacross all calls or the comparison is meaningless. -
Pull your own coverage. Same call for the user's domain. If Search Console is connected, also pull
google_search_console.querywithdimensions: ["query"]over 28 days. It will show terms you rank for that Ahrefs missed, which prevents false "gaps". -
Compute the gap. Keywords where at least one competitor ranks in the top 10 and you rank below 20 or not at all. Weight by volume and by how many competitors rank. A term two or three competitors all cover is a validated topic, not a one-off.
-
Cluster before reporting. Group the gap keywords into topics rather than listing them individually. Fifty keywords usually collapse into five or six content themes, and that's the actionable form.
-
Report. Per cluster: the theme, total addressable volume, which competitors rank, their best position, average difficulty, and the single best head term. Then name the top 3 clusters worth pursuing and why.
Gotchas
- Ahrefs volume and traffic are estimates. Present them as directional. Never mix an Ahrefs estimate and a Search Console actual in the same column without labelling which is which.
- Set
countrydeliberately. It defaults to a single market; a US-only pull will look like a huge gap for a UK-focused competitor. - Not every gap is worth closing. Filter out terms irrelevant to the business before reporting. A competitor's unrelated blog traffic is not an opportunity.
- Check difficulty against your actual authority. Use
ahrefs.domain_overviewon both domains first. If a competitor has a far higher domain rating, their easy terms are not your easy terms.