Un outil de détection des lacunes de mots-clés SEO recherche une liste de mots-clés cibles, identifie ceux pour lesquels les concurrents sont classés dans le top 10 alors que votre domaine n'apparaît pas, et fournit les lacunes sous forme d'opportunités de contenu exploitables.
Prérequis
- Python 3.9+
- Clé API Scavio
Parcours
Étape 1: Définissez votre domaine et vos concurrents
Configurez les domaines que vous souhaitez comparer.
YOUR_DOMAIN = "yoursite.com"
COMPETITOR_DOMAINS = ["competitor1.com", "competitor2.com", "competitor3.com"]
KEYWORDS = [
"project management software",
"task tracker for teams",
"agile board online",
"kanban tool free",
"sprint planning tool"
]Étape 2: Recherchez chaque mot-clé et extrayez les positions
Pour chaque mot-clé, vérifiez si votre domaine et vos concurrents apparaissent dans les 20 premiers résultats.
import requests
API_KEY = "your-scavio-api-key"
def get_positions(keyword: str, domains: list) -> dict:
r = requests.post(
"https://api.scavio.dev/api/v1/search",
json={"query": keyword, "num_results": 20},
headers={"x-api-key": API_KEY},
timeout=15
)
r.raise_for_status()
results = r.json().get("organic_results", [])
positions = {}
for domain in domains:
pos = next((i + 1 for i, res in enumerate(results) if domain in res.get("link","")), None)
positions[domain] = pos
return positionsÉtape 3: Identifiez les lacunes de mots-clés
Une lacune est un mot-clé pour lequel au moins un concurrent se classe dans le top 10 mais pas votre domaine.
def find_gaps(keywords: list, your_domain: str, competitor_domains: list) -> list:
all_domains = [your_domain] + competitor_domains
gaps = []
for kw in keywords:
positions = get_positions(kw, all_domains)
your_pos = positions.get(your_domain)
competitor_positions = {d: positions.get(d) for d in competitor_domains}
top10_competitors = [d for d, p in competitor_positions.items() if p and p <= 10]
if top10_competitors and (not your_pos or your_pos > 10):
gaps.append({
"keyword": kw,
"your_position": your_pos or "not ranking",
"competitors_ranking": {d: competitor_positions[d] for d in top10_competitors}
})
return gaps
gaps = find_gaps(KEYWORDS, YOUR_DOMAIN, COMPETITOR_DOMAINS)
for g in gaps:
print(f"GAP: {g['keyword']} | You: {g['your_position']} | {g['competitors_ranking']}")Exemple Python
import requests
from datetime import date
API_KEY = "your-scavio-api-key"
YOUR_DOMAIN = "yoursite.com"
COMPETITORS = ["asana.com", "monday.com", "clickup.com"]
KEYWORDS = [
"project management software", "task tracker for teams",
"agile board online", "kanban tool free",
"sprint planning tool", "team task management"
]
def get_positions(keyword, domains):
r = requests.post("https://api.scavio.dev/api/v1/search",
json={"query": keyword, "num_results": 20},
headers={"x-api-key": API_KEY}, timeout=15)
r.raise_for_status()
results = r.json().get("organic_results", [])
return {d: next((i+1 for i, res in enumerate(results) if d in res.get("link","")), None)
for d in domains}
def find_gaps(keywords, your_domain, competitors):
all_domains = [your_domain] + competitors
gaps, covered = [], []
for kw in keywords:
pos = get_positions(kw, all_domains)
your_pos = pos[your_domain]
comp_top10 = {d: pos[d] for d in competitors if pos.get(d) and pos[d] <= 10}
if comp_top10 and (not your_pos or your_pos > 10):
gaps.append({"keyword": kw, "your_position": your_pos or "NR",
"gap_competitors": comp_top10})
elif your_pos and your_pos <= 10:
covered.append({"keyword": kw, "position": your_pos})
return {"gaps": gaps, "covered": covered}
if __name__ == "__main__":
result = find_gaps(KEYWORDS, YOUR_DOMAIN, COMPETITORS)
print(f"Keyword Gap Analysis — {YOUR_DOMAIN} — {date.today()}")
print(f"\nGAPS ({len(result['gaps'])} keywords — content opportunities):")
for g in result["gaps"]:
comp_str = ", ".join(f"{d}@{p}" for d, p in g["gap_competitors"].items())
print(f" {g['keyword']:<35} | You: {str(g['your_position']):<12} | {comp_str}")
print(f"\nCOVERED ({len(result['covered'])} keywords — protect these):")
for c in result["covered"]:
print(f" {c['keyword']:<35} | Position {c['position']}")Exemple JavaScript
const API_KEY = 'your-scavio-api-key';
const YOUR_DOMAIN = 'yoursite.com';
const COMPETITORS = ['asana.com', 'monday.com'];
const KEYWORDS = ['project management software', 'task tracker for teams', 'kanban tool free'];
async function getPositions(keyword, domains) {
const res = await fetch('https://api.scavio.dev/api/v1/search', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'x-api-key': API_KEY },
body: JSON.stringify({ query: keyword, num_results: 20 })
});
const data = await res.json();
const results = data.organic_results ?? [];
return Object.fromEntries(domains.map(d => [d, (results.findIndex(r => r.link?.includes(d)) + 1) || null]));
}
for (const kw of KEYWORDS) {
const positions = await getPositions(kw, [YOUR_DOMAIN, ...COMPETITORS]);
const yourPos = positions[YOUR_DOMAIN];
const compTop10 = COMPETITORS.filter(d => positions[d] && positions[d] <= 10);
if (compTop10.length && (!yourPos || yourPos > 10)) {
console.log(`GAP: ${kw} | You: ${yourPos ?? 'NR'} | Competitors: ${compTop10.join(', ')}`);
}
}Sortie attendue
Keyword Gap Analysis - yoursite.com - 2026-05-22
GAPS (4 keywords - content opportunities):
project management software | You: NR | asana.com@2, monday.com@5
agile board online | You: NR | clickup.com@3
kanban tool free | You: 14 | asana.com@1, monday.com@7
sprint planning tool | You: NR | clickup.com@4, asana.com@8
COVERED (2 keywords - protect these):
task tracker for teams | Position 6
team task management | Position 9