Article SEO SEO Technique

SEO Local Service Area Radius : Optimiser votre Rayon de Zone de Service

Sommaire de l'article

Introduction

Le SEO local et le concept de service area radius (rayon de zone de service) sont devenus incontournables pour les entreprises qui souhaitent attirer des clients dans une zone géographique précise. Cette approche est particulièrement cruciale pour les artisans, prestataires de services à domicile, TPE/PME locales, franchises multi-agences et toutes les structures qui interviennent dans une zone de chalandise définie.

En travaillant correctement votre rayon de zone de service, vous augmentez la probabilité d’apparaître dans les résultats de recherche locaux pertinents (résultats organiques, Pack Local / Google Maps, Google Business Profile), au moment exact où des internautes proches recherchent vos produits ou services.

Dans cet article complet, nous allons :

  • clarifier le concept de service area radius et son lien avec le SEO local ;
  • expliquer comment Google gère réellement les zones de service (sans mythes ni rumeurs) ;
  • présenter des bonnes pratiques concrètes pour optimiser votre visibilité dans votre rayon d’intervention ;
  • donner des idées de structure de site, de contenu et de signaux locaux ;
  • proposer une FAQ pour répondre aux questions les plus fréquentes.

Concepts Clés

Avant de mettre en place des actions, il est indispensable de poser des bases solides sur ce que recouvre réellement le rayon de zone de service en SEO local.

Qu'est-ce qu'un Service Area Radius ?

Le service area radius, ou rayon de zone de service, désigne la zone géographique dans laquelle une entreprise accepte de se déplacer ou de livrer ses services. Il peut être défini :

  • soit comme un rayon approximatif (par exemple “environ 20 km autour de Toulouse”) ;
  • soit comme une liste de villes, codes postaux ou départements desservis ;
  • soit comme une combinaison des deux (rayon moyen + communes prioritaires).

Par exemple, un artisan plombier basé à Lyon peut décider d’intervenir principalement dans un rayon d’environ 25 kilomètres, couvrant Lyon intra-muros, Villeurbanne, Vénissieux, Bron et quelques communes limitrophes. Il ne s’agit pas d’une “règle officielle” imposée par Google, mais d’une réalité opérationnelle et commerciale propre à l’entreprise.

Cette notion de rayon n’est pas un paramètre magique qui garantirait un classement spécifique. Il sert plutôt à aligner :

  • votre stratégie de visibilité (site, fiches locales, contenus) ;
  • vos capacités opérationnelles (déplacements, délais, coûts) ;
  • les attentes réelles des internautes en matière de proximité.

Local SEO et Service Area Radius

Le SEO local regroupe l’ensemble des techniques visant à améliorer la visibilité d’une entreprise dans les résultats de recherche liés à une localisation. Il s’applique à deux grands types de structures :

  • les entreprises qui accueillent du public à une adresse physique (boutique, cabine, showroom, restaurant, salon, etc.) ;
  • les entreprises qui se déplacent chez leurs clients dans une zone géographique donnée (plombier, électricien, chauffagiste, coach sportif à domicile, infirmier libéral, jardinier, etc.).

Dans les deux cas, Google va tenir compte de trois facteurs clés pour le classement local :

  • Distance : la proximité géographique entre l’internaute (ou la zone qu’il tape dans sa requête) et votre entreprise ;
  • Pertinence : la capacité de votre profil Google Business Profile et de votre site à répondre précisément à la recherche (catégories, contenu, mots-clés, description) ;
  • Proéminence / Réputation : la notoriété et la crédibilité perçues (avis, citations locales, signaux en ligne).

Le service area radius n’est donc pas un “levier caché” qui contournerait ces facteurs. Il doit au contraire être utilisé pour renforcer votre pertinence locale là où vous avez le plus de chances de convertir : votre vraie zone de chalandise.

Geotargeting et Service Area Radius

Le geotargeting (ou ciblage géographique) consiste à adapter vos actions marketing en fonction de la localisation de vos prospects. Dans une stratégie SEO local orientée service area radius, le geotargeting peut prendre plusieurs formes :

  • création de pages locales dédiées à certaines villes ou zones prioritaires ;
  • adaptation des balises title, meta descriptions et H1 pour intégrer le nom de la ville ou du département ;
  • utilisation de contenus hyper locaux (exemples de chantiers, témoignages de clients par ville, cas d’usage par quartier) ;
  • publicités payantes (SEA, campagnes locales, Local Services Ads) ciblant une zone géographique précise.

Le geotargeting est particulièrement puissant pour les entreprises dont l’activité est réellement liée à un territoire. Il permet d’éviter de diluer le budget et les efforts sur des zones peu pertinentes, en concentrant la visibilité sur les secteurs où la demande est forte et la logistique maîtrisée.

Ce que Google fait (et ne fait pas) avec votre Zone de Service

Un point important à clarifier : Google ne se base pas uniquement sur le rayon que vous déclarez dans votre fiche Google Business Profile pour décider où vous positionner. La zone de service déclarée :

  • sert principalement à informer les internautes (zone couverte, villes desservies) ;
  • n’est pas une garantie de visibilité dans toute cette zone ;
  • n’annule pas les critères naturels de distance, pertinence et réputation.

Autrement dit, déclarer une zone de service très large (par exemple tout un pays) sans adresse pertinente, contenu localisé ni réputation solide, n’a aucune chance réaliste de vous faire remonter partout. À l’inverse, une zone plus restreinte mais bien travaillée (contenu local, avis, citations, cohérence NAP) produit souvent de meilleurs résultats dans la réalité.

Bonnes Pratiques pour Optimiser votre Rayon de Zone de Service

Une fois vos concepts clarifiés, vous pouvez passer à la mise en œuvre. L’objectif : faire en sorte que votre site, votre fiche Google Business Profile et l’ensemble de vos signaux en ligne reflètent clairement votre zone de service et la renforcent.

1. Définir une Zone de Service Réaliste et Priorisée

Commencez par déterminer précisément :

  • votre zone principale (cœur de marché : ville, agglomération, quelques communes clés) ;
  • votre zone secondaire (communes plus éloignées où vous intervenez ponctuellement) ;
  • votre zone non couverte (trop loin, pas rentable, délais incompatibles).

Évitez d’annoncer une couverture irréaliste uniquement dans l’espoir de toucher plus de requêtes. Mieux vaut une zone annoncée cohérente avec :

  • vos délais d’intervention ;
  • vos frais de déplacement ;
  • la qualité de service que vous pouvez garantir.

Sur votre site, explicitez clairement cette zone principale et, si nécessaire, les communes ou quartiers prioritaires. Cela facilitera la compréhension pour vos prospects, mais aussi pour les moteurs de recherche.

2. Optimiser le Contenu pour la Zone Géographique

Pour que votre rayon de service prenne tout son sens en SEO, votre site doit refléter votre implantation locale et votre zone d’intervention. Quelques principes :

  • Intégrer naturellement des mots-clés locaux dans les balises title, H1, H2 et dans le corps du texte : nom de la ville, de l’agglomération, du département ou de la région lorsque c’est pertinent.
  • Utiliser des expressions usuelles comme “près de”, “à proximité de”, “dans votre commune”, plutôt que de répéter artificiellement un mot-clé exactement identique.
  • Éviter le bourrage de mots-clés (“plombier Lyon” répété de façon non naturelle), qui nuit à la lisibilité et peut affaiblir vos performances SEO.

Exemples de formulations naturelles :

  • “Entreprise de réparation d’appareils électroménagers intervenant à Paris et dans les arrondissements voisins.”
  • “Service de dépannage disponible dans un large rayon autour de Lyon, incluant Villeurbanne, Bron et Vénissieux.”
  • “Plombier chauffagiste basé à Toulouse, actif dans la plupart des communes de la métropole.”

Votre contenu doit parler d’abord aux humains : clarté sur la zone couverte, délais, conditions d’intervention, types de missions par ville ou par secteur.

3. Structurer le Site Web pour le SEO Local

Une structure de site claire aide les moteurs de recherche à comprendre vos priorités géographiques et le type de services proposés. Pour une activité à zone de service :

  • Prévoyez une page de présentation de la zone de service (par exemple “Zones d’intervention” ou “Où intervenons-nous ?”) détaillant les principales villes ou secteurs couverts.
  • Pour les marchés compétitifs, créez des pages locales ciblées de type “service + ville” quand cela a du sens (une page “Plombier à Lyon”, une page “Plombier à Villeurbanne”, etc.), en veillant à proposer un contenu réellement différencié sur chaque page.
  • Assurez-vous que les URLs soient lisibles et, si nécessaire, incluent des éléments géographiques, par exemple : /plombier-lyon, /depannage-electromenager-paris-15.

Les éléments techniques de base restent cruciaux :

  • balises </strong> uniques, incluant le service et la localisation cible lorsque c’est pertinent ;</li> <li>balises <strong>meta description</strong> rédigées pour inciter au clic (bénéfices, zone, appel à l’action) ;</li> <li>maillage interne entre vos différentes pages locales pour renforcer la compréhension de votre rayon d’action.</li> </ul> <h3 id="4-utiliser-les-donnees-structurees-localbusiness">4. Utiliser les Données Structurées LocalBusiness</h3> <p>Les <strong>données structurées</strong> (schema.org) permettent de fournir à Google des informations standardisées sur votre entreprise locale. Pour une activité avec zone de service :</p> <ul> <li>Utilisez le type <strong>LocalBusiness</strong> (ou un sous-type plus précis comme Plumber, Electrician, MedicalClinic, etc.) ;</li> <li>Indiquez clairement votre <strong>adresse</strong>, votre <strong>numéro de téléphone</strong> et vos <strong>horaires d’ouverture</strong> ;</li> <li>Ajoutez un élément <strong>areaServed</strong> lorsque cela est pertinent pour préciser les villes, codes postaux ou régions desservis.</li> </ul> <p>Les données structurées n’agissent pas comme un “raccourci” pour étendre artificiellement votre visibilité, mais elles renforcent la <strong>cohérence</strong> de vos signaux locaux et aident Google à comprendre plus finement votre modèle économique.</p> <h3 id="5-creer-du-contenu-de-qualite-local-et-utile">5. Créer du Contenu de Qualité, Local et utile</h3> <p>Le contenu reste au cœur de toute stratégie SEO efficace. Pour un business local avec rayon de service, vous pouvez aller au-delà des simples pages “service + ville” et proposer :</p> <ul> <li>des <strong>études de cas locales</strong> (exemple de chantier réalisé à Marseille, témoignage de client à Lille, etc.) ;</li> <li>des <strong>guides pratiques</strong> adaptés aux conditions locales (climat, réglementation, habitudes du marché) ;</li> <li>des <strong>articles de blog</strong> sur les problématiques spécifiques à votre région (ex. “Préparer son chauffage avant l’hiver en Haute-Savoie”, “Entretenir sa toiture en bord de mer près de La Rochelle”).</li> </ul> <p>Ce type de contenu :</p> <ul> <li>renforce votre <strong>expertise perçue</strong> ;</li> <li>génère de nouvelles portes d’entrée organiques (recherches informationnelles) ;</li> <li>ancre clairement votre entreprise dans un territoire donné.</li> </ul> <h3 id="6-exploiter-pleinement-google-business-profile">6. Exploiter pleinement Google Business Profile</h3> <p>Google Business Profile (anciennement Google My Business) est un levier majeur pour apparaître dans le <strong>Pack Local</strong> (les résultats avec carte) et sur Google Maps. Pour une entreprise avec rayon de service :</p> <ul> <li>Complétez <strong>exhaustivement</strong> votre profil : nom de l’entreprise, catégorie principale, catégories secondaires, description, services, horaires, téléphone, site web.</li> <li>Indiquez votre <strong>adresse de base</strong> (lorsque c’est autorisé par la nature de votre activité) ou paramétrez correctement votre profil en tant qu’<strong>entreprise de zone de service</strong> si vous n’accueillez pas de public à votre adresse.</li> <li>Déclarez vos <strong>zones de service</strong> (villes, départements, régions) de façon réaliste, en évitant les listes excessivement longues qui ne reflètent pas la réalité.</li> <li>Ajoutez des <strong>photos de qualité</strong> : équipe, véhicules, réalisations, avant/après, lieux d’intervention typiques.</li> <li>Publiez régulièrement des <strong>posts</strong> (offres, actualités, conseils, événements locaux) pour montrer que votre entreprise est active.</li> </ul> <p>La fiche Google Business Profile agit comme un pivot entre votre rayon de service et votre présence organique : elle peut générer des appels, des demandes d’itinéraires ou des visites sur votre site, à condition d’être correctement renseignée et animée.</p> <h3 id="7-gerer-et-valoriser-les-avis-clients-locaux">7. Gérer et Valoriser les Avis Clients Locaux</h3> <p>Les <strong>avis clients</strong> jouent un rôle central dans la perception de votre entreprise et dans ses performances locales. Ils sont à la fois un signal de confiance pour les internautes et un indicateur de réputation pour Google. Pour optimiser leur impact :</p> <ul> <li>mettez en place un <strong>processus systématique</strong> de demande d’avis après chaque prestation (email, SMS, QR code, carte de visite avec lien court) ;</li> <li>visez une <strong>note moyenne élevée</strong> et un volume d’avis progressif et régulier plutôt que des pics ponctuels ;</li> <li>répondez à tous les avis, positifs comme négatifs, avec un ton professionnel et personnalisé ;</li> <li>incitez vos clients (de façon non artificielle) à mentionner la <strong>ville ou le quartier</strong> dans leurs commentaires lorsqu’ils en parlent spontanément, ce qui renforce la dimension locale.</li> </ul> <h3 id="8-developper-les-citations-locales-et-la-coherence-nap">8. Développer les Citations Locales et la Cohérence NAP</h3> <p>Les <strong>citations locales</strong> sont des mentions de votre entreprise (nom, adresse, téléphone – NAP) sur d’autres sites : annuaires, chambres de commerce, annuaires professionnels, sites d’avis spécialisés, sites associatifs locaux, etc.</p> <p>Pour un bon SEO local, deux éléments sont essentiels :</p> <ul> <li>la <strong>présence</strong> sur des plateformes locales pertinentes (annuaires de votre ville, portail de votre secteur d’activité, etc.) ;</li> <li>la <strong>cohérence parfaite</strong> de vos informations NAP : même orthographe du nom, même adresse, même format de numéro de téléphone.</li> </ul> <p>Des données incohérentes (adresses différentes, anciens numéros de téléphone, variantes de nom) peuvent brouiller les signaux envoyés aux moteurs de recherche. Une fois votre rayon de service défini, assurez-vous que toutes vos présences en ligne reflètent la même information de base.</p> <h3 id="9-prendre-en-compte-le-mobile-et-l-intention-pres-de-chez-moi">9. Prendre en Compte le Mobile et l’Intention “près de chez moi”</h3> <p>Une part importante des recherches locales est effectuée sur smartphone, souvent juste avant une visite ou une prise de contact. Votre site doit donc :</p> <ul> <li>être <strong>parfaitement responsive</strong> (adapté aux mobiles et tablettes) ;</li> <li>afficher rapidement, y compris sur des connexions mobiles ;</li> <li>afficher clairement vos <strong>coordonnées</strong> et un <strong>bouton d’appel</strong> en un clic ;</li> <li>mettre en avant votre <strong>zone de service</strong> dès les premières sections des pages clés (page d’accueil, pages services).</li> </ul> <p>Les recherches de type “près de moi”, “près d’ici” ou simplement “plombier urgence” effectuées à proximité de votre zone peuvent déclencher l’affichage de votre fiche si vos signaux locaux sont solides et si vous êtes géographiquement pertinent.</p> <h2 id="exemples-de-strategies-par-type-d-entreprise">Exemples de Stratégies par Type d’Entreprise</h2> <h3 id="artisan-ou-prestataire-de-services-a-domicile">Artisan ou Prestataire de Services à Domicile</h3> <p>Un plombier, un électricien ou un serrurier qui se déplace chez ses clients peut :</p> <ul> <li>définir une <strong>zone de service principale</strong> (ex. 20 à 30 km autour de sa ville) ;</li> <li>créer une <strong>page “Zones d’intervention”</strong> listant les principales communes desservies ;</li> <li>rédiger quelques <strong>pages locales ciblées</strong> sur les communes les plus importantes ;</li> <li>mettre en avant les <strong>délais d’intervention</strong> selon la distance ;</li> <li>publier des <strong>cas clients locaux</strong> et des photos de chantiers par ville.</li> </ul> <h3 id="cabinet-commerce-ou-point-de-vente-physique">Cabinet, Commerce ou Point de Vente Physique</h3> <p>Un restaurant, un salon de coiffure, un cabinet médical ou un magasin de proximité :</p> <ul> <li>dispose d’une <strong>adresse fixe</strong> qui reste le centre de gravité pour Google ;</li> <li>attire principalement une clientèle provenant de quelques kilomètres autour du lieu ;</li> <li>peut créer du contenu sur les <strong>quartiers desservis</strong>, les moyens d’accès, le stationnement, les transports en commun ;</li> <li>doit veiller à une <strong>cohérence parfaite</strong> entre site, Google Business Profile et citations locales.</li> </ul> <h3 id="reseaux-multi-agences-ou-franchises">Réseaux Multi-Agences ou Franchises</h3> <p>Pour une enseigne présente dans plusieurs villes ou départements :</p> <ul> <li>chaque <strong>point de vente</strong> doit en principe disposer de sa propre fiche Google Business Profile avec ses informations locales ;</li> <li>le site principal peut comporter une <strong>page dédiée par agence</strong> (ex. “Agence de Toulouse”, “Agence de Bordeaux”) ;</li> <li>le rayon de service de chaque point doit être défini en fonction de sa <strong>zone de chalandise réelle</strong> et non de tout le pays ;</li> <li>des contenus et actions locales peuvent être menés par agence (événements, partenariats, sponsoring local).</li> </ul> <h2 id="mesurer-et-ajuster-votre-strategie-de-service-area-radius">Mesurer et Ajuster votre Stratégie de Service Area Radius</h2> <p>Définir un rayon de zone de service ne suffit pas ; il faut aussi mesurer ce qui fonctionne et ajuster régulièrement.</p> <h3 id="indicateurs-a-suivre">Indicateurs à Suivre</h3> <p>Parmi les indicateurs utiles pour une stratégie de SEO local orientée rayon de service, on peut citer :</p> <ul> <li>le <strong>volume d’appels, de messages et de demandes d’itinéraires</strong> générés par votre fiche Google Business Profile ;</li> <li>le <strong>nombre de visites sur votre site</strong> issues de requêtes locales (activité + ville, “près de moi”, etc.) ;</li> <li>la <strong>répartition géographique</strong> de vos clients (villes, codes postaux) ;</li> <li>la <strong>rentabilité</strong> des interventions en fonction de la distance (temps de trajet, panier moyen, marge).</li> </ul> <h3 id="ajuster-votre-zone-au-fil-du-temps">Ajuster votre Zone au Fil du Temps</h3> <p>Avec ces données, vous pouvez :</p> <ul> <li>renforcer votre présence dans les <strong>zones les plus rentables</strong> en créant plus de contenu local, en ciblant vos campagnes et en développant des partenariats ;</li> <li>réduire ou modifier les zones moins rentables, en ajustant la zone de service déclarée et en communiquant clairement sur votre nouvelle politique ;</li> <li>tester de <strong>nouvelles communes</strong> limitrophes si votre capacité d’intervention augmente (embauche, nouvelle agence, véhicule supplémentaire).</li> </ul> <h2 id="faq-radius-de-zone-de-service-et-seo-local">FAQ – Radius de Zone de Service et SEO Local</h2> <h3 id="google-limite-t-il-officiellement-le-rayon-de-zone-de-service-a-une-distance-precise-nbsp">Google limite-t-il officiellement le rayon de zone de service à une distance précise ?</h3> <p>Non. Google ne fixe pas une distance maximale officielle identique pour tous. Il vous laisse déclarer une zone de service raisonnable, mais continue de privilégier les résultats en fonction de la <strong>proximité réelle</strong>, de la <strong>pertinence</strong> et de la <strong>réputation</strong>. Déclarer une très grande zone n’assure en rien une visibilité proportionnelle sur tout ce territoire.</p> <h3 id="dois-je-creer-une-page-par-ville-dans-mon-rayon-de-service-nbsp">Dois-je créer une page par ville dans mon rayon de service ?</h3> <p>Il n’est pas obligatoire de créer une page pour chaque ville, surtout si votre zone de service comprend des dizaines de communes. En revanche, pour les <strong>villes les plus stratégiques</strong> (forte demande, forte concurrence, importance commerciale), des pages locales de qualité, avec un contenu réellement spécifique, peuvent être très efficaces. L’essentiel est d’éviter les pages dupliquées ou trop génériques.</p> <h3 id="le-rayon-que-j-indique-dans-google-business-profile-influence-t-il-directement-mon-classement-nbsp">Le rayon que j’indique dans Google Business Profile influence-t-il directement mon classement ?</h3> <p>La zone de service que vous déclarez sert avant tout à informer les utilisateurs. Elle n’écrase pas le critère de <strong>distance réelle</strong> dans l’algorithme. Même si vous déclarez un rayon très large, vous resterez en priorité visible autour de votre zone d’implantation ou dans les villes où vos signaux locaux sont les plus forts.</p> <h3 id="comment-choisir-la-bonne-taille-de-rayon-de-service-nbsp">Comment choisir la bonne taille de rayon de service ?</h3> <p>Basez-vous sur :</p> <ul> <li>le <strong>temps de trajet moyen</strong> que vous êtes prêt à accepter ;</li> <li>la <strong>rentabilité</strong> des missions en fonction de la distance ;</li> <li>la <strong>densité de la demande</strong> (en ville, un rayon plus petit peut suffire, alors qu’en zone rurale un rayon plus large peut être pertinent).</li> </ul> <p>Commencez avec une zone cohérente avec votre capacité actuelle, puis ajustez-la en fonction des résultats et de l’évolution de votre entreprise.</p> <h3 id="puis-je-apparaitre-dans-le-pack-local-d-une-ville-ou-je-n-ai-ni-adresse-ni-agence-nbsp">Puis-je apparaître dans le Pack Local d’une ville où je n’ai ni adresse ni agence ?</h3> <p>Pour le Pack Local, Google favorise généralement les entreprises disposant d’une <strong>adresse réelle dans la ville</strong> ou à proximité immédiate. Une entreprise de zone de service peut apparaître dans certains cas, surtout si elle dispose d’une forte réputation et d’une grande pertinence pour la requête, mais il est plus difficile de se positionner sans présence physique locale. D’où l’intérêt de travailler votre <strong>contenu local</strong>, vos <strong>avis</strong> et vos <strong>signaux de proximité</strong>.</p> <h3 id="quelle-difference-entre-une-entreprise-a-adresse-et-une-entreprise-de-zone-de-service-dans-google-nb">Quelle différence entre une entreprise “à adresse” et une entreprise “de zone de service” dans Google ?</h3> <p>Une entreprise “à adresse” accueille des clients sur place. Son adresse est affichée publiquement sur Google Maps. Une entreprise “de zone de service” intervient chez ses clients et peut choisir de <strong>masquer son adresse</strong>, tout en indiquant les zones ou villes desservies. Dans les deux cas, la qualité du profil et la cohérence des informations restent essentielles pour le SEO local.</p> <h3 id="dois-je-mentionner-mon-rayon-en-kilometres-sur-mon-site-nbsp">Dois-je mentionner mon rayon en kilomètres sur mon site ?</h3> <p>C’est une option possible, mais ce n’est pas obligatoire. Vous pouvez :</p> <ul> <li>parler d’un <strong>rayon approximatif</strong> (“environ 20 km autour de Strasbourg”) ;</li> <li>lister des <strong>villes et communes précises</strong> ;</li> <li>combiner les deux (“nous intervenons principalement à X, Y, Z et dans un rayon d’environ 25 km”).</li> </ul> <p>L’important est que l’internaute comprenne rapidement si vous intervenez dans sa zone, et sous quelles conditions.</p> <h2 id="conclusion">Conclusion</h2> <p>Le <strong>service area radius</strong> n’est pas une simple option de paramétrage, mais une véritable <strong>stratégie de positionnement local</strong>. En définissant une zone réaliste, en structurant votre site autour de cette zone, en optimisant votre fiche Google Business Profile et en renforçant vos signaux de proximité (contenus, avis, citations locales), vous maximisez vos chances d’apparaître devant les bons prospects, au bon endroit et au bon moment.</p> <p>Plutôt que de chercher à “couvrir tout le pays” de façon théorique, concentrez-vous sur votre cœur de zone, là où votre entreprise est vraiment compétitive. C’est ainsi que votre rayon de zone de service deviendra un véritable levier de croissance durable pour votre visibilité locale.</p> </div> <!-- CTA Section --> <div class="mt-12 pt-8 border-t border-gray-200"> <div class="bg-gradient-to-r from-purple-600 to-blue-600 rounded-xl p-8 text-center text-white"> <h3 class="text-2xl font-bold mb-4">Besoin d'aide avec votre SEO ?</h3> <p class="mb-6 text-purple-100">Notre équipe d'experts peut vous aider à optimiser votre site e-commerce</p> <div class="flex flex-col sm:flex-row gap-4 justify-center"> <a href="/seo-ecommerce" class="bg-white text-purple-600 px-8 py-3 rounded-lg font-semibold hover:bg-purple-50 transition inline-block"> Découvrir nos services SEO </a> <a href="/#contact" class="bg-purple-800 text-white px-8 py-3 rounded-lg font-semibold hover:bg-purple-900 transition inline-block"> Nous contacter </a> </div> </div> </div> </article> <!-- Section Commentaires --> <div class="mt-12 max-w-4xl mx-auto bg-white rounded-2xl shadow-xl p-8 md:p-12"> <h2 class="text-3xl font-bold text-gray-900 mb-6 flex items-center gap-3"> <i class="fas fa-comments text-purple-600"></i> Commentaires </h2> <!-- Liste des commentaires approuvés --> <div id="comments-list" class="mb-8 space-y-6"> <!-- Les commentaires approuvés seront chargés ici via JavaScript --> </div> <!-- Formulaire de commentaire --> <div class="border-t border-gray-200 pt-8"> <h3 class="text-xl font-semibold text-gray-900 mb-4">Laisser un commentaire</h3> <form id="comment-form" class="space-y-4"> <input type="hidden" id="article-slug" value="seo-local-service-area-radius-optimiser-votre-rayon-de-zone-de-service"> <div class="grid md:grid-cols-2 gap-4"> <div> <label for="comment-name" class="block text-sm font-medium text-gray-700 mb-2">Nom *</label> <input type="text" id="comment-name" name="name" required class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-600 focus:border-transparent"> </div> <div> <label for="comment-email" class="block text-sm font-medium text-gray-700 mb-2">Email *</label> <input type="email" id="comment-email" name="email" required class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-600 focus:border-transparent"> </div> </div> <div> <label for="comment-message" class="block text-sm font-medium text-gray-700 mb-2">Message *</label> <textarea id="comment-message" name="message" rows="5" required class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-600 focus:border-transparent"></textarea> </div> <div class="text-sm text-gray-600"> <i class="fas fa-info-circle text-purple-600"></i> Votre commentaire sera soumis à modération avant publication. </div> <button type="submit" class="bg-gradient-to-r from-purple-600 to-blue-600 text-white px-8 py-3 rounded-lg font-semibold hover:from-purple-700 hover:to-blue-700 transition inline-flex items-center gap-2"> <i class="fas fa-paper-plane"></i> Publier le commentaire </button> </form> <div id="comment-status" class="mt-4 hidden"></div> </div> </div> <!-- Navigation Articles --> <div class="mt-12 max-w-4xl mx-auto"> <a href="/blog" class="inline-flex items-center gap-2 text-purple-600 hover:text-purple-800 transition font-semibold"> <i class="fas fa-arrow-left"></i> Retour au blog </a> </div> </div> </section> <!-- Script pour les commentaires --> <script> const articleSlug = 'seo-local-service-area-radius-optimiser-votre-rayon-de-zone-de-service'; // Charger les commentaires approuvés async function loadComments() { try { const response = await fetch(`/gestion-commentaires/get-comments.php?slug=${articleSlug}`); const data = await response.json(); const commentsList = document.getElementById('comments-list'); if (data.success && data.comments.length > 0) { commentsList.innerHTML = data.comments.map(comment => ` <div class="border-l-4 border-purple-600 pl-4 py-2"> <div class="flex items-center gap-2 mb-2"> <strong class="text-gray-900">${comment.name}</strong> <span class="text-sm text-gray-500">•</span> <span class="text-sm text-gray-500">${new Date(comment.date).toLocaleDateString('fr-FR')}</span> </div> <p class="text-gray-700">${comment.message}</p> </div> `).join(''); } else { commentsList.innerHTML = '<p class="text-gray-500 italic">Aucun commentaire pour le moment. Soyez le premier à commenter !</p>'; } } catch (error) { console.error('Erreur lors du chargement des commentaires:', error); } } // Gérer la soumission du formulaire document.getElementById('comment-form').addEventListener('submit', async function(e) { e.preventDefault(); const formData = { slug: articleSlug, name: document.getElementById('comment-name').value, email: document.getElementById('comment-email').value, message: document.getElementById('comment-message').value }; const submitBtn = this.querySelector('button[type="submit"]'); const originalText = submitBtn.innerHTML; submitBtn.disabled = true; submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Envoi en cours...'; try { const response = await fetch('/gestion-commentaires/submit-comment.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(formData) }); const result = await response.json(); const messageDiv = document.getElementById('comment-status'); if (result.success) { messageDiv.className = 'mt-4 p-4 bg-green-100 border border-green-400 text-green-700 rounded-lg'; messageDiv.textContent = 'Merci ! Votre commentaire a été soumis et sera publié après modération.'; messageDiv.classList.remove('hidden'); this.reset(); } else { messageDiv.className = 'mt-4 p-4 bg-red-100 border border-red-400 text-red-700 rounded-lg'; messageDiv.textContent = result.message || 'Une erreur est survenue. Veuillez réessayer.'; messageDiv.classList.remove('hidden'); } } catch (error) { const messageDiv = document.getElementById('comment-status'); messageDiv.className = 'mt-4 p-4 bg-red-100 border border-red-400 text-red-700 rounded-lg'; messageDiv.textContent = 'Erreur de connexion. Veuillez réessayer plus tard.'; messageDiv.classList.remove('hidden'); } finally { submitBtn.disabled = false; submitBtn.innerHTML = originalText; } }); // Charger les commentaires au chargement de la page loadComments(); </script> <footer class="bg-gray-950 text-gray-400 py-12"> <div class="container mx-auto px-6"> <div class="flex flex-col md:flex-row justify-between items-center"> <div class="mb-6 md:mb-0 flex items-start gap-4"> <img src="/images/logo.png" alt="Logo VRAIVEX" class="h-32 w-32 md:h-40 md:w-40 object-contain"> <div> <a href="#" class="text-2xl font-bold block"> <span class="gradient-text">VRAIVEX</span> </a> <p class="mt-2 text-sm">Automatisation, IA et SEO au service de la performance e-commerce</p> </div> </div> <div class="flex flex-col items-center md:items-end"> <div class="grid grid-cols-2 md:flex md:flex-wrap gap-3 md:space-x-6 mb-4 text-center md:text-right"> <a href="/#about" class="hover:text-white transition text-sm">À propos</a> <a href="/#services" class="hover:text-white transition text-sm">Services</a> <a href="/#prestations" class="hover:text-white transition text-sm">Prestations</a> <a href="/#bestsellers" class="hover:text-white transition text-sm">Best Sellers</a> <a href="/#brands" class="hover:text-white transition text-sm">Nos marques</a> <a href="/creation-site-ecommerce" class="hover:text-white transition text-sm">Création Sites</a> <a href="/seo-ecommerce" class="hover:text-white transition text-sm">SEO E-commerce</a> <a href="/partenaires" class="hover:text-white transition text-sm">Partenaires</a> <a href="/#contact" class="hover:text-white transition text-sm">Contact</a> </div> <p class="text-sm text-center md:text-right">© 2025 VRAIVEX. Tous droits réservés.</p> </div> </div> </div> </footer> <!-- Back to Top Button --> <button id="backToTop" class="fixed bottom-8 right-8 bg-gradient-to-r from-purple-600 to-blue-600 text-white p-4 rounded-full shadow-lg hover:shadow-xl transform hover:scale-110 transition-all duration-300 z-50 hidden"> <i class="fas fa-arrow-up text-xl"></i> </button> <script> // Header scroll effect window.addEventListener('scroll', function() { const header = document.getElementById('header'); if (window.scrollY > 100) { header.classList.add('header-scrolled'); } else { header.classList.remove('header-scrolled'); } }); // Smooth scrolling for anchor links document.querySelectorAll('a[href^="#"]').forEach(anchor => { anchor.addEventListener('click', function (e) { e.preventDefault(); document.querySelector(this.getAttribute('href')).scrollIntoView({ behavior: 'smooth' }); }); }); // Mobile menu toggle const mobileMenuButton = document.getElementById('mobileMenuButton'); const mobileMenu = document.getElementById('mobileMenu'); const menuIcon = document.getElementById('menuIcon'); if (mobileMenuButton && mobileMenu) { mobileMenuButton.addEventListener('click', function() { mobileMenu.classList.toggle('hidden'); // Toggle icon between bars and times if (mobileMenu.classList.contains('hidden')) { menuIcon.classList.remove('fa-times'); menuIcon.classList.add('fa-bars'); } else { menuIcon.classList.remove('fa-bars'); menuIcon.classList.add('fa-times'); } }); // Close menu when clicking on a link const mobileLinks = mobileMenu.querySelectorAll('a'); mobileLinks.forEach(link => { link.addEventListener('click', function() { mobileMenu.classList.add('hidden'); menuIcon.classList.remove('fa-times'); menuIcon.classList.add('fa-bars'); }); }); } // Brands Carousel const brandsCarousel = document.getElementById('brandsCarousel'); const brandsContainer = document.getElementById('brandsContainer'); const brandsPrevBtn = document.getElementById('brandsPrevBtn'); const brandsNextBtn = document.getElementById('brandsNextBtn'); const brandsPrevBtnMobile = document.getElementById('brandsPrevBtnMobile'); const brandsNextBtnMobile = document.getElementById('brandsNextBtnMobile'); if (brandsContainer && brandsCarousel) { let currentIndex = 0; const cards = brandsContainer.querySelectorAll('.brand-card'); const cardsPerView = { mobile: 1, tablet: 2, desktop: 3, large: 4 }; function getCardsPerView() { const width = window.innerWidth; if (width >= 1280) return cardsPerView.large; if (width >= 1024) return cardsPerView.desktop; if (width >= 768) return cardsPerView.tablet; return cardsPerView.mobile; } function updateCarousel() { const cardsPerViewCount = getCardsPerView(); const containerWidth = brandsCarousel.offsetWidth; const cardWidth = containerWidth / cardsPerViewCount; const maxIndex = Math.max(0, cards.length - cardsPerViewCount); currentIndex = Math.min(currentIndex, maxIndex); brandsContainer.style.transform = `translateX(-${currentIndex * cardWidth}px)`; // Update button states const isAtStart = currentIndex === 0; const isAtEnd = currentIndex >= maxIndex; if (brandsPrevBtn) { brandsPrevBtn.style.opacity = isAtStart ? '0.5' : '1'; brandsPrevBtn.style.cursor = isAtStart ? 'not-allowed' : 'pointer'; } if (brandsNextBtn) { brandsNextBtn.style.opacity = isAtEnd ? '0.5' : '1'; brandsNextBtn.style.cursor = isAtEnd ? 'not-allowed' : 'pointer'; } if (brandsPrevBtnMobile) { brandsPrevBtnMobile.style.opacity = isAtStart ? '0.5' : '1'; brandsPrevBtnMobile.style.cursor = isAtStart ? 'not-allowed' : 'pointer'; } if (brandsNextBtnMobile) { brandsNextBtnMobile.style.opacity = isAtEnd ? '0.5' : '1'; brandsNextBtnMobile.style.cursor = isAtEnd ? 'not-allowed' : 'pointer'; } } function nextSlide() { const cardsPerViewCount = getCardsPerView(); const maxIndex = Math.max(0, cards.length - cardsPerViewCount); if (currentIndex < maxIndex) { currentIndex++; updateCarousel(); } } function prevSlide() { if (currentIndex > 0) { currentIndex--; updateCarousel(); } } // Event listeners if (brandsNextBtn) brandsNextBtn.addEventListener('click', nextSlide); if (brandsPrevBtn) brandsPrevBtn.addEventListener('click', prevSlide); if (brandsNextBtnMobile) brandsNextBtnMobile.addEventListener('click', nextSlide); if (brandsPrevBtnMobile) brandsPrevBtnMobile.addEventListener('click', prevSlide); // Set responsive width for cards function setCardWidths() { const cardsPerViewCount = getCardsPerView(); const containerWidth = brandsCarousel.offsetWidth; const gap = 24; // 24px gap const cardWidth = (containerWidth - (gap * (cardsPerViewCount - 1))) / cardsPerViewCount; cards.forEach(card => { card.style.width = `${cardWidth}px`; card.style.flexShrink = '0'; }); } // Initialize setCardWidths(); updateCarousel(); // Update on resize let resizeTimeout; window.addEventListener('resize', function() { clearTimeout(resizeTimeout); resizeTimeout = setTimeout(function() { setCardWidths(); currentIndex = 0; updateCarousel(); }, 250); }); } </script> <script> // Header scroll effect window.addEventListener('scroll', function() { const header = document.getElementById('header'); if (window.scrollY > 50) { header.classList.add('header-scrolled'); } else { header.classList.remove('header-scrolled'); } }); // Scroll animations const observerOptions = { threshold: 0.1, rootMargin: '0px 0px -50px 0px' }; const observer = new IntersectionObserver(function(entries) { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.add('visible'); } }); }, observerOptions); // Observe all fade-in-up elements document.querySelectorAll('.fade-in-up').forEach(el => { observer.observe(el); }); // Smooth scroll for anchor links document.querySelectorAll('a[href^="#"]').forEach(anchor => { anchor.addEventListener('click', function (e) { e.preventDefault(); const target = document.querySelector(this.getAttribute('href')); if (target) { target.scrollIntoView({ behavior: 'smooth', block: 'start' }); } }); }); // Counter animation for stats function animateCounter(element, target, duration = 2000) { let start = 0; const increment = target / (duration / 16); const timer = setInterval(() => { start += increment; if (start >= target) { element.textContent = target + (element.textContent.includes('+') ? '+' : '') + (element.textContent.includes('K') ? 'K€' : ''); clearInterval(timer); } else { element.textContent = Math.floor(start) + (element.textContent.includes('+') ? '+' : '') + (element.textContent.includes('K') ? 'K€' : ''); } }, 16); } // Observe stats section const statsObserver = new IntersectionObserver(function(entries) { entries.forEach(entry => { if (entry.isIntersecting && !entry.target.classList.contains('animated')) { entry.target.classList.add('animated'); const statsCards = entry.target.querySelectorAll('.stats-card'); statsCards.forEach((card, index) => { setTimeout(() => { card.style.opacity = '0'; card.style.transform = 'translateY(20px)'; setTimeout(() => { card.style.transition = 'all 0.6s ease'; card.style.opacity = '1'; card.style.transform = 'translateY(0)'; }, 100); }, index * 100); }); } }); }, { threshold: 0.3 }); const statsSection = document.querySelector('section.bg-gradient-to-r'); if (statsSection) { statsObserver.observe(statsSection); } </script> <script> // Gestion du formulaire de contact const contactForm = document.getElementById('contact-form'); const formMessage = document.getElementById('form-message'); const submitBtn = document.getElementById('submit-btn'); if (contactForm) { contactForm.addEventListener('submit', async function(e) { e.preventDefault(); // Désactiver le bouton pendant l'envoi submitBtn.disabled = true; submitBtn.textContent = 'Envoi en cours...'; // Récupérer les données du formulaire const formData = new FormData(contactForm); try { // Vérifier que les données sont bien dans le FormData const formDataObj = { name: formData.get('name'), email: formData.get('email'), subject: formData.get('subject'), message: formData.get('message') }; console.log('Données du formulaire:', formDataObj); // Vérifier que tous les champs sont remplis if (!formDataObj.name || !formDataObj.email || !formDataObj.subject || !formDataObj.message) { formMessage.classList.remove('hidden'); formMessage.className = 'mb-6 p-4 rounded-lg bg-red-600 text-white'; formMessage.textContent = 'Veuillez remplir tous les champs du formulaire.'; submitBtn.disabled = false; submitBtn.textContent = 'Envoyer le message'; return; } // Essayer d'abord avec JSON (plus fiable) // Si ça ne fonctionne pas, on essaiera avec FormData let response; try { // Méthode 1 : Envoyer en JSON (plus fiable selon les forums) response = await fetch('gestion-formulaire-contact/send-email-json.php', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(formDataObj) }); } catch (jsonError) { console.warn('Erreur avec JSON, essai avec FormData:', jsonError); // Méthode 2 : Fallback avec FormData response = await fetch('send-email.php', { method: 'POST', body: formData }); } // Lire le texte de la réponse d'abord pour déboguer const responseText = await response.text(); console.log('Réponse serveur:', responseText.substring(0, 500)); // Vérifier si la réponse est OK if (!response.ok) { // Essayer de parser le JSON d'erreur try { const errorResult = JSON.parse(responseText); // Afficher le message d'erreur du serveur directement à l'utilisateur formMessage.classList.remove('hidden'); formMessage.className = 'mb-6 p-4 rounded-lg bg-red-600 text-white'; formMessage.textContent = errorResult.message || `Erreur ${response.status}: ${response.statusText}`; submitBtn.disabled = false; submitBtn.textContent = 'Envoyer le message'; return; // Sortir de la fonction pour ne pas continuer } catch (e) { throw new Error(`Erreur HTTP ${response.status}: ${response.statusText}. Réponse: ${responseText.substring(0, 200)}`); } } // Vérifier si PHP n'est pas exécuté (le serveur renvoie le code PHP brut) if (responseText.trim().startsWith('<?php') || responseText.includes('<?php')) { console.error('ERREUR: PHP n\'est pas exécuté par le serveur. Le code PHP est renvoyé brut.'); console.error('Le serveur web n\'est pas configuré pour exécuter PHP.'); // Utiliser la solution de secours : sauvegarder dans localStorage const messageData = { name: formData.get('name'), email: formData.get('email'), subject: formData.get('subject'), message: formData.get('message'), timestamp: new Date().toISOString() }; // Sauvegarder dans localStorage comme solution de secours const savedMessages = JSON.parse(localStorage.getItem('vraivex_messages') || '[]'); savedMessages.push(messageData); localStorage.setItem('vraivex_messages', JSON.stringify(savedMessages)); // Afficher un message spécial formMessage.classList.remove('hidden'); formMessage.className = 'mb-6 p-4 rounded-lg bg-yellow-600 text-white'; formMessage.innerHTML = '⚠️ PHP n\'est pas configuré sur le serveur. Votre message a été sauvegardé localement. <br>Veuillez nous contacter directement à <strong>contact@vraivex.fr</strong> ou consulter les messages sauvegardés dans la console du navigateur.'; // Afficher les messages sauvegardés dans la console console.log('Messages sauvegardés localement:', savedMessages); console.log('Pour consulter les messages, tapez dans la console: JSON.parse(localStorage.getItem("vraivex_messages"))'); return; // Sortir de la fonction } // Essayer de parser le JSON let result; try { result = JSON.parse(responseText); } catch (parseError) { console.error('Erreur de parsing JSON:', parseError); console.error('Réponse reçue:', responseText.substring(0, 500)); throw new Error('Le serveur a renvoyé une réponse invalide. Vérifiez la console pour plus de détails.'); } // Afficher le message de résultat formMessage.classList.remove('hidden'); if (result.success) { formMessage.className = 'mb-6 p-4 rounded-lg bg-green-600 text-white'; formMessage.textContent = 'Message envoyé avec succès ! Nous vous répondrons dans les plus brefs délais.'; contactForm.reset(); } else { formMessage.className = 'mb-6 p-4 rounded-lg bg-red-600 text-white'; let errorMsg = result.message || 'Une erreur est survenue. Veuillez réessayer.'; // Afficher le message de debug en développement (à retirer en production) if (result.debug) { console.error('Erreur détaillée:', result.debug); } formMessage.textContent = errorMsg; } } catch (error) { formMessage.classList.remove('hidden'); formMessage.className = 'mb-6 p-4 rounded-lg bg-red-600 text-white'; // Message d'erreur plus détaillé pour le débogage let errorMsg = 'Une erreur est survenue lors de la communication avec le serveur. '; errorMsg += 'Veuillez réessayer plus tard ou nous contacter directement à contact@vraivex.fr'; // En mode développement, afficher plus de détails if (error.message) { console.error('Erreur détaillée:', error); console.error('Message:', error.message); console.error('Stack:', error.stack); } formMessage.textContent = errorMsg; } finally { // Réactiver le bouton submitBtn.disabled = false; submitBtn.textContent = 'Envoyer le message'; // Masquer le message après 5 secondes setTimeout(() => { formMessage.classList.add('hidden'); }, 5000); } }); } // Back to Top Button functionality const backToTopButton = document.getElementById('backToTop'); // Show/hide button based on scroll position window.addEventListener('scroll', () => { if (window.pageYOffset > 300) { backToTopButton.classList.remove('hidden'); } else { backToTopButton.classList.add('hidden'); } }); // Smooth scroll to top when clicked backToTopButton.addEventListener('click', () => { window.scrollTo({ top: 0, behavior: 'smooth' }); }); </script> </body> </html>