Article SEO SEO Technique

SEO Local Geolocation Géolocalisation

SEO Local, Geolocation et Géolocalisation : Le Guide Complet 2025

Introduction

Le SEO local et la géolocalisation sont devenus des leviers stratégiques majeurs pour toute entreprise qui dépend d’une clientèle de proximité : commerces, restaurants, professions libérales, artisans, services B2B locaux, franchises, réseaux de points de vente, etc.

Avec l’essor du mobile et des requêtes du type « près de moi », la recherche locale occupe aujourd’hui une place centrale dans le parcours client. On estime qu’environ 46 % des recherches mensuelles sur Google ont une intention locale, et qu’environ 30 % des recherches sur mobile sont liées à une localisation. Autrement dit : presque un internaute sur deux ne cherche pas seulement une information, mais un lieu, un service ou un professionnel à proximité.

Dans ce contexte, maîtriser le concept de SEO local géolocalisé n’est plus une option : c’est une condition de visibilité, de trafic qualifié et, in fine, de chiffre d’affaires.

Qu’est-ce que le SEO Local Geolocation / Géolocalisation ?

Le SEO local (Search Engine Optimization local) regroupe l’ensemble des techniques visant à améliorer la visibilité d’une entreprise dans les résultats de recherche locaux, qu’il s’agisse des résultats classiques (liens bleus), du Local Pack (bloc Google Maps avec 3 fiches d’établissements) ou de Google Maps lui‑même.

Concrètement, il s’agit de faire en sorte que votre entreprise apparaisse lorsqu’un utilisateur recherche, par exemple :

  • « restaurant italien près de moi »
  • « dentiste Paris 15 »
  • « plombier urgence Lyon »
  • « salle de sport Bordeaux bastide »

La géolocalisation intervient à plusieurs niveaux :

  • Géolocalisation de l’utilisateur : Google et les autres moteurs utilisent l’adresse IP, le GPS du smartphone ou le réseau pour estimer la position de l’internaute.
  • Géolocalisation de l’entreprise : adresse postale, coordonnées GPS, zone de chalandise déclarée, localisation sur Google Maps.
  • Signal local dans le contenu : mention de la ville, du quartier, du code postal, de repères géographiques (« près de la gare », « à deux pas du centre‑ville », etc.).

L’objectif du SEO local géolocalisé est d’aligner ces éléments pour que les moteurs de recherche puissent relier correctement une requête locale à la bonne entreprise, au bon endroit et au bon moment.

Pourquoi le SEO Local et la Géolocalisation sont‑ils stratégiques ?

Les chiffres les plus utilisés en 2024‑2025 montrent que le SEO local est l’un des canaux les plus rentables pour les entreprises physiques :

  • Environ 46 % des recherches Google ont une intention locale.
  • Environ 30 % des recherches mobiles sont liées à une localisation.
  • Environ 76 % des personnes qui effectuent une recherche locale sur leur smartphone se rendent dans une entreprise dans les 24 heures.
  • Selon les études de référence récentes, entre 18 % et 28 % des recherches locales aboutissent à un achat, selon le type de requête et l’appareil utilisé.
  • Une large majorité des utilisateurs utilise Google Maps pour trouver l’emplacement d’une entreprise, et une partie significative des clics sur les résultats locaux se concentre sur le Google Map Pack.

Ces données, bien qu’issues pour beaucoup d’études antérieures à 2020, sont encore largement utilisées en 2025 faute de chiffres publics plus récents. Elles montrent néanmoins une tendance claire : les recherches locales convertissent très bien et se traduisent souvent par une visite en magasin ou un achat dans un délai court.

En parallèle, les comportements évoluent :

  • Les requêtes contenant « près de moi » ou « à proximité » ont connu une croissance très forte sur les dernières années.
  • Une part importante des consommateurs se renseigne en ligne avant de se rendre en magasin, et lit systématiquement les avis clients.
  • Les fiches établissements Google (Google Business Profile) deviennent la première vitrine numérique de nombreuses entreprises locales.

Ne pas travailler le SEO local, c’est donc laisser le champ libre aux concurrents sur un espace de visibilité où les intentions d’achat et les taux de conversion sont parmi les plus élevés du marketing digital.

Concepts Clés du SEO Local Géolocalisé

1. Intention de recherche locale

On parle d’intention locale lorsqu’un utilisateur recherche une information liée à un lieu, qu’il l’indique explicitement (ex. « coiffeur Lille ») ou implicitement (ex. « coiffeur » recherché depuis Lille sur mobile). Le moteur de recherche va alors :

  • interpréter le besoin comme local,
  • adapter l’affichage (Local Pack, carte, résultats proches géographiquement),
  • croiser la position de l’utilisateur et les signaux locaux des entreprises.

2. Fiche d’établissement et Google Maps

Le Google Business Profile (anciennement Google My Business) est au cœur du SEO local. Une fiche correctement optimisée permet d’apparaître dans :

  • le bloc Google Maps (Local Pack) sur les pages de résultats,
  • les résultats de recherche sur Google Maps,
  • les résultats locaux sur mobile, y compris via la recherche vocale.

Les informations clés que Google utilise incluent :

  • Nom, adresse, numéro de téléphone (NAP) cohérents sur tout le web,
  • Catégories d’activité, description, services,
  • Horaires, photos, produits, menu, attributs,
  • Avis clients, notes moyennes et réponses de l’entreprise.

3. Géolocalisation technique

La géolocalisation repose sur des signaux techniques qui aident les moteurs à comprendre précisément où se situe votre entreprise :

  • Adresse complète et cohérente sur le site, dans le pied de page et sur la page de contact,
  • Balises </code> et <code><meta description></code> incluant la ville ou la zone ciblée,</li> <li><strong>Balises de données structurées</strong> (schema.org LocalBusiness, Organization, etc.) pour baliser adresse, téléphone, horaires, coordonnées géographiques,</li> <li>Plan du site clair avec une page dédiée par ville, par quartier ou par établissement lorsque c’est pertinent.</li> </ul> <h3 id="4-balisage-structure-et-schema-markup">4. Balisage structuré et Schema Markup</h3> <p>Les <strong>données structurées</strong> (par exemple via <code>schema.org/LocalBusiness</code>) permettent de décrire de manière normalisée :</p> <ul> <li>le type d’entreprise (Restaurant, MedicalClinic, Store, etc.),</li> <li>l’adresse postale complète (<code>PostalAddress</code>),</li> <li>le numéro de téléphone, l’URL, les horaires,</li> <li>les coordonnées de géolocalisation (latitude / longitude),</li> <li>des éléments d’e‑réputation (note moyenne, nombre d’avis, si disponible et conforme aux consignes des moteurs).</li> </ul> <p>Ce balisage ne garantit pas un meilleur classement, mais il facilite l’<strong>indexation correcte des informations locales</strong> et augmente les chances d’affichage riche dans les résultats de recherche (extraits enrichis, panneaux Knowledge, etc.).</p> <h3 id="5-signal-de-proximite-pertinence-et-popularite">5. Signal de proximité, pertinence et popularité</h3> <p>Les algorithmes de recherche locale reposent généralement sur trois grands piliers :</p> <ul> <li><strong>Proximité</strong> : distance entre l’utilisateur et l’entreprise au moment de la recherche.</li> <li><strong>Pertinence</strong> : adéquation entre la requête (mots‑clés, intention) et le contenu du site / de la fiche d’établissement.</li> <li><strong>Popularité</strong> : notoriété en ligne, avis, liens, citations locales, cohérence des informations sur l’ensemble du web.</li> </ul> <p>Une stratégie efficace de SEO local doit travailler simultanément ces trois dimensions.</p> <h2 id="bonnes-pratiques-seo-local-et-geolocalisation">Bonnes Pratiques SEO Local et Géolocalisation</h2> <h3 id="1-optimiser-le-contenu-pour-des-mots-cles-locaux">1. Optimiser le contenu pour des mots‑clés locaux</h3> <p>L’optimisation du contenu reste le socle du référencement local. Il s’agit d’intégrer naturellement des <strong>mots‑clés locaux</strong> pertinents, sans sur‑optimisation :</p> <ul> <li>Nom de la ville, du département, de la région,</li> <li>Quartier, zone commerciale, zone industrielle,</li> <li>Points de repère connus (gare, université, stade, centre‑ville, etc.).</li> </ul> <p>Quelques recommandations concrètes :</p> <ul> <li>Rédiger des <strong>pages locales dédiées</strong> par ville ou par zone de chalandise lorsque c’est pertinent (par exemple, une page « Plombier à Lyon », une page « Plombier à Villeurbanne », etc.).</li> <li>Adapter les <strong>balises titres</strong>, les <strong>meta descriptions</strong> et les <strong>titres H1/H2</strong> pour inclure les zones ciblées.</li> <li>Créer des <strong>contenus utiles et concrets</strong> pour l’utilisateur local : guides pratiques, FAQ locales, informations logistiques (parking, transports, accessibilité), actualités de quartier.</li> </ul> <h3 id="2-ameliorer-la-structure-du-site-et-l-experience-utilisateur">2. Améliorer la structure du site et l’expérience utilisateur</h3> <p>Une <strong>structure de site claire</strong> et une <strong>navigation simple</strong> sont essentielles, en particulier sur mobile, qui domine les recherches locales. Sur ce point, l’article initial comportait des erreurs de balisage HTML (balises <code><strong></code> mal fermées) et des termes tronqués qui peuvent nuire à la lisibilité et à l’accessibilité. La structure doit être :</p> <ul> <li><strong>Logique</strong> : pages principales (services, à propos, contact, zones desservies), puis sous‑pages locales si besoin.</li> <li><strong>Hiérarchisée</strong> : titres H1, H2, H3 correctement imbriqués, menus clairs, fil d’Ariane.</li> <li><strong>Responsive</strong> : affichage optimisé pour smartphones et tablettes (temps de chargement, boutons cliquables, cartes intégrées, etc.).</li> </ul> <p>L’ergonomie mobile est particulièrement décisive en local, compte tenu de la part importante de recherches géolocalisées réalisées sur smartphone.</p> <h3 id="3-creer-du-contenu-local-de-haute-qualite">3. Créer du contenu local de haute qualité</h3> <p>Au‑delà de la simple présence de mots‑clés locaux, la qualité du contenu est déterminante. Quelques pistes :</p> <ul> <li>Des <strong>articles de blog</strong> orientés sur des problématiques locales (événements, actualités de quartier, réglementations locales, conseils spécifiques à la région).</li> <li>Des <strong>pages de services</strong> détaillées, avec des exemples concrets de prestations réalisées dans telle ou telle ville.</li> <li>Des <strong>études de cas</strong> ou témoignages de clients situés dans la zone ciblée.</li> <li>Des <strong>FAQ locales</strong> qui répondent aux questions réellement posées par vos clients (horaires, accès, délais, zones couvertes, tarifs selon le déplacement, etc.).</li> </ul> <h3 id="4-optimiser-et-maintenir-a-jour-la-fiche-google-business-profile">4. Optimiser et maintenir à jour la fiche Google Business Profile</h3> <p>Ne pas revendiquer ou laisser incomplète sa fiche d’établissement est une erreur fréquente alors qu’il s’agit souvent du premier point de contact avec les prospects locaux. Pour tirer le meilleur parti de cette fiche :</p> <ul> <li>Revendiquer et <strong>vérifier</strong> la fiche de votre établissement.</li> <li>Remplir l’ensemble des champs : description, catégories, services, horaires, site web, téléphone.</li> <li>Ajouter des <strong>photos de qualité</strong> (intérieur, extérieur, équipe, produits).</li> <li>Mettre à jour les informations en cas de changement (horaires, fermeture exceptionnelle, déménagement).</li> <li>Publier régulièrement des <strong>posts d’actualités</strong> (offres, événements, nouveautés).</li> </ul> <h3 id="5-gerer-les-avis-et-l-e-reputation-locale">5. Gérer les avis et l’e‑réputation locale</h3> <p>Les <strong>avis en ligne</strong> sont un facteur clé du SEO local et de la conversion. De nombreuses études montrent que la quasi‑totalité des consommateurs lit régulièrement les avis avant de choisir un commerce local, et qu’une majorité se montre réticente lorsqu’elle trouve des informations incorrectes ou de mauvaises notes répétées.</p> <p>Bonnes pratiques :</p> <ul> <li>Encourager les clients satisfaits à <strong>laisser un avis</strong> (sans incitation abusive non conforme aux règles des plateformes).</li> <li>Répondre à tous les avis, positifs comme négatifs, de manière professionnelle.</li> <li>Surveiller la cohérence de la <strong>note moyenne</strong> et du volume d’avis par rapport aux concurrents locaux.</li> <li>Corriger rapidement les informations inexactes ou obsolètes sur les plateformes d’avis et les annuaires.</li> </ul> <h3 id="6-travailler-les-citations-locales-et-la-coherence-nap">6. Travailler les citations locales et la cohérence NAP</h3> <p>Les <strong>citations locales</strong> sont les mentions de votre entreprise (Nom, Adresse, Téléphone – NAP) sur d’autres sites : annuaires, portails professionnels, chambres de commerce, sites d’avis, etc. Elles contribuent à la popularité et à la confiance accordée par les moteurs de recherche.</p> <p>Points de vigilance :</p> <ul> <li>Assurer une <strong>cohérence parfaite</strong> des informations NAP sur toutes les plateformes.</li> <li>Mettre à jour les fiches lors d’un déménagement, d’un changement de nom ou de numéro.</li> <li>Éviter les doublons et fiches obsolètes qui pourraient créer de la confusion.</li> </ul> <h2 id="outils-et-ressources-pour-le-seo-local-geolocalise">Outils et Ressources pour le SEO Local Géolocalisé</h2> <h3 id="1-google-search-console">1. Google Search Console</h3> <p><strong>Google Search Console</strong> permet de suivre la manière dont votre site apparaît dans les résultats de recherche, y compris pour les requêtes locales :</p> <ul> <li>Mots‑clés contenant des noms de villes, de régions ou « près de moi ».</li> <li>Pages qui génèrent le plus d’impressions et de clics sur des requêtes locales.</li> <li>Problèmes d’indexation ou de couverture affectant vos pages locales.</li> </ul> <h3 id="2-google-analytics">2. Google Analytics</h3> <p><strong>Google Analytics</strong> (ou toute solution analytique équivalente) permet d’analyser :</p> <ul> <li>L’origine géographique réelle de vos visiteurs (villes, régions, pays).</li> <li>Les performances des pages locales (taux de rebond, durée de session, conversions).</li> <li>L’impact du mobile sur le trafic local et les conversions (appels, formulaires, réservations).</li> </ul> <h3 id="3-outils-specialises-seo-local">3. Outils spécialisés SEO local</h3> <p>En complément, plusieurs catégories d’outils peuvent vous aider à affiner votre stratégie :</p> <ul> <li>Outils de <strong>suivi de position locale</strong> (rank tracking par ville ou par code postal).</li> <li>Outils de <strong>gestion de fiches d’établissement</strong> multi‑sites ou multi‑plateformes.</li> <li>Outils d’<strong>audit NAP</strong> et de contrôle des citations locales.</li> <li>Outils de gestion et de <strong>réponse aux avis</strong> à grande échelle.</li> </ul> <h3 id="4-guides-blogs-specialises-et-communautes">4. Guides, blogs spécialisés et communautés</h3> <p>Des <strong>guides SEO local</strong>, blogs spécialisés, newsletters et forums professionnels permettent de rester informé des évolutions :</p> <ul> <li>Changements dans l’algorithme de Google affectant le Local Pack.</li> <li>Nouvelles fonctionnalités dans Google Business Profile.</li> <li>Études de cas sectorielles (restauration, santé, tourisme, artisanat, etc.).</li> </ul> <p>Il est important toutefois de garder un regard critique sur les <strong>statistiques avancées</strong> : beaucoup de chiffres mis en avant en 2024‑2025 proviennent d’études plus anciennes, parfois américaines, et ne sont pas toujours directement transposables à tous les pays ou à tous les secteurs.</p> <h2 id="eviter-les-erreurs-frequentes-avec-les-chiffres-du-seo-local">Éviter les erreurs fréquentes avec les chiffres du SEO local</h2> <p>Les erreurs suivantes sont très courantes dans les présentations ou articles sur le SEO local :</p> <ul> <li><strong>Mélanger des statistiques issues d’études différentes</strong> (par exemple, additionner des pourcentages de visites en magasin à 24 h qui n’ont pas la même définition ou la même méthodologie).</li> <li><strong>Utiliser des pourcentages très élevés d’achats après recherche locale</strong> sans préciser qu’ils proviennent de sources marketing secondaires ni décrire le contexte (type de requête, pays, secteur, période).</li> <li><strong>Présenter comme “récentes”</strong> des données issues d’études de 2014‑2018, sans mentionner l’année d’origine.</li> <li><strong>Généraliser des chiffres très spécifiques</strong> (par exemple, un pourcentage de visites dans un rayon de 5 km issu d’une étude sur un marché précis) à tous les contextes et tous les pays.</li> </ul> <p>Pour un contenu fiable et durable, il est recommandé de :</p> <ul> <li>Préciser lorsque les statistiques sont des <strong>ordres de grandeur tendances</strong> toujours utilisées faute de données plus récentes.</li> <li>Éviter les chiffres manifestement exagérés lorsqu’ils contredisent la plage 18–28 % d’achats après recherche locale généralement admise.</li> <li>Insister sur l’<strong>importance du contexte</strong> : pays, secteur, distance, device, période de mesure.</li> </ul> <h2 id="faq-seo-local-geolocalisation-et-geolocation">FAQ – SEO Local, Géolocalisation et Geolocation</h2> <dl> <dt>Qu’est‑ce que le SEO local ?</dt> <dd>Le <strong>SEO local</strong> est une stratégie de référencement naturel qui vise à améliorer la visibilité d’une entreprise dans les résultats de recherche liés à une zone géographique précise. Il s’agit de positionner votre site et votre fiche d’établissement lorsque des internautes proches de vous recherchent vos produits ou services.</dd> <dt>Pourquoi le SEO local est‑il important ?</dt> <dd>Le SEO local est important car une part significative des recherches Google a une <strong>intention locale</strong> et qu’une portion notable de ces recherches aboutit à une <strong>visite en magasin</strong> ou à un <strong>achat</strong>. En travaillant votre visibilité locale, vous captez un trafic hautement qualifié, souvent à un moment où le prospect est prêt à passer à l’action.</dd> <dt>Comment optimiser mon site pour le SEO local ?</dt> <dd>Pour optimiser votre site pour le SEO local, vous pouvez : <ul> <li>Intégrer des <strong>mots‑clés locaux</strong> (ville, quartier, région) dans vos titres, descriptions et contenus.</li> <li>Créer des <strong>pages locales dédiées</strong> pour vos principales zones de chalandise.</li> <li>Structurer clairement votre site et veiller à une excellente expérience utilisateur sur mobile.</li> <li>Mettre en place un <strong>balisage structuré</strong> de type LocalBusiness pour vos informations locales.</li> <li>Optimiser et maintenir à jour votre <strong>fiche Google Business Profile</strong>.</li> </ul> </dd> <dt>Quel est le rôle de la géolocalisation dans le SEO local ?</dt> <dd>La <strong>géolocalisation</strong> permet aux moteurs de recherche de relier la position de l’utilisateur à celle de votre entreprise. Elle intervient à la fois par la localisation du terminal (GPS, IP, réseau) et par les signaux fournis par votre site, votre fiche d’établissement et vos citations locales. Elle aide les moteurs à proposer les résultats les plus pertinents dans un <strong>rayon géographique adapté</strong>.</dd> <dt>Combien de temps faut‑il pour voir des résultats en SEO local ?</dt> <dd>Le délai dépend de nombreux facteurs (concurrence locale, état de votre visibilité actuelle, qualité de votre site, avis, cohérence NAP, etc.). En général, on observe les premiers effets d’une stratégie structurée de SEO local en quelques semaines à quelques mois, avec une montée en puissance progressive sur les requêtes locales stratégiques.</dd> <dt>Les avis en ligne influencent‑ils vraiment mon référencement local ?</dt> <dd>Oui, les <strong>avis en ligne</strong> sont un signal important pour les moteurs de recherche et pour les utilisateurs. Une bonne note moyenne, un volume suffisant d’avis récents et des réponses professionnelles de l’entreprise peuvent améliorer votre attractivité dans le Local Pack, augmenter votre taux de clics et favoriser les conversions.</dd> <dt>Dois‑je créer une page par ville ou une seule page pour toute ma zone ?</dt> <dd>Si vous ciblez plusieurs villes ou quartiers avec une offre réellement implantée localement (agences, points de vente, zones de service claires), il est généralement pertinent de créer une <strong>page dédiée par ville ou par zone clé</strong>. Chaque page doit être unique, utile et apporter une vraie valeur ajoutée, et non une simple duplication de texte avec un nom de ville différent.</dd> <dt>Le SEO local est‑il seulement pour les commerces physiques ?</dt> <dd>Non. Le SEO local concerne également les <strong>entreprises de services</strong> qui se déplacent chez le client (plombiers, électriciens, sociétés de nettoyage, consultants locaux, etc.) ou qui opèrent sur une zone de chalandise définie, même si elles n’ont pas de boutique ouverte au public.</dd> </dl> <h2 id="conclusion">Conclusion</h2> <p>Le <strong>SEO local géolocalisé</strong> est aujourd’hui une composante indispensable de la stratégie digitale des entreprises qui dépendent d’une clientèle de proximité. Dans un environnement où près de la moitié des recherches Google ont une dimension locale et où une part significative des recherches locales se traduit par une visite ou un achat, négliger ce levier revient à laisser échapper des opportunités commerciales concrètes.</p> <p>En combinant une <strong>présence technique solide</strong> (site bien structuré, balisage local, cohérence NAP), une <strong>fiche d’établissement optimisée</strong>, un <strong>contenu local de qualité</strong> et une gestion active des <strong>avis et citations</strong>, vous créez un écosystème numérique cohérent qui renforce votre visibilité là où elle compte le plus : auprès des utilisateurs proches, au moment précis où ils cherchent vos produits ou services.</p> <p>Le SEO local n’est pas un ensemble de « trucs et astuces » ponctuels, mais un <strong>travail continu</strong> d’optimisation, de mise à jour et d’adaptation aux usages. En l’abordant comme un investissement stratégique de long terme, vous transformez la géolocalisation en véritable moteur de croissance 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-geolocation-geolocalisation"> <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-geolocation-geolocalisation'; // 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="/#realisations" class="hover:text-white transition text-sm">Réalisations</a> <a href="/#brands" class="hover:text-white transition text-sm">Nos Sites</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">© 2026 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 gap = 24; const cardsPerView = { mobile: 1, tablet: 2, desktop: 3, large: 4 }; function getCardsPerView() { const w = window.innerWidth; if (w >= 1280) return cardsPerView.large; if (w >= 1024) return cardsPerView.desktop; if (w >= 768) return cardsPerView.tablet; return cardsPerView.mobile; } function getCardWidth() { const cpv = getCardsPerView(); const cw = brandsCarousel.offsetWidth; return (cw - gap * (cpv - 1)) / cpv; } function updateCarousel() { const cpv = getCardsPerView(); const cardW = getCardWidth(); const maxIdx = Math.max(0, cards.length - cpv); currentIndex = Math.min(currentIndex, maxIdx); const offset = currentIndex * (cardW + gap); brandsContainer.style.transform = `translateX(-${offset}px)`; const atStart = currentIndex === 0; const atEnd = currentIndex >= maxIdx; [brandsPrevBtn, brandsPrevBtnMobile].forEach(function(btn) { if (btn) { btn.style.opacity = atStart ? '0.4' : '1'; btn.style.pointerEvents = atStart ? 'none' : 'auto'; } }); [brandsNextBtn, brandsNextBtnMobile].forEach(function(btn) { if (btn) { btn.style.opacity = atEnd ? '0.4' : '1'; btn.style.pointerEvents = atEnd ? 'none' : 'auto'; } }); if (document.getElementById('brandsCounter')) { document.getElementById('brandsCounter').textContent = (currentIndex + 1) + ' / ' + (maxIdx + 1); } } function nextSlide() { const cpv = getCardsPerView(); const maxIdx = Math.max(0, cards.length - cpv); if (currentIndex < maxIdx) { currentIndex++; updateCarousel(); } } function prevSlide() { if (currentIndex > 0) { currentIndex--; updateCarousel(); } } if (brandsNextBtn) brandsNextBtn.addEventListener('click', nextSlide); if (brandsPrevBtn) brandsPrevBtn.addEventListener('click', prevSlide); if (brandsNextBtnMobile) brandsNextBtnMobile.addEventListener('click', nextSlide); if (brandsPrevBtnMobile) brandsPrevBtnMobile.addEventListener('click', prevSlide); function setCardWidths() { const cardW = getCardWidth(); cards.forEach(function(card) { card.style.width = cardW + 'px'; card.style.minWidth = cardW + 'px'; card.style.flexShrink = '0'; }); } let touchStartX = 0; let touchEndX = 0; brandsCarousel.addEventListener('touchstart', function(e) { touchStartX = e.changedTouches[0].screenX; }, { passive: true }); brandsCarousel.addEventListener('touchend', function(e) { touchEndX = e.changedTouches[0].screenX; const diff = touchStartX - touchEndX; if (Math.abs(diff) > 50) { diff > 0 ? nextSlide() : prevSlide(); } }, { passive: true }); setCardWidths(); updateCarousel(); 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>