Guide technique SEO local prêt-production : pratiques avancées

Guide technique SEO local prêt-production
En 60–120 minutes, posez une base solide pour capter le « map pack », les requêtes « near me » et la recherche vocale/IA. Niveau intermédiaire/avancé. Focus : précision, performance, sécurité, observabilité.
1) Objectif
Livrer un site prêt-production optimisé pour le SEO local :
- Cohérence NAP (Name, Address, Phone).
- Pages de localisation et de services structurées.
- Balisage JSON-LD
LocalBusiness,FAQPageetAggregateRatingcomplet et conforme aux directives Google. - Redirections et canonicals fiables (Nginx sans
if,<link rel="canonical">absolus). - Core Web Vitals mobile-first, HTTP/2, compression, cache long.
- Sitemaps partitionnés et indexés.
- Intégration API Google Business Profile (OAuth2 et service accounts, quotas dynamiques, backoff idempotent).
- Observabilité : GA4, Search Console, GBP Insights, Lighthouse CI, audit logs.
2) Prérequis
- Accès au code, serveur/proxy (Nginx compilé HTTP/2, Brotli ou CDN), DNS.
- Comptes Google Search Console, GA4, identifiants OAuth2 et/ou service account (domain-wide delegation) pour GBP API.
- Environnements dev/staging/prod, CI/CD, gestion des logs et alertes.
- Budget estimé : audit 500–2 000 $, pages 50–200 $ l’unité.
3) Implémentation pas à pas
Étape 1 – TLS/HTTP2, redirections & canonicals
Évitez les if et l’en-tête Link dynamique ; préférez une règle de réécriture et des balises <link rel="canonical"> absolues.

server {
listen 80;
server_name example.com www.example.com;
return 301 https://example.com$request_uri;
}
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/ssl/certs/example.crt;
ssl_certificate_key /etc/ssl/private/example.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
root /var/www/html;
# Réécrire sans 'if' pour forcer le slash final
rewrite ^([^.]*[^/])$ $1/ permanent;
location / {
try_files $uri $uri/ =404;
}
}
Dans chaque <head> :
<link rel="canonical" href="https://example.com/chemin/page/" />
Étape 2 – Core Web Vitals mobile-first
- Compression Brotli + gzip fallback :
brotli on;
brotli_comp_level 6;
brotli_types text/plain text/css application/javascript application/json image/svg+xml;
- Cache-control long (1 an,
immutable) pour assets. - Images AVIF/WebP,
srcset,loading="lazy",fetchpriority. - Inline critical CSS,
preconnect,defer/asyncJS.
Étape 3 – JSON-LD LocalBusiness, FAQPage, AggregateRating
Rendu server-side dans le <head> ou début du <body>. Exemple pour une boulangerie :
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Bakery",
"name": "Boulangerie Dupont",
"@id": "https://example.com/lyon/cordeliers/",
"url": "https://example.com/lyon/cordeliers/",
"image": ["https://example.com/static/storefront.webp"],
"telephone": "+33 4 72 00 00 00",
"address": {
"@type": "PostalAddress",
"streetAddress": "12 Rue des Cordeliers",
"addressLocality": "Lyon",
"addressRegion": "Auvergne-Rhône-Alpes",
"postalCode": "69002",
"addressCountry": "FR"
},
"geo": {
"@type": "GeoCoordinates",
"latitude": 45.7597,
"longitude": 4.8340
},
"openingHoursSpecification": [
{
"@type": "OpeningHoursSpecification",
"dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday"],
"opens": "07:00",
"closes": "19:00"
}
],
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": 4.7,
"reviewCount": 132
},
"sameAs": [
"https://www.facebook.com/boulangeriedupont",
"https://www.instagram.com/boulangeriedupont"
]
}
</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "Livrez-vous à domicile ?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Oui, livraison sur Lyon pour toute commande supérieure à 20 €."
}
}
]
}
</script>
Note : respectez les politiques Google sur les avis (minimum 5 avis pour AggregateRating, données modérées onsite). Évitez les balises dupliquées entre pages.

Étape 4 – Pages localisation & services
- URL structurées (
/ville/quartier/,/services/nom-service/), contenu riche > 300 mots. - Inclure intro locale, NAP, horaires, CTA (appel/itinéraire), carte, FAQ, visuels, témoignages.
- Maillage interne : relier chaque service à ses localisations et vice-versa.
Étape 5 – API Google Business Profile & synchronisation
- OAuth2 recommandée pour compte individuel (flow standard, accès/refresh tokens).
Voir : https://developers.google.com/my-business/content/authorization - Service accounts : nécessite domain-wide delegation et n’est pas pris en charge pour tous les profils. Stocker tokens et clés privées dans un vault sécurisé, mettre en place rotation régulière.
- Quotas : récupérer dynamiquement via l’API
GET /quota, n’hésitez pas à ajuste le backoff - Idempotence : joindre un
requestId(UUID v4) à chaque requête et/ou exploiter l’ETag pour des requêtes conditionnelles (If-Match,If-None-Match). - Backoff exponentiel avec jitter et plafonnement :
async function patchWithBackoff(payload) {
const maxAttempts = 6;
const baseDelay = 1000; // ms
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
const requestId = uuidv4();
const headers = { "X-Request-Id": requestId };
if (etag) headers["If-Match"] = etag;
const resp = await sendPatch(payload, headers);
if (resp.ok) return resp;
if (![429, 500, 502, 503, 504].includes(resp.status)) {
throw new Error(`API error ${resp.status}`);
}
// Exponential backoff with jitter and cap
const cap = 30000;
const delay = Math.min(cap, baseDelay * 2 ** (attempt - 1));
const jitter = Math.random() * baseDelay;
await sleep(delay + jitter);
}
throw new Error('Échec après plusieurs tentatives');
}
Étape 6 – Sitemaps & robots.txt
Partitionnez si > 50 000 URL, listez les sous-sitemaps dans sitemap-index.xml.
User-agent: *
Disallow: /search
Allow: /
Sitemap: https://example.com/sitemap-index.xml
Étape 7 – Crawl-budget & indexation
- Identifiez les pages low-value (thin content) :
noindexou fusion. - Priorisez pages de conversion et zones stratégiques.
- Attribuez
priorityetchangefreqdans les sitemaps.
4) Vérification & tests automatisés
curl -I https://example.com/lyon/cordeliers/→ statut 200, HTTP/2, SSL ok, balisecanonical.- Rich Results Test CLI/API pour
LocalBusinessetFAQPage. - Lint JSON-LD (outil Google ou
npm ld lint). - Lighthouse CI : perf ≥ 0.80, accès ≥ 0.90, LCP < 2.5 s, CLS < 0.1.
- Search Console : couverture sans erreurs, sitemaps valides.
- GA4 : événements et UTMs GBP remontés.
- GBP : vérifiez la consistance des horaires et consultez les audit logs.
5) Dépannage courant
- Contenu dupliqué : revérifiez vos
canonical, enrichissez ou fusionnez. - Horaires site/GBP divergents : cron job de sync + alertes.
- Rich results absents : assurez-vous du rendu SSR du JSON-LD.
- Écarts CWV staging/prod : comparer cache, network et RUM.
- Suspension GBP : ralentissez la cadence, conservez logs et requestId.
- Problèmes NAP sur mobile : ne modifiez que l’affichage CSS, JSON-LD reste inchangé.
6) Prochaines étapes
Planifiez des revues mensuelles : audits Core Web Vitals, Rich Results, couverture SEO. Automatisez alertes via webhook Search Console, exportez GBP Insights. Formez l’équipe pour maintenir la cohérence NAP et les horaires à jour.

Damien Larquey
Author at Codolie
Passionate about technology, innovation, and sharing knowledge with the developer community.