1<!doctype html> 2<html lang="fr"> 3 <head> 4 <meta charset="UTF-8" /> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 6 <meta name="color-scheme" content="light only"> 7 <!-- Positionnement corrigé par JP le 01/08/2026 : Lystes s'adapte à tout 8 secteur, et c'est diagnostic OU essayage OU qualification selon le 9 produit. L'ancien titre bornait le marché à un rayon. 10 Le postbuild (scripts/generate-static-meta.ts) réécrit ces balises et 11 y ajoute le prix d'entrée, lu dans PRODUCT_TIERS. Ce qui est ici est 12 le filet : le titre reste juste même si le postbuild ne tourne pas, 13 et sans prix écrit en dur qui deviendrait faux. --> 14 <title>Déployer des agents IA ecommerce & retail | Lystes</title> 15 <meta name="description" content="Déployez des agents IA sur vos fiches produit : ils conseillent vos visiteurs et leur disent si le produit leur convient. Shopify et WooCommerce. Dès 49,99 ⬠HT par mois."> 16 <meta name="author" content="Lystes" /> 17 <meta name="google-site-verification" content="ORJ94K9XNrZJvYurTyweOx5czoR516sQJHYesbcwVHY" /> 18 <link rel="canonical" href="https://lystes.ai/"> 19 20 <!-- DNS Prefetch for external resources --> 21 <link rel="dns-prefetch" href="https://sjvxyiqiacpwskglgxkf.supabase.co"> 22 <link rel="dns-prefetch" href="https://fonts.googleapis.com"> 23 <link rel="dns-prefetch" href="https://fonts.gstatic.com"> 24 <link rel="dns-prefetch" href="https://api.fontshare.com"> 25 26 <!-- Preconnect for faster loading --> 27 <link rel="preconnect" href="https://sjvxyiqiacpwskglgxkf.supabase.co" crossorigin> 28 <link rel="preconnect" href="https://fonts.googleapis.com"> 29 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> 30 <link rel="preconnect" href="https://api.fontshare.com" crossorigin> 31 32 <!-- Critical font loading with display swap --> 33 <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" media="print" onload="this.media='all'"> 34 <link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,[email protected],200..800&display=swap" rel="stylesheet" media="print" onload="this.media='all'"> 35 <link href="https://api.fontshare.com/v2/css?f[]=satoshi@300,400,500,600,700&display=swap" rel="stylesheet" media="print" onload="this.media='all'"> 36 37 <!-- Fallback for no-JS font loading --> 38 <noscript> 39 <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet"> 40 <link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,[email protected],200..800&display=swap" rel="stylesheet"> 41 <link href="https://api.fontshare.com/v2/css?f[]=satoshi@300,400,500,600,700&display=swap" rel="stylesheet"> 42 </noscript> 43 44 <!-- Open Graph (canonical + og:url are set per-route via <RouteCanonical /> using react-helmet-async) --> 45 <meta property="og:url" content="https://lystes.ai/"> 46 <meta property="og:type" content="website"> 47 <meta property="og:image" content="https://lystes.ai/social-card.jpg"> 48 49 <!-- Twitter --> 50 <meta name="twitter:card" content="summary_large_image" /> 51 <meta name="twitter:site" content="@LystesAI" /> 52 <meta name="twitter:image" content="https://lystes.ai/social-card.jpg"> 53 54 55 56 57 58 59 <!-- Inline critical CSS for above-the-fold content --> 60 <style> 61 /* Critical CSS for instant first paint */ 62 *,*::before,*::after{box-sizing:border-box} 63 html{-webkit-text-size-adjust:100%;line-height:1.5} 64 body{margin:0;font-family:'Satoshi',-apple-system,BlinkMacSystemFont,sans-serif;background:#fff;color:#1d1d1f} 65 #root{min-height:100vh} 66 /* Contenu pré-rendu pour les moteurs de recherche : présent dans le DOM, 67 mais JAMAIS visible pour un navigateur qui exécute JavaScript. 68 Correction JP 05/08 : l'ancienne révélation après 1 seconde faisait 69 apparaître le texte brut avant l'affichage du site sur les connexions 70 lentes. Le bloc est désormais masqué en dur ; seul le <noscript> 71 ci-dessous le réaffiche, pour les visiteurs et robots sans JS. */ 72 .lystes-prerendu{display:none} 73 74 .page-loader{display:flex;align-items:center;justify-content:center;min-height:100vh;background:#fff} 75 .page-loader-spinner{width:32px;height:32px;border:2px solid #e5e5e5;border-top-color:#1d1d1f;border-radius:50%;animation:spin 0.8s linear infinite} 76 @keyframes spin{to{transform:rotate(360deg)}} 77 </style> 78 79 <!-- Sans JavaScript : le contenu indexable devient visible et lisible. --> 80 <noscript> 81 <style> 82 .lystes-prerendu{display:block;max-width:720px;margin:0 auto;padding:80px 24px;color:#1d1d1f} 83 .lystes-prerendu h1{font-size:32px;line-height:1.2;font-weight:600;margin:0 0 16px} 84 .lystes-prerendu p{font-size:16px;line-height:1.6;color:#4a4a4f;margin:0 0 24px} 85 .lystes-prerendu ul{list-style:none;padding:0;margin:0} 86 .lystes-prerendu li{margin:0 0 10px;font-size:15px} 87 .lystes-prerendu a{color:#1d1d1f;text-decoration:none} 88 </style> 89 </noscript> 90 91 92 <!-- Shopify App Bridge CDN - Required for embedded app validation --> 93 <!-- This script is loaded synchronously as required by Shopify --> 94
94<script> 95 // Only load App Bridge when in Shopify context (has shop param or shopify-embedded path) 96 (function() { 97 // UNIQUEMENT les routes embarquees reelles. L'ancienne condition 98 // (?shop= OU un chemin contenant /shopify) matchait /install/shopify : 99 // App Bridge s'y chargeait et aspirait la page d'installation dans 100 // l'admin Shopify de la marchande, vers la mauvaise app. Constate le 101 // 02/09/2026 : c'etait un des verrous du parcours d'installation. 102 // La page d'installation DOIT rester top-level, l'OAuth l'exige. 103 var p = window.location.pathname; 104 var isShopifyContext = p === '/shopify' || p.indexOf('/shopify/embedded') === 0; 105 if (isShopifyContext) { 106 // Inject the meta tag for API key 107 // CETTE VALEUR EST LE CLIENT ID SHOPIFY, ET ELLE DOIT RESTER EGALE AU 108 // SECRET SERVEUR SHOPIFY_CLIENT_ID. La fonction shopify-embedded-app-v2 109 // lit ce secret, cette page l'ecrit en dur : deux sources, donc une 110 // derive possible. Elle a eu lieu. Du 04/02/2026 au 25/08/2026, cette 111 // ligne portait la cle 914f6e77... (voir le test), celle d'une 112 // application qui n'existait plus, et App Bridge refusait la page. 113 // Le test cle-shopify-unique.test.ts empeche desormais le retour. 114 // Ce n'est pas un secret : Shopify sert cette cle a chaque navigateur. 115 var meta = document.createElement('meta'); 116 meta.name = 'shopify-api-key'; 117 meta.content = '7ab0b3c9524db02f78c7da4e522691e3'; 118 document.head.appendChild(meta); 119 120 // Inject the App Bridge CDN script synchronously 121 var script = document.createElement('script'); 122 script.src = 'https://cdn.shopify.com/shopifycloud/app-bridge.js'; 123 script.async = false; 124 document.head.appendChild(script); 125 } 126 })(); 127 </script>
127 128 <meta property="og:title" content="Déployer des agents IA ecommerce & retail | Lystes"> 129 <meta name="twitter:title" content="Déployer des agents IA ecommerce & retail | Lystes"> 130 <meta property="og:description" content="Déployez des agents IA sur vos fiches produit : ils conseillent vos visiteurs et leur disent si le produit leur convient. Shopify et WooCommerce. Dès 49,99 ⬠HT par mois."> 131 <meta name="twitter:description" content="Déployez des agents IA sur vos fiches produit : ils conseillent vos visiteurs et leur disent si le produit leur convient. Shopify et WooCommerce. Dès 49,99 ⬠HT par mois."> 132 133 <!-- Brand JSON-LD: teaches Google that lystes.ai IS the Lystes brand --> 134
134<script type="application/ld+json"> 135 { 136 "@context": "https://schema.org", 137 "@type": "Organization", 138 "name": "Lystes", 139 "alternateName": ["Lystes AI", "Lyste", "Lystee"], 140 "url": "https://lystes.ai/", 141 "logo": "https://lystes.ai/lystes-logo.png", 142 "description": "Déployez des agents IA sur vos fiches produit : ils conseillent vos visiteurs et leur disent si le produit leur convient. Shopify et WooCommerce.", 143 "sameAs": ["https://twitter.com/LystesAI"] 144 } 145 </script>
145 146
146<script type="application/ld+json"> 147 { 148 "@context": "https://schema.org", 149 "@type": "WebSite", 150 "name": "Lystes", 151 "alternateName": ["Lystes AI", "Lyste", "Lystee"], 152 "url": "https://lystes.ai/", 153 "inLanguage": "fr-FR", 154 "potentialAction": { 155 "@type": "SearchAction", 156 "target": "https://lystes.ai/search?q={search_term_string}", 157 "query-input": "required name=search_term_string" 158 } 159 } 160 </script>
160 161
161<script type="module" crossorigin src="/assets/main-C0s5idaH.js"></script>
161 162 <link rel="modulepreload" crossorigin href="/assets/index-DKx07lmn.js"> 163 <link rel="modulepreload" crossorigin href="/assets/App-DpkWjfsu.js"> 164 <link rel="stylesheet" crossorigin href="/assets/index-QjwwJ_e8.css"> 165 <link rel="stylesheet" crossorigin href="/assets/App-CsBY7POv.css">
166<script defer src="/~flock.js" data-proxy-url="/~api/analytics"></script>
166</head> 167 168 <body> 169 <div id="root"><div class="lystes-prerendu"><h1>Déployer des agents IA ecommerce & retail</h1><p>Déployez des agents IA sur vos fiches produit : ils conseillent vos visiteurs et leur disent si le produit leur convient. Shopify et WooCommerce. Dès 49,99 ⬠HT par mois.</p><ul><li><a href="/a-propos">à propos de Lystes AI</a></li><li><a href="/affiliate">Programme d'affiliation Lystes : 25 % du 1er paiement</a></li><li><a href="/boutiques">Les boutiques référencées sur Lystes</a></li><li><a href="/clients">Ils utilisent Lystes AI</a></li><li><a href="/contact">Contacter Lystes AI</a></li><li><a href="/creative">Photos et vidéos produit générées par IA | Lystes</a></li><li><a href="/entreprise">Lystes AI : des agents qui apprennent de chaque vente</a></li><li><a href="/faq">Questions fréquentes sur Lystes AI</a></li><li><a href="/integrations">Intégrations Shopify et WooCommerce | Lystes AI</a></li><li><a href="/mcp">Pilotez votre boutique depuis Claude et ChatGPT</a></li><li><a href="/pourquoi">Comment fonctionne Lystes AI</a></li><li><a href="/securite">Sécurité et hébergement des données | Lystes AI</a></li></ul></div></div> 170 171 <!-- Filet de sécurité « page blanche ». 172 Deux cas réels observés chez des visiteurs sur du matériel ancien : 173 1. le navigateur ignore les modules ES (nomodule) : rien ne se charge, 174 écran blanc total, aucune erreur visible ; 175 2. le bundle se charge mais plante à l'exécution (fonctionnalité JS
176 trop récente, extension, réseau coupé) : #root reste vide. 177 Dans les deux cas on affiche un message lisible + l'erreur exacte, 178 plutôt qu'un écran blanc muet impossible à diagnostiquer. --> 179
179<script nomodule> 180 document.getElementById('root').innerHTML = 181 '<div style="max-width:560px;margin:80px auto;padding:24px;font-family:-apple-system,sans-serif;color:#1d1d1f">' + 182 '<h1 style="font-size:22px;font-weight:600;margin:0 0 12px">Navigateur trop ancien</h1>' + 183 '<p style="font-size:15px;line-height:1.6;color:#4a4a4f">Cette application nécessite un navigateur récent. ' + 184 'Merci de mettre à jour Chrome, Firefox, Edge ou Safari, puis de recharger la page.</p></div>'; 185 </script>
185 186 187
187<script> 188 (function () { 189 var derniereErreur = ''; 190 function noter(m) { if (m && !derniereErreur) derniereErreur = String(m); } 191 window.addEventListener('error', function (e) { 192 noter((e && e.message) || (e && e.target && e.target.src)); 193 }, true); 194 window.addEventListener('unhandledrejection', function (e) { 195 noter(e && e.reason && (e.reason.message || e.reason)); 196 }); 197 198 // Le module principal ne s'exécutera pas si ces briques manquent : 199 // on le dit tout de suite plutôt que d'attendre 12 secondes. 200 function manquantes() { 201 var m = []; 202 if (typeof Promise !== 'function') m.push('Promise'); 203 if (typeof fetch !== 'function') m.push('fetch'); 204 if (typeof Object.fromEntries !== 'function') m.push('Object.fromEntries'); 205 if (typeof IntersectionObserver !== 'function') m.push('IntersectionObserver'); 206 try { new Function('var a=null;return a?.b ?? 1;')(); } catch (e) { m.push('opérateurs modernes (?. et ??)'); } 207 return m; 208 } 209 210 function ecran(titre, texte, detail) { 211 var root = document.getElementById('root'); 212 if (!root) return; 213 try { 214 localStorage.setItem('lystes_boot_error', JSON.stringify({ 215 message: detail || titre, href: location.href, ua: navigator.userAgent, at: Date.now() 216 })); 217 } catch (e) { /* stockage indisponible */ } 218 root.innerHTML = 219 '<div style="max-width:560px;margin:80px auto;padding:24px;font-family:-apple-system,sans-serif;color:#1d1d1f">' + 220 '<h1 style="font-size:22px;font-weight:600;margin:0 0 12px">' + titre + '</h1>' + 221 '<p style="font-size:15px;line-height:1.6;color:#4a4a4f">' + texte + '</p>' + 222 '<button id="lystes-recharger" style="margin:8px 8px 20px 0;padding:10px 18px;border:0;border-radius:10px;' + 223 'background:#1d1d1f;color:#fff;font-size:14px;cursor:pointer">Recharger</button>' + 224 '<a href="/diagnostic" style="display:inline-block;padding:10px 18px;border-radius:10px;background:#f0f0f0;' + 225 'color:#1d1d1f;font-size:14px;text-decoration:none">Diagnostic</a>' + 226 '<p style="font-size:13px;line-height:1.6;color:#4a4a4f">Navigateurs à jour : ' + 227 '<a href="https://www.google.com/chrome/">Chrome</a>, ' + 228 '<a href="https://www.mozilla.org/firefox/new/">Firefox</a>, ' + 229 '<a href="https://www.microsoft.com/edge">Edge</a>.</p>' + 230 (detail ? '<pre style="white-space:pre-wrap;background:#f5f5f5;padding:12px;border-radius:8px;' + 231 'font-size:12px;color:#4a4a4f">' + String(detail).replace(/</g, '<') + '</pre>' : '') + 232 '<p style="font-size:12px;color:#8a8a8f">' + navigator.userAgent.replace(/</g, '<') + '</p></div>'; 233 var b = document.getElementById('lystes-recharger'); 234 if (b) b.onclick = function () { location.reload(); }; 235 } 236 237 var absentes = manquantes(); 238 if (absentes.length) { 239 ecran('Navigateur trop ancien', 240 'Votre navigateur ne prend pas en charge certaines fonctions nécessaires au site. ' + 241 'Mettez-le à jour, puis rechargez la page.', 242 'Fonctions manquantes : ' + absentes.join(', ')); 243 return; 244 } 245 246 setTimeout(function () { 247 var root = document.getElementById('root'); 248 if (!root || root.children.length > 0) return; // l'app a démarré 249 ecran("L'application n'a pas pu démarrer", 250 'Rechargez la page. Si le problème persiste, mettez votre navigateur à jour ou ' + 251 'essayez une fenêtre de navigation privée.', 252 derniereErreur); 253 }, 12000); 254 })(); 255 </script>
255 256 257
257<script type="text/javascript" src="https://s.skimresources.com/js/302460X1790460.skimlinks.js"></script>
257 258 259 </body> 260</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.