Présence Web et Référencement
Objectif
Les deux magasins demandent des URL avant de permettre la soumission : politique de confidentialité, support, suppression de compte, et pour les liens d'application les fichiers .well-known. Cette compétence construit un petit site statique rapide qui satisfait d'abord à ces formulaires, puis le rend trouvable (moteurs de recherche, aperçus de liens, assistants IA) sans traceurs, motifs sombres ou chiffres que l'application ne peut pas étayer.
Faites cela avant les formulaires de fiche de magasin et de confidentialité (listing-and-aso, privacy-and-declarations) : ils ont besoin d'URL en direct.
Prérequis
- Un domaine que vous contrôlez, avec accès DNS (Cloudflare est utilisé dans les exemples ; n'importe quel hébergeur fonctionne s'il peut définir des en-têtes et servir des fichiers sans redirections).
- Les identifiants finaux de l'application et les données de signature de
identity-and-signing(Team ID, bundle ID, nom du package, SHA-256 de la signature d'application Play). - Le texte de la politique de confidentialité dérivé de l'analyse du code/SDK (
privacy-and-declarations) et le flux de suppression qui existe réellement dans l'application. - Les prix lus depuis les magasins (
subscriptions-and-payments), jamais tapés de mémoire. - Node.js 18+ pour les scripts dans scripts/.
1. Pages requises par les magasins
Liste de contrôle avec chaque champ de magasin → URL : references/store-url-checklist.md.
| Page | Chemin (suggéré) | Règles |
|---|---|---|
| Politique de confidentialité | /privacy | Publique, sans connexion, sans blocage géographique, HTML (pas PDF), nomme l'application, correspond aux réponses de confidentialité du magasin |
| Conditions | /terms | Nécessaire si vous vendez des abonnements (CLUF standard d'Apple ou le vôtre ; liez-le dans l'application et la fiche) |
| Support / contact | /support | Un vrai moyen de vous joindre (email ou formulaire), pas seulement une FAQ |
| Suppression de compte (web) | /delete-account | Google Play exige cette URL. Nomme l'application comme sur la fiche, permet à l'utilisateur de demander la suppression depuis la page elle-même, indique ce qui est supprimé, ce qui est conservé et pendant combien de temps, et qu'un abonnement au magasin doit être annulé séparément |
- Apple exige que la suppression commence dans l'application (directive 5.1.1(v)) ; une page web ne remplace pas cela. Play exige à la fois le chemin dans l'application et l'URL web. Docs : Suppression de compte Apple, Suppression de compte Play, Règles d'URL de politique de confidentialité Play.
- Sans connexion et stable. Pas de mur de cookies, pas de connexion, pas de JavaScript nécessaire pour lire le texte. Ne renommez pas les chemins après la soumission ; si vous devez le faire, conservez une redirection 301 depuis l'ancien chemin.
- Par langue. Une URL par langue (
/privacy,/de/privacy) avechreflang; App Store Connect permet de définir une URL de confidentialité par localisation. Si une page n'est pas traduite, liez la page de la langue par défaut plutôt qu'une 404. - Affichez la date de "dernière mise à jour" sur les pages juridiques et conservez les anciennes versions dans le contrôle de version.
2. Hébergement des liens d'application
Les modèles pour les fichiers eux-mêmes se trouvent dans identity-and-signing/templates/. Cette section concerne leur service.
https://<domaine>/.well-known/apple-app-site-associationet/.well-known/assetlinks.json: HTTP 200,Content-Type: application/json, aucune redirection (pas http→https, pas apex→www, pas de barre oblique finale), pas d'authentification, pas de page de défi bot.- Décidez apex vs
wwwune fois pour toutes. Servez les fichiers sur chaque hôte listé dans les entitlements / filtres d'intent ; redirigez l'autre hôte pour les pages uniquement, jamais pour/.well-known/. - Les hébergeurs statiques servent souvent le fichier AASA sans extension comme
application/octet-stream. Routez/.well-known/*via le Worker (voir le modèle) ou définissez l'en-tête explicitement, puis vérifiez avecscripts/check-site.mjs. - Déployez les fichiers
.well-knownavant la compilation de l'application qui revendique le domaine. Apple récupère AASA via son CDN, donc les changements peuvent prendre du temps à apparaître.
Pages d'invitation / parrainage (/i/<code>)
- Le Worker valide le code par rapport à l'alphabet exact et à la longueur émis par le backend, puis remplit un modèle. Rien d'autre de l'URL n'atteint le HTML.
- Si l'application est installée, les liens universels / App Links l'ouvrent directement (le chemin doit être dans les
componentsd'AASA et le filtre d'intent Android). Sinon, la page affiche les deux boutons de magasin et un bouton "copier le code" comme solution de repli manuelle. - Android : ajoutez le code à l'URL Play sous la forme
&referrer=<key=value encodé en URL>et lisez-le dans l'application avec l'API Play Install Referrer. iOS n'a pas de référent d'installation ; demandez à l'utilisateur de coller le code, ou préremplissez-le depuis le presse-papiers uniquement après un appui explicite. - En-têtes :
X-Robots-Tag: noindex,Cache-Control: private, no-store,Referrer-Policy: no-referrer. Gardez/i/hors du sitemap. Ne leDisallowpas dans robots.txt : un robot qui ne peut pas récupérer la page ne voit jamais lenoindex.
3. Page d'accueil
- Même langage visuel que les captures d'écran du magasin (couleurs, typographie, les mêmes cartes UI réelles). Un visiteur arrivant du site devrait reconnaître la page du magasin.
- Badges des magasins uniquement dans les œuvres officielles, non modifiés, avec l'espacement et le libellé requis ; lien direct vers la fiche. Règles : Directives marketing Apple, Badges Google Play.
- Avant le lancement : une ligne "Bientôt disponible sur l'App Store et Google Play", pas trois badges désactivés. Au lancement (après la publication en direct) : remplacez par de vrais liens de badges, ajoutez la balise Smart App Banner (docs), mettez à jour
llms.txtet le JSON-LD. Gardez cela comme un seul indicateur de configuration pour que ce soit un seul changement. APPROBATION avant de basculer. - Prix honnêtes. Les prix proviennent d'un fichier généré à partir de la relecture du magasin. Les pages contiennent des espaces réservés (
%%PRICE_MONTHLY%%) ; le Worker les remplit par pays du visiteur (request.cf.country) et indique "le magasin affiche le prix exact dans votre devise" pour les pays hors tableau. La langue de la page ne décide jamais de la devise. Pas de prix "était" barrés, pas de faux comptes à rebours, pas de cases pré-cochées. - Rapide et accessible. Texte en HTML (pas rendu par JS), un fichier CSS, peu ou pas de JS, polices auto-hébergées avec
font-display: swap, image de héros dimensionnée avecfetchpriority="high". Objectifs : LCP < 2,5 s, CLS < 0,1, INP < 200 ms (Web Vitals). Contraste et états de focus selon WCAG 2.2 ;prefers-reduced-motionrespecté. - Analytiques. Préférez aucun ou des comptages serveur/sans cookies (journaux de périphérie, analytiques respectueuses de la vie privée sans identifiants). Si vous ne définissez aucun cookie et ne chargez aucun script tiers, vous n'avez pas besoin de bannière de cookies ; n'en affichez pas "au cas où". Si vous ajoutez un traceur, la bannière de consentement, la politique de confidentialité et les réponses de confidentialité du magasin doivent toutes changer ensemble.
4. Images de partage social
- Une image Open Graph par langue : 1200×630 PNG/JPG, sous ~1 Mo, texte suffisamment grand pour être lu en taille de vignette. URL
https://absolues dansog:imageettwitter:image, plusog:image:width/height/alt,og:title,og:description,og:url,twitter:card=summary_large_image. Spécification : ogp.me, Guide de partage Meta. - Les applications de messagerie mettent en cache les aperçus de manière agressive. Après avoir modifié une image, donnez-lui un nouveau nom de fichier (ou
?v=2), puis re-scrapez dans le Sharing Debugger ("Scrape Again"). WhatsApp et autres messageries conservent leurs propres caches sans outil de rafraîchissement public, donc une nouvelle URL d'image est la solution fiable ; testez en envoyant le lien dans une nouvelle conversation.
5. SEO technique
- Titre (≈50–60 caractères, marque + ce qu'elle fait) et méta-description (≈150–160 caractères) uniques par page et par langue. Liens titre, extraits.
- hreflang : chaque version linguistique liste toutes les versions y compris elle-même, plus
x-default; les paires doivent être réciproques. Versions localisées. - Canonique : auto-référençant, absolu, sur l'URL finale (sans redirection). Canonicalisation.
- Sitemap avec uniquement des URL 200, indexables, canoniques et un
<lastmod>réel (date à laquelle le contenu a changé, par exemple depuis git, pas l'heure de compilation). Modèle, docs. - robots.txt : modèle, intro. robots.txt contrôle le crawling, pas l'indexation ; utilisez
noindexpour les pages qui doivent rester hors des résultats. - Données structurées (JSON-LD) : Organization, WebSite, MobileApplication ; FAQPage uniquement pour une FAQ visible sur la page. Exemples et règles : references/structured-data.md.
- Les hôtes non-production (aperçu,
*.workers.dev) envoientX-Robots-Tag: noindex.
6. Découverte
- Google Search Console : ajoutez une propriété Domaine, ajoutez l'enregistrement TXT
google-site-verificationà l'apex, vérifiez, soumettez le sitemap, demandez l'indexation pour les pages d'accueil. Vérifier la propriété. - Bing Webmaster Tools : importez depuis Search Console, ou vérifiez avec l'enregistrement DNS que Bing donne (un CNAME), puis soumettez le sitemap. Ajouter et vérifier.
- IndexNow (Bing, Yandex, Seznam, Naver et autres ; pas Google) : hébergez
/<clé>.txtcontenant la clé, déployez, puis exécuteznode scripts/indexnow-ping.mjs(simulation) et--send. Le script vérifie d'abord que le fichier de clé est en direct. Protocole. - Robots d'IA et llms.txt : décidez par bot s'il faut autoriser les bots de recherche/réponse et les bots d'entraînement (décision du propriétaire, APPROBATION). Liste des bots, objectifs et liens officiels : references/ai-crawlers.md. Ajoutez un court llms.txt avec le résumé du produit et les URL clés, sans prix.
Les enregistrements DNS sont une infrastructure partagée : ajoutez le nouvel enregistrement ; ne modifiez ni ne supprimez jamais les enregistrements TXT/SPF/MX existants. APPROBATION avant tout changement DNS.
7. Déploiement (exemple Cloudflare Worker)
Modèle : templates/worker.example.js. Il sert les fichiers .well-known avec le bon type et sans redirection, remplit les espaces réservés de prix par pays, rend /i/<code>, ajoute les en-têtes de sécurité et noindex sur les hôtes non-production.
Deux options de stockage :
- Workers Static Assets (le plus simple) :
"assets": { "directory": "./dist", "binding": "ASSETS", "run_worker_first": true }danswrangler.jsonc; le Worker appelleenv.ASSETS.fetch(). Docs. - KV (adressé par contenu) : la compilation écrit les fichiers sous leur hash et un
manifest.js(chemin → hash, type) ; téléchargez avecwrangler kv bulk putavant de déployer le Worker, afin que le nouveau manifeste ne pointe jamais vers un fichier manquant. Commandes KV.
Étapes :
node build.mjs→dist/(échoue en cas de clé de traduction manquante ou d'espace réservé non rempli autre que ceux de prix).- Tests unitaires (
node --test) : exécutez lefetchdu Worker contre des actifs factices. Couvrez : AASA/assetlinks 200 +application/json+ pas de redirection ; redirectionwww/httppour les pages uniquement ;/i/<mauvais>→ 404,/i/<bon>→ noindex + no-store ; chaque région de prix remplit tous les espaces réservés (aucun%%restant) ; encodage de pourcentage malformé → 404, pas 500. - Aperçu :
npx wrangler deploy --dry-run, ou déployez sur un hôte d'aperçu et exécuteznode scripts/check-site.mjs https://<hôte-d-aperçu>. - APPROBATION — déploiement de production (
npx wrangler deploy). Épinglezaccount_id,nameetroutesdanswrangler.jsoncpour que la commande ne puisse pas cibler un autre projet sur un compte partagé. - Après déploiement :
node scripts/check-site.mjs https://example.com --invite <code d'exemple>, puis le ping IndexNow.
Points de décision nécessitant une approbation humaine
- Déploiements de production et modifications DNS.
- Libellé des pages juridiques (confidentialité, conditions, suppression) ; le propriétaire approuve tout changement.
- Autorisation/interdiction des robots d'entraînement d'IA.
- Le passage "bientôt disponible" → "télécharger" et tout prix affiché sur le site.
- Ajout d'analytiques, d'un formulaire de liste d'attente ou de tout ce qui collecte des données personnelles.
Vérification
node scripts/check-site.mjs https://example.com --paths /privacy,/terms,/support,/delete-accountse termine avec 0 : pages requises 200 sans connexion, AASA/assetlinks JSON sans redirection, balises OG avec images absolues accessibles, hreflang réciproque, URL du sitemap toutes 200.- Chaque URL dans la liste de contrôle store-url s'ouvre dans une fenêtre privée sur un téléphone.
- Rich Results Test et Schema Markup Validator ne montrent aucune erreur ; PageSpeed Insights mobile LCP < 2,5 s.
- Search Console : sitemap "Succès" ; Bing : soumissions IndexNow visibles.
Pièges courants
- URL de confidentialité qui redirige vers une connexion, un PDF ou une politique d'entreprise générique qui ne nomme jamais l'application.
- Page de suppression qui dit seulement "supprimer dans l'application" (Play veut un chemin de demande sur la page) ou oublie de mentionner l'annulation de l'abonnement au magasin.
- AASA servi via une redirection apex→www, en
text/html, ou derrière un défi bot. Disallow: /i/dans robots.txt combiné avec un en-têtenoindexque les robots ne voient alors jamais.- Prix codés en dur par langue (EUR sur la page allemande pour un visiteur en Suisse) ou laissés comme des nombres obsolètes après un changement de prix du magasin.
aggregateRatinginventé pour une nouvelle application, ouoffersavec un prix qui n'est vrai que dans un seul pays.- Image OG avec une URL relative dans un aperçu de messagerie, ou un
og:imagequi renvoie une 404. hreflangmanquant sur les pages de suppression/compte, ou page en français listant l'espagnol mais pas l'inverse.- Enregistrements DNS supprimés au lieu d'ajoutés (SPF/DKIM/courrier perdu).
- Scripts de construction qui échouent sur un espace réservé inattendu, mais que personne ne remarque avant la prochaine vérification.
Références
| Référence | Lien |
|---|---|
| Modèle de Worker | templates/worker.example.js |
| Exemple de Sitemap | templates/sitemap.example.xml |
| Exemple de llms.txt | templates/llms.example.txt |
| Liste de contrôle des URL de magasin | references/store-url-checklist.md |
| Données structurées | references/structured-data.md |
| Robots d'IA | references/ai-crawlers.md |
| Script de vérification du site | scripts/check-site.mjs |
| Script de ping IndexNow | scripts/indexnow-ping.mjs |
| Script de construction | scripts/build.mjs (selon package.json) |