Chantier de l'audit audit-seo-geo.md — 20 des 21 actions.
Technique
- Prérendu statique rétabli : le layout racine passe dans [lang], plus de
headers() ni de x-pathname. 0 page prérendue avant, 89 après.
- Schémas : offres 39/99/179 €, Organization ancrée en Belgique (adresse,
TVA, areaServed, LinkedIn), FAQPage sur la home, BreadcrumbList partout.
- Hiérarchie h1/h2/h3 remise dans l'ordre ; liens morts corrigés ; liens
légaux en <Link> — le lint passe de 15 erreurs à 0.
- Les 9 modules de la home sont enfin dans le HTML (8 manquaient).
- sharp en dépendance : mesuré, sans lui /_next/image renvoyait le JPEG
source (64 Ko), avec lui du WebP (26 Ko).
Contenu
- Nouvelles pages en 4 langues : /tarifs, /assistant-ia, /borne-kiosk,
/visite-hors-ligne, /marches-publics.
- Blog /fr/ressources (2 articles) et comparatifs sourcés et datés
myinfomate-vs-smartify et -vs-stqry, en français.
- Pages légales sous /{lang}/ : mentions et confidentialité traduites, CGU
publiées (le lien de consentement de /signup ne menait nulle part) avec
un avis traduit, la version française faisant foi.
- Vocabulaire acheteur dans les 6 segments : RGPD, marchés publics,
accessibilité — en disant l'absence de certification Access-i.
- Captures réelles de la V3 et carte de parcours ; alt textes localisés.
1,1 Mo d'images économisé.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
34 KiB
Audit SEO / GEO — myinfomate-landing
Audit en lecture seule du repo
myinfomate-landing, réalisé le 2026-09-09. Périmètre : code source uniquement. Aucun test réseau surhttps://myinfomate.ben'a été fait — tout ce qui n'est pas dérivable du code est marqué non vérifiable depuis le code.
0. Suivi d'avancement
Mis à jour le 2026-09-10. Les numéros renvoient au plan d'action du §6.
| # | Action | État |
|---|---|---|
| 1 | Hiérarchie h2/h3 |
✅ 2026-09-10 — libellé décoratif en <p>, titre de section en h2, cartes en h3 (home + segments) |
| 2 | Schema Organization |
✅ 2026-09-10 — adresse, vatID, taxID, areaServed, sameAs LinkedIn Unov ; url passé à https://unov.be |
| 3 | 9 panneaux ModulesSection dans le DOM |
✅ 2026-09-10 — vérifié dans le HTML servi |
| 4 | Offres Essentiel/Pro/Premium + AggregateOffer |
✅ 2026-09-10 — src/data/structured-data.ts, HTVA (valueAddedTaxIncluded: false) |
| 5 | Liens morts href="#" |
✅ 2026-09-10 — logo et ACCUEIL → /{lang}, globe du footer → unov.be (home et segments, le 2ᵉ n'était pas relevé par l'audit) |
| M4 | TVA écrite dans les mentions légales | ✅ 2026-09-10 |
| M7 | Profils sociaux | ✅ 2026-09-10 — vitrine LinkedIn MyInfoMate créée, dans sameAs du SoftwareApplication ; fiche produit LinkedIn soumise pour évaluation |
| 6 | llms.txt FR + prix + robots.txt |
✅ 2026-09-10 — llms.txt en français (vocabulaire acheteur, grille complète, TVA), anglais déplacé dans llms-en.txt, les deux cités dans robots.txt |
| 7 | Prérendu statique | ✅ 2026-09-10 — <html lang> dans [lang]/layout.tsx (layout racine par langue), pages légales dans le groupe (legal) avec leur propre layout, plus de headers() ni de x-pathname. 58 pages prérendues, servies en x-nextjs-cache: HIT |
| 8 | /{lang}/tarifs |
✅ 2026-09-10 — grille + 7 FAQ tarifaires ×4 langues, FAQPage + offres ; lien « Tarifs » du menu (home et segments) pointe dessus ; grille extraite dans components/PricingPlans.tsx (était copiée deux fois) |
| 9 | /{lang}/assistant-ia |
✅ 2026-09-10 — 4 langues (736 à 846 mots), 6 FAQ + FAQPage par langue, hreflang complet, liée depuis la section IA de la home et dans le sitemap. Section « Ce qu'il ne fait pas » assumée : dire les limites plutôt que survendre l'IA |
| — | Liens légaux du footer | ✅ 2026-09-10 — passés en <Link> (home, segments, signup) : le lint du repo est à 0 erreur, il en comptait 15 |
| — | Page CGU | ✅ 2026-09-10 — /conditions-generales publiée (~4 000 mots) : la case de consentement de /signup faisait accepter des CGU introuvables. Liée depuis les pieds de page et le sitemap. ⚠️ validation juridique toujours due |
| M4 | Frais de mise en place | ✅ 2026-09-10 — décision de Thomas : pas de montant affiché. À la place, dans les 4 langues : « frais de mise en place uniques, chiffrés dans le devis », et la FAQ de /tarifs dit ce qu'ils couvrent et qu'ils précèdent la signature (voir carte kanban 180) |
| 12 | Vocabulaire acheteur dans les 6 segments | 🟠 2026-09-10 — français fait. Nouvelles FAQ par segment : RGPD (les 6), marchés publics (5 — pas hôtels, secteur privé), accessibilité/Access-i (3). « Médiation numérique », « parcours de visite » et « cartel numérique » injectés dans les intros. NL/EN/DE pas encore traduits : les FAQ françaises sont plus fournies que les autres langues |
| 14 | Page marchés publics | 🟠 partiellement couvert par la FAQ des segments ; page dédiée toujours à faire |
| 10 | FAQ sur la homepage | ✅ 2026-09-10 — 8 questions ×4 langues + FAQPage (produit, prix, canaux, hors ligne, marque blanche, délai, hébergement des données). C'était la page qu'un LLM atteint en premier, et elle n'avait aucune FAQ |
| 13 | BreadcrumbList |
✅ 2026-09-10 — sur segments, cas clients (liste et détail), tarifs et assistant IA ; helper breadcrumbSchema() dans structured-data.ts |
| 21 | Dates du sitemap | ✅ 2026-09-10 — lastModified: new Date() (date du build sur les 55 URLs) remplacé par des dates réelles par famille de pages, constante LAST_MODIFIED en tête de sitemap.ts à mettre à jour avec le contenu |
| 12 bis | Traduction des FAQ segments | ✅ 2026-09-10 — 42 items ajoutés en EN/NL/DE. Parité atteinte : 10 / 10 / 8 / 7 / 8 / 9 FAQ par segment dans les 4 langues |
| 16 | Images | ✅ 2026-09-10 — recompressées (palette PNG, effort: 10) : app-screenshot-1 731 → 232 Ko, app-screenshot-2 547 → 185 Ko, myinfomate-logo 240 → 57 Ko. Qualité vérifiée à l'œil. map_generated déjà optimale. 1,1 Mo économisé. sharp a servi en installation temporaire, il n'est pas ajouté aux dépendances |
| — | google-maps-route.png (699 Ko) |
⚠️ référencé nulle part dans src/ — supprimable, mais je n'y touche pas sans ton accord |
| — | Captures d'écran de l'app | ✅ 2026-09-10 — remplacées par les vraies captures de la V3 fournies par Thomas (app du Fort de Saint-Héribert) : accueil sombre en grille bento et fiche article dans les deux téléphones du hero, liste des sections dans le mockup « white label », où un cadre vide affichait une icône de palette. Anciennes captures .png supprimées, nouvelles en JPEG (129 / 121 / 107 Ko). Textes alternatifs réécrits et localisés dans les 4 langues — ils étaient en anglais et décrivaient l'ancienne interface |
| 14 | /{lang}/marches-publics |
✅ 2026-09-10 — 4 langues, 5 FAQ. Argument central : Visit Namur, attribué sur cahier des charges publié. Dit franchement l'absence de certification Access-i et d'audit, et renvoie au service marchés pour les seuils plutôt que de citer un chiffre non vérifié |
| 17 | /{lang}/borne-kiosk et /{lang}/visite-hors-ligne |
✅ 2026-09-10 — 4 langues, 4 FAQ chacune, adossées à Visit Namur et au Fort de Saint-Héribert. Gabarit partagé components/ContentPage.tsx |
| — | Optimisation d'images en prod | ✅ 2026-09-10 — sharp ajouté aux dépendances, après mesure : sans lui, /_next/image renvoyait le JPEG source (64 Ko) ; avec lui, du WebP de 26 Ko. ⚠️ à confirmer au premier build Docker (binaires linuxmusl) |
| — | Maillage interne vers les 5 pages produit | ✅ 2026-09-10 — colonne « Solutions » dans le pied de page de la home et des pages segment (3 colonnes vides récupérées), plus des liens dans le contenu, qui valent davantage : carte « Mode Kiosk » → /borne-kiosk, point « Contenu hors ligne » → /visite-hors-ligne, bandeau acheteur public sous la grille de /tarifs → /marches-publics. Compté sur les pages servies : chaque page produit reçoit 1 à 3 liens par page. Sitemap : 67 URLs |
| 15 | Pages légales en 4 langues | ✅ 2026-09-10 — mentions légales et confidentialité traduites, CGU laissées en français avec un avis traduit (« la version française fait foi ») et le corps marqué lang="fr" : traduire un contrat qu'un juriste va corriger, c'est du travail à refaire. Les 3 pages vivent sous /{lang}/…, les anciennes URLs redirigent vers la langue du visiteur |
| 18 | Pages comparatives | ✅ 2026-09-10 — /fr/comparatif/myinfomate-vs-smartify et …-vs-stqry, prix relevés à la source le 10/09 (Smartify : 1 800 / 3 500 / 9 500 £ par an ; STQRY : 199 /mois, +100 Pro, 2 000 $ de frais uniques d'app native), sources liées et datées. Chaque page dit ce que le concurrent fait mieux. ⚠️ Guideius et izi.TRAVEL écartés : le premier ne publie aucun prix, le second a un modèle gratuit non comparable |
| 20 | Blog /fr/ressources |
✅ 2026-09-10 — index + 2 articles (audioguide vs application, borne vs BYOD), schema BlogPosting. Français seulement ; les autres langues répondent 404, c'est volontaire |
| 11 | Témoignages clients | ⏸️ écarté le 2026-09-10 par Thomas — il ne souhaite pas solliciter les clients pour l'instant, même satisfaits. Le type CasClient reste sans champ témoignage : à rouvrir le jour où un client en propose un spontanément |
| 19 | Pages XR | ⬜ deux pages à prévoir, pas une : /lunettes-connectees et /casque-vr. À écrire quand chaque module sera démontrable — cf. DOCS/v2/vr-quest-unity-plan.md et DOCS/rayban-meta-integration.md |
Tout est stagé, pas encore committé au 2026-09-10 (en attente de validation).
Point connu : une URL inexistante (/fr/xyz) répond bien 404 + noindex, mais son HTML initial est le shell d'erreur de Next ; la page 404 ([lang]/not-found.tsx) s'affiche après hydratation. Effet de l'absence de layout racine commun ; le corriger demanderait experimental.globalNotFound. Sans impact SEO.
Posts LinkedIn de lancement : DOCS/linkedin-posts-lancement.md.
1. Verdict en 5 lignes
- Oui, partiellement citable. Le contenu textuel principal est rendu côté serveur (composants serveur + client components pré-rendus par Next), les prix sont en texte brut,
llms.txtexiste et est bon, et aucun crawler IA n'est bloqué. Un LLM interrogé sur « audioguide pour musée en Belgique » a de la matière. - Mais le site n'est trouvable que sur des requêtes produit, pas sur les requêtes d'acheteur. Les 6 pages segment sont bien construites (~1 130 mots FR + 6 FAQ chacune), mais il n'existe aucune page
/tarifs,/assistant-ia,/borne-kiosk,/visite-offline, ni page lunettes connectées : le différenciateur IA n'a pas d'URL propre. - Le vocabulaire de l'acheteur public belge est absent : zéro occurrence de « médiation numérique », « scénographie », « cartel numérique », « accessibilité », « Access-i », « marché public », « RGPD » dans les ~5 700 lignes de contenu de
src/data/. - Deux fuites de contenu réelles : 8 des 9 descriptions de modules de la homepage ne sont pas dans le HTML (
ModulesSection.tsx:135), et aucune page n'est pré-rendue statiquement (layout.tsx:36force le SSR sur tout l'arbre). - Les preuves clients sont là mais désincarnées : 3 cas clients datés et nommés, mais aucun logo, aucun témoignage attribué, aucun lien sortant vers un site client ou une fiche store — c'est ce qui manque le plus à un dossier de marché public.
2. Inventaire factuel
Framework et mode de rendu
| Élément | Valeur | Source |
|---|---|---|
| Framework | Next.js 16.1.6, React 19.2.3, App Router | package.json:12-13 |
| CSS | Tailwind v4 (@tailwindcss/postcss) |
package.json:22 |
| Build | output: "standalone", React Compiler activé |
next.config.ts:5-6 |
| Déploiement | Docker node:22-alpine, node server.js derrière Traefik |
Dockerfile:8-18, README.md |
| Routing i18n | Middleware Next 16 (src/proxy.ts) → redirect vers /{locale} selon Accept-Language |
src/proxy.ts:28-32 |
| Locales | fr, en, nl, de — fr par défaut, html lang fr-BE / nl-BE |
src/i18n.ts:1-17 |
| Mode de rendu effectif | SSR dynamique sur 100 % des pages de contenu — 0 page prérendue | voir ci-dessous |
Le contenu texte est bien dans le HTML servi — ce n'est pas une SPA client-only, donc le point critique redouté n'est pas présent. Deux composants seulement sont des client components porteurs de contenu (SegmentPageClient.tsx:1, ModulesSection.tsx:1) ; Next les rend quand même dans le HTML initial, donc leur texte est extractible à l'exception de ce qui est conditionné par un useState (voir bloquant B2).
En revanche, la génération statique ne fonctionne pas. Le prerender-manifest.json du dernier build présent dans .next/ (daté du 13/08) ne contient que trois routes prérendues :
PRERENDERED: ['/_global-error', '/icon.png', '/sitemap.xml']
DYNAMIC: []
Cause : src/app/layout.tsx:36-37 appelle await headers() pour lire x-pathname. Cet accès aux headers de requête opte tout l'arbre de routes hors du rendu statique. Résultat : les generateStaticParams() déclarés dans [lang]/page.tsx:27, [lang]/[segment]/page.tsx:9 et [lang]/signup/page.tsx:25 ne produisent aucun HTML statique — chaque visite, y compris chaque crawl, déclenche un rendu React complet.
Routes trouvées
| Route | Fichier | Titre (FR) | H1 | Contenu |
|---|---|---|---|---|
/{lang} |
src/app/[lang]/page.tsx |
MyInfoMate — Application guide visiteur pour musées & lieux | MyInfoMate - La solution facile pour créer, gérer et diffuser du contenu interactif (HomeClient.tsx:29-31) |
~1 990 mots FR |
/{lang}/musees |
[segment]/page.tsx |
Application Guide de Visite pour Musées | MyInfoMate | Votre musée mérite une application à la hauteur de vos collections |
~1 134 mots FR, 6 FAQ |
/{lang}/offices-tourisme |
idem | même structure, meta propre | H1 hero segment | ~1 100 mots, 6 FAQ |
/{lang}/parcs-naturels |
idem | ~1 100 mots, 6 FAQ | ||
/{lang}/hotels-loisirs |
idem | ~1 100 mots, 6 FAQ | ||
/{lang}/evenements |
idem | ~1 100 mots, 6 FAQ | ||
/{lang}/education-culture |
idem | ~1 100 mots, 6 FAQ | ||
/{lang}/cas-clients |
cas-clients/page.tsx |
listing | oui | court |
/{lang}/cas-clients/musee-de-la-fraise |
cas-clients/[slug]/page.tsx |
Musée de la Fraise — Premier client MyInfoMate | Kiosk & App Mobile | De la vitrine au numérique : la naissance de MyInfoMate (:101) |
~400 mots |
/{lang}/cas-clients/fort-de-saint-heribert |
idem | ~400 mots | ||
/{lang}/cas-clients/visit-namur |
idem | ~400 mots | ||
/{lang}/signup |
signup/page.tsx |
Créer mon compte — Plan Essentiel | — | robots: {index:false} (:41) — correct |
/mentions-legales |
app/mentions-legales/page.tsx |
Mentions légales | Mentions légales (:18) |
FR uniquement, hors [lang] |
/confidentialite |
app/confidentialite/page.tsx |
Politique de confidentialité | Politique de confidentialité (:18) |
FR uniquement, hors [lang] |
Total indexable : 11 URLs × 4 langues + 2 pages légales = 46 URLs. Cohérent avec src/app/sitemap.ts, qui génère exactement ces entrées avec alternates.languages par entrée (sitemap.ts:8-15).
Fondations techniques — état
| Point | État | Détail |
|---|---|---|
robots.txt |
✅ présent | public/robots.txt — User-agent: * / Allow: / / Disallow: /api/ |
| Blocage crawlers IA | ✅ aucun bloqué | GPTBot, ClaudeBot, anthropic-ai, PerplexityBot, Google-Extended, CCBot, Bingbot sont tous autorisés par le User-agent: *. Aucune règle nominative, ni Allow ni Disallow (robots.txt:1-3) |
sitemap.xml |
✅ généré + référencé | src/app/sitemap.ts, référencé robots.txt:5 |
llms.txt |
✅ présent et de bonne qualité | public/llms.txt, 85 lignes — produit, features, modes de déploiement, assistant IA, clients, pricing, société |
| Canonical | ✅ sur toutes les pages | [lang]/page.tsx:60, [segment]/page.tsx:48, cas-clients/[slug], légales :7 |
| hreflang | ✅ complet + x-default |
layout.tsx:68-71, [lang]/page.tsx:59-62, et aussi dans sitemap.ts:13 |
| Open Graph | ✅ | layout.tsx:53-62 + per-page ; OG image dynamique [lang]/opengraph-image.tsx (edge runtime, 1200×630, locale-aware) et variante par segment |
| Twitter Card | ✅ summary_large_image |
layout.tsx:63-67 |
| Données structurées | ✅ JSON-LD (pas microdata) | Organization + WebSite + SoftwareApplication (home) ; FAQPage + SoftwareApplication (segments) ; Article (cas clients) |
| BreadcrumbList | ❌ absent | aucune occurrence dans le repo |
| Images | ⚠️ | next/image partout (donc WebP/AVIF à la volée), priority sur le hero (HomeClient.tsx:53), alt renseignés. Mais les sources sont des PNG lourds : app-screenshot-1.png 748 Ko, google-maps-route.png 715 Ko, app-screenshot-2.png 560 Ko, myinfomate-logo.png 246 Ko |
| Temps de chargement réel | non vérifiable depuis le code — le Lighthouse est d'ailleurs encore coché « à faire » dans TODO-SEO.md:39 |
3. Bloquants critiques
B1 — Aucune page n'est prérendue : tout est SSR à chaque requête
Fichier : src/app/layout.tsx:36-37
const h = await headers();
const pathname = h.get("x-pathname") ?? "/";
Cet appel dans le layout racine force le rendu dynamique de l'intégralité de l'application. prerender-manifest.json le confirme : trois routes prérendues, aucune page de contenu. Les generateStaticParams() déclarés dans trois fichiers sont inertes.
Conséquence : pas de blocage d'indexation (le HTML est bien complet dans la réponse), mais un TTFB dépendant du serveur à chaque crawl, et la perte de toute mise en cache statique/CDN. Sur un VPS unique derrière Traefik (README.md), c'est le premier facteur de lenteur.
Correctif : le layout racine n'a besoin de la locale que pour <html lang> et des métadonnées de repli — or elle est déjà disponible via le segment [lang]. Déplacer resolveLocale() + generateMetadata vers un src/app/[lang]/layout.tsx (à créer) recevant params.lang, et laisser le layout racine muet. [lang]/page.tsx:31 et [segment]/page.tsx:16 définissent déjà leurs métadonnées complètes, donc le layout racine est en grande partie redondant.
B2 — 8 des 9 descriptions de modules de la homepage sont absentes du HTML
Fichier : src/components/ModulesSection.tsx:20, 73, 125, 135
const [activeModule, setActiveModule] = useState(0);
...
<h3 ...>{modules[activeModule].title}</h3>
<p ...>{modules[activeModule].description}</p>
Seul le module d'index 0 (Carte interactive) voit sa description et sa value rendues. Les huit autres — Quiz/jeux, Vidéo, Article, Agenda, Offline, Web, Statistiques, Escape game — n'existent dans le HTML que sous forme de libellé de bouton (ModulesSection.tsx:59). Or « mode offline » et « escape game » sont deux des arguments les plus différenciants : ils figurent dans llms.txt:26,29 mais pas dans le HTML de la homepage.
Correctif : rendre les neuf panneaux et masquer les inactifs en CSS (hidden / aria-hidden), exactement comme le fait déjà correctement la FAQ des pages segment (SegmentPageClient.tsx:652 — collapse par max-h-0, contenu toujours présent dans le DOM).
B3 — Aucun schema Offer pour les plans Pro / Premium / Enterprise
Fichiers : src/app/[lang]/page.tsx:100-110 et [segment]/page.tsx:84-94
Le SoftwareApplication ne déclare qu'une seule offre, à 39 €. Les prix 99 € et 179 € sont bien en texte brut dans le HTML (SegmentPageClient.tsx:460 et suivantes) — donc lisibles par un LLM — mais invisibles pour Google Rich Results et pour tout agent qui s'appuie sur les données structurées. À la question « combien coûte MyInfoMate pour avoir l'assistant IA ? », un LLM devra deviner.
Correctif : remplacer offers par un tableau de trois à quatre Offer (name: "Essentiel" / "Pro" / "Premium", price, priceCurrency: "EUR", périodicité), plus un AggregateOffer avec lowPrice: 39 / highPrice: 179.
4. Manques importants (existe mais mal fait)
M1 — Hiérarchie de titres inversée sur toutes les pages
Le label décoratif en petites capitales est un <h2>, et le vrai titre de section un <h3>. Vérifiable partout :
HomeClient.tsx:78-79—<h2>{t.strategic.sectionLabel}</h2>puis<h3>{t.strategic.sectionTitle}</h3>HomeClient.tsx:126-127,:181-182,:301-302,:421-422,:474-475SegmentPageClient.tsx:310-311,:333-334,:363-364,:398-399,:636-637ModulesSection.tsx:34-35
Un extracteur de plan de page lit donc « LE DÉFI DES MUSÉES » comme titre de niveau 2 et « Ce que vivent la plupart des musées » comme sous-titre : l'inverse exact. Correctif purement cosmétique — inverser les balises, garder les classes.
M2 — Le schema Organization n'ancre pas l'entreprise en Belgique
src/app/[lang]/page.tsx:70-81 ne contient que name, url, logo, contactPoint. Manquent address (PostalAddress : Rue René Copette 3, 5020 Namur, BE), areaServed (BE / FR / LU), vatID ou taxID (BCE 0776.895.467), et sameAs (aucun profil externe déclaré). Toutes ces données existent pourtant en clair dans mentions-legales/page.tsx:24-28. C'est le signal le plus direct qu'un LLM utilise pour répondre à « une solution belge ».
M3 — Les mentions légales sont hors du système i18n
src/app/mentions-legales/page.tsx et src/app/confidentialite/page.tsx vivent hors de [lang], sont explicitement exclues du middleware (proxy.ts:5), n'existent qu'en français et n'ont pas de hreflang. Un acheteur néerlandophone ou luxembourgeois qui vérifie la conformité de l'éditeur tombe sur du français. Le sitemap ne les référence qu'en une seule version (sitemap.ts:66-77).
M4 — TVA jamais écrite, RGPD jamais mis en avant côté commercial
mentions-legales/page.tsx:25 donne « Numéro d'entreprise BCE : 0776.895.467 » mais jamais le format TVA BE 0776.895.467 — c'est pourtant la chaîne que cherche le service comptable d'une commune. Par ailleurs « RGPD » n'apparaît que dans confidentialite/page.tsx : grep -ric "RGPD" src/data/*.ts retourne 0. Le seul argument d'hébergement européen est une ligne de la page signup (translations.ts:207, « Hébergé en Europe ») — sur une page en noindex.
M5 — Cas clients : aucune preuve vérifiable de l'extérieur
src/data/cas-clients.ts donne pour chaque client client, year, location (:49-52, :223-225, :397-399), mais l'interface CasClient (:36-42) ne prévoit ni URL du site client, ni lien vers une fiche store, ni témoignage, ni logo.
- Aucun témoignage nommé : zéro occurrence de
quote/testimonial/authordans le fichier. - Aucun logo client :
public/ne contient que le logo MyInfoMate et quatre screenshots génériques. - Aucun lien sortant : pas un seul
href="http"danscas-clients/[slug]/page.tsx. - Les « résultats » sont qualitatifs —
{value:'2021', label:'Premier déploiement'},{value:'100%', label:'Autonomie éditoriale'}(cas-clients.ts:97-100) : aucun chiffre de fréquentation, de nombre de POI, de langues ou de sessions. - Le schema
Article(cas-clients/[slug]/page.tsx:56-65) n'a niimage, nidateModified, niabout/mentionspointant vers le lieu.
Les chiffres concrets présents ailleurs restent maigres : llms.txt:64-68 mentionne iBeacon, offline 100 %, iOS + Android — c'est le contenu le plus factuel du site, et il n'est pas dans le HTML.
M6 — Aucune date de mise à jour visible
sitemap.ts:18 fixe lastModified: new Date(), c'est-à-dire la date du build, appliquée uniformément à toutes les URLs : ce n'est pas un signal de fraîcheur, c'est du bruit. Aucune page n'affiche de date dans son HTML ; les cas clients affichent l'année du projet (cas-clients/[slug]/page.tsx:99), pas la date de rédaction.
M7 — Deux liens morts et aucun profil social
HomeClient.tsx:766:<a href="#">avec une icône « public » dans le footer — bouton social qui ne pointe nulle part.NavBar.tsx:59et:149: logo et « ACCUEIL » enhref="#"(scroll JS) au lieu dehref={/${lang}}. Un crawler n'a pas de lien de retour vers la home depuis le header.- Aucun
sameAsLinkedIn — la création de la page LinkedIn Unov est d'ailleurs encore ouverte dansTODO-SEO.md:40.
M8 — Images sources non optimisées
748 Ko, 715 Ko et 560 Ko en PNG pour des screenshots d'app. next/image réencode, mais l'optimiseur travaille sur ces sources à chaque cache miss. myinfomate-logo.png (246 Ko) sert à la fois de favicon (layout.tsx:52), d'image OG de repli (layout.tsx:61) et d'image 32 px dans le footer (HomeClient.tsx:755-760). Le paquet sharp n'est pas dans package.json ; le comportement réel de l'optimiseur dans le conteneur node:22-alpine est non vérifiable depuis le code.
5. Opportunités (n'existe pas et devrait exister)
O1 — Pages par intention manquantes
Aucune de ces routes n'existe dans src/app/ :
| URL attendue | État | Commentaire |
|---|---|---|
/tarifs |
❌ | Les prix ne vivent que dans des sections #pricing de la home et des six pages segment. Une requête « prix audioguide musée » n'a aucune page à faire remonter. Le contenu existe déjà (SegmentPageClient.tsx:395-628) — il suffit de l'extraire dans une route. |
/assistant-ia |
❌ | Le différenciateur n'a pas de page. Il est une section de la home (HomeClient.tsx:170-260) et un paragraphe de llms.txt:42-49. Face à Guideius ou izi.TRAVEL, c'est l'argument qui n'existe nulle part ailleurs — et il n'est pas adressable. |
/borne-kiosk |
❌ | Le kiosk n'est qu'un mode de déploiement dans #deployment-modes (translations.ts:53) ; le cas Visit Namur porte entièrement dessus. Mérite une page. |
/visite-offline-sans-reseau |
❌ | Le mode offline est un module (ModulesSection.tsx:12) dont la description n'est même pas dans le HTML (bloquant B2). Le cas Fort de Saint-Héribert est un argument offline parfait (iBeacon, aucune couverture réseau). |
/musee-plein-air |
❌ | Partiellement couvert par /parcs-naturels. |
/lunettes-connectees |
❌ | Une seule occurrence dans tout le contenu : translations.ts:60, « Meta Quest et lunettes connectées », dans un bloc « à venir ». Pas de page, pas de schema. |
/application-office-de-tourisme |
✅ équivalent | /{lang}/offices-tourisme existe et est complet. |
O2 — Vocabulaire de l'acheteur culturel : absent
grep -ric sur src/data/translations.ts, segments.ts, cas-clients.ts :
| Terme | Occurrences |
|---|---|
| « médiation numérique » | 0 |
| « scénographie » | 0 |
| « cartel numérique » | 0 |
| « accessibilité » | 0 |
| « Access-i » | 0 |
| « marché public » | 0 |
| « RGPD » | 0 (hors page confidentialité) |
| « réalité augmentée » | 0 |
| « BYOD » | 8 (bon) |
| « audioguide » / « audio guide » | 24 / 30 (bon) |
| « Namur » | 34 (bon, surtout via les cas clients) |
| « Wallonie » | 2 |
| « Belgique » | 3 (uniquement dans cas-clients.ts) |
Le site parle la langue du produit, pas celle du conservateur ni celle du service marchés publics. « Médiation numérique » est le terme employé par les appels à projets de la Fédération Wallonie-Bruxelles : ne pas l'avoir écrit une seule fois est une occasion manquée gratuite.
O3 — Aucune page marchés publics
Rien dans le repo sur les seuils, la procédure de marché de faible montant, la capacité à répondre à un cahier des charges, ni de document type. C'est pourtant l'objection numéro un d'une commune ou d'une province.
O4 — Aucune page comparative
src/app/ ne contient aucune route comparatif. Le comparatif existe à l'intérieur des pages segment (Segment.comparison, segments.ts:23-26) mais compare des catégories abstraites (« App visiteur générique », « Fiches pédagogiques papier »). Les seuls concurrents nommés le sont dans les meta descriptions (« Alternative à Smartify », segments.ts:81) et dans un pain point (segments.ts:~120 : « Smartify, SmartGuide ou STQRY coûtent entre €100 et €925/mois »). Aucune mention de Guideius, izi.TRAVEL, MySmartJourney, Musa Guide, Cirkwi ou Apptree dans tout le repo — alors que ce sont les noms réellement tapés par un acheteur belge ou français.
Ce n'est pas une erreur, c'est le levier GEO le plus rentable qui reste : les pages « alternative à X » sont exactement ce qu'un LLM ingère pour répondre à une question de comparaison. TODO-SEO.md:56-59 les liste déjà comme à faire.
O5 — Aucun blog
src/app/ ne contient aucune route blog, ressources ou articles. TODO-SEO.md:49-54 a déjà les cinq sujets d'articles identifiés ; aucun n'est écrit. Le seul contenu éditorial du site est du contenu produit — pas un texte ne répond à une question que se pose un responsable de musée avant d'avoir entendu parler de MyInfoMate.
O6 — llms.txt : bon fichier, trois angles morts
public/llms.txt est de bonne facture (85 lignes, structuré, avec liens vers les trois cas clients). Ses faiblesses :
- Il est uniquement en anglais (
llms.txt:3) alors que le marché cible est francophone. Un LLM interrogé en français citera plus volontiers une source française. - Il n'est pas référencé dans
robots.txt, ni lié depuis le HTML. - Les prix y sont incomplets (
llms.txt:74, « Starting from €39/month ») alors que la grille 39 / 99 / 179 est publique sur le site.
O7 — Pas de FAQ sur la homepage
Les six pages segment ont chacune six questions et un FAQPage JSON-LD ([segment]/page.tsx:65-76) — c'est très bien fait. La homepage n'a aucune FAQ ni FAQPage. C'est pourtant la page qu'un LLM atteint en premier.
6. Plan d'action priorisé
Trié par ratio impact / effort. T = correctif technique, C = écriture de contenu.
| # | Action | Type | Impact | Effort |
|---|---|---|---|---|
| 1 | Inverser h2/h3 sur les 12 sections concernées (HomeClient.tsx:78,126,181,301,421,474 ; SegmentPageClient.tsx:310,333,363,398,636 ; ModulesSection.tsx:34) |
T | Moyen | 0,5 h |
| 2 | Enrichir le schema Organization : address, areaServed: ["BE","FR","LU"], vatID: "BE0776895467", sameAs ([lang]/page.tsx:70-81) |
T | Fort | 0,5 h |
| 3 | Rendre les 9 panneaux de ModulesSection dans le DOM, masquer en CSS au lieu de modules[activeModule] (ModulesSection.tsx:73,125) — récupère « offline » et « escape game » dans le HTML |
T | Fort | 1 h |
| 4 | Passer SoftwareApplication.offers à un tableau de 3 Offer + AggregateOffer 39–179 € ([lang]/page.tsx:100, [segment]/page.tsx:84) |
T | Fort | 1 h |
| 5 | Corriger les liens morts : footer href="#" (HomeClient.tsx:766), logo et ACCUEIL de la NavBar (NavBar.tsx:59,149) → /{lang} |
T | Moyen | 0,5 h |
| 6 | Traduire llms.txt en français (ou publier FR + llms-en.txt), y ajouter la grille 39/99/179 et le référencer depuis robots.txt |
C | Fort | 1,5 h |
| 7 | Déplacer resolveLocale()/generateMetadata de layout.tsx:36 vers un [lang]/layout.tsx → réactive le prérendu statique des 46 URLs |
T | Fort | 2–3 h |
| 8 | Créer /{lang}/tarifs en réutilisant la section pricing existante + une FAQ tarifaire |
T+C | Fort | 3 h |
| 9 | Créer /{lang}/assistant-ia — le différenciateur mérite son URL, avec FAQ et schema |
C | Fort | 4 h |
| 10 | Ajouter un FAQPage de 6–8 questions en bas de homepage (réutiliser le format de segments.ts) |
C | Moyen | 3 h |
| 11 | Ajouter au type CasClient : clientUrl, storeUrls, testimonial {quote, name, role} — et les remplir après accord des 3 clients |
T+C | Fort | 4 h + relance clients |
| 12 | Injecter le vocabulaire acheteur (« médiation numérique », « accessibilité », « scénographie », « parcours de visite », « RGPD », « hébergement européen ») dans translations.ts et les 6 segments FR |
C | Fort | 4–6 h |
| 13 | Ajouter BreadcrumbList sur les pages segment et cas clients |
T | Faible | 1 h |
| 14 | Créer /{lang}/marches-publics : seuils, marché de faible montant, capacité à répondre, coordonnées BCE/TVA |
C | Fort (public belge) | 4 h |
| 15 | Traduire /mentions-legales et /confidentialite en 4 langues et les faire passer sous [lang] (ajuster proxy.ts:5) |
T+C | Moyen | 3 h |
| 16 | Recompresser les 4 PNG de public/ (748 / 715 / 560 / 246 Ko → cible < 150 Ko) et produire un logo 32 px distinct du logo OG |
T | Moyen | 1 h |
| 17 | Créer /{lang}/borne-kiosk et /{lang}/visite-offline-sans-reseau, adossées aux cas Visit Namur et Fort de Saint-Héribert |
C | Moyen | 6 h |
| 18 | Trois pages comparatives : myinfomate-vs-izi-travel, myinfomate-vs-guideius, myinfomate-vs-smartify — factuelles, sourcées, sans dénigrement |
C | Fort (GEO) | 8 h |
| 19 | Créer /{lang}/lunettes-connectees (à faire quand le module sera démontrable — cf. DOCS/rayban-meta-integration.md) |
C | Faible aujourd'hui | 4 h |
| 20 | Ouvrir un blog /{lang}/ressources avec les 5 articles déjà listés dans TODO-SEO.md:49-54 |
C | Fort à 6 mois | 20 h+ |
| 21 | Remplacer lastModified: new Date() par une date réelle par contenu (sitemap.ts:18) et afficher une date de mise à jour sur les cas clients |
T | Faible | 2 h |
Séquence recommandée. Les items 1 à 6 tiennent en une demi-journée et corrigent l'essentiel des pertes gratuites. L'item 7 est le seul chantier technique de fond. Les items 8, 9, 12 et 14 sont ceux qui changent réellement la réponse d'un LLM à « quelle solution d'audioguide pour mon musée en Belgique ? ».
Annexe — ce qui est déjà bien fait
À ne pas casser :
- Le contenu textuel est intégralement dans le HTML servi — ce n'est pas une SPA client-only.
- Aucun crawler IA n'est bloqué (
robots.txt:1-2). llms.txtexiste et est structuré — la majorité des concurrents n'en ont pas.- Les six pages segment sont de vraies pages d'intention : ~1 130 mots FR, pain points, features, comparatif, six FAQ, le tout en quatre langues, avec
FAQPageJSON-LD. - Les FAQ des pages segment sont collapsées en CSS (
max-h-0,SegmentPageClient.tsx:652) et non conditionnées par unuseState: le texte est bien dans le DOM. C'est le bon pattern — exactement ce queModulesSectionne fait pas. hreflangcomplet avecx-default, sur chaque page et dans le sitemap./signupest correctement ennoindex, follow(signup/page.tsx:41).- OG image générée dynamiquement et localisée, avec une variante par segment.
- Les prix (39 / 99 / 179 €) sont en texte brut dans le HTML, pas en image.