Un stack caro configurado como una app, no como un sitio que Google tenga que leer. Los cimientos sirven; falta la capa de SEO y la medición pierde datos.
Todo se midió hoy con llamadas reales desde esta máquina (curl, Chrome headless y headed, Lighthouse 13.4 local). Nada se tomó de documentos previos. Lo que no se pudo medir está marcado «no comprobado» con el motivo.
Qué es Wally's, para no auditarlo como si fuera sólo una tienda: cuatro restaurantes/wine bars con tienda (Beverly Hills, Santa Monica, Malibu, Las Vegas), reservas por OpenTable y SevenRooms, catas y eventos con boleto, private dining, catering, canastas corporativas y bodega de guarda. El e-commerce es una de sus líneas; la búsqueda de marca de restaurante («Wally's Beverly Hills reservations», «hours») es probablemente la mayor fuente de tráfico orgánico — probablemente, porque sin GSC no se mide. Ver A12 y M6.
Wally's corre sobre Shopify Hydrogen + Oxygen, Sanity CMS, Klevu, Klaviyo y Gorgias. El resultado es un catálogo de ~28,100 URLs de producto en el sitemap, ~80 % agotadas, mezcladas con inventario de punto de venta (Red Bull, Michelob, tazas de plástico), todas indexables y todas con lastmod falso. Encima de eso, el HTML que recibe Google no contiene el producto: nombre, precio, descripción y botón de compra sólo existen después de que corre React, y React falla al hidratar en todas las páginas probadas.
Cinco cosas explican casi todo:
/wines?filter.region=Napa+Valley → 301 → /collections/wines?filter… con canonical a /collections/wines sin filtro. Las páginas de más intención comercial no existen para Google, aunque /collections/napa-valley sí existe y no está enlazada.?page=2 canoniza a la página 1.zero-stock, no-image, no-description, in-stock-all, wallys-products-to-archive, discountable, retag, fb-insta. Más 10+ duplicados por sufijo y 8 colecciones «December Sale» vivas en septiembre.dataLayer manda items como objeto, no como arreglo: GA4 recibe view_item/add_to_cart sin producto. Los tags disparan antes de aceptar cookies y no hay Consent Mode. Hay dos Hotjar.Lo bueno: HTTPS/HSTS correctos, redirecciones limpias a https://www, robots.txt sano, sitemap de productos que sí se genera, JSON-LD Product + BreadcrumbList en cada PDP y CollectionPage en cada colección, TTFB de 220–440 ms, CLS 0 en home y PDP, 404 con noindex y código correcto, sin hreflang que arreglar.
No comprobado hoy: tráfico estimado, backlinks, DR, keywords y competidores por Ahrefs — el conector devolvió Access denied: MCP token is invalid en dos intentos. Core Web Vitals de campo (CrUX) — la API de PageSpeed respondió 429 sin key. Ambos se completan al reconectar, sin repetir el resto.
| Capa | Qué hay | Evidencia |
|---|---|---|
| Storefront | Shopify Hydrogen (React Router 7) sobre Oxygen | powered-by: Shopify, Oxygen, Hydrogen |
| CMS | Sanity (6n4fbwab, dataset production) | cdn.sanity.io, sitemap-sanity.xml, SANITY_STUDIO_USE_PREVIEW_MODE: "true" en el HTML |
| Tienda | cbbc83-3.myshopify.com, Storefront API 2025-07, checkout en el dominio myshopify | loader data |
| CDN | Cloudflare delante de Oxygen | server: cloudflare, cf-ray |
| Búsqueda | Klevu | KLEVU_KEY en el HTML |
| Email / CRM | Klaviyo — 73 requests por página | red |
| Soporte | Gorgias — 63 requests por página | red |
| Accesibilidad | UserWay — 31 requests por página | red |
| Analítica / ads | GTM GTM-MNRVWXQ → GA4 G-DDRQ9T5MZ2, Ads AW-1070057468, Meta 487230146902047, Bing UET 26014677, LinkedIn 6778964, Hotjar ×2 | google_tag_manager + red |
| Fuentes | Typekit + Google Fonts + bunny.net — tres proveedores | red |
Límites de la plataforma que hay que decir en la reunión:
lastmod = hora de la petición). Sin lastmod real, sin imágenes, sin filtro por disponibilidad.oxygen-full-page-cache: uncacheable en el home: cada visita golpea el origen.Escala: Crítico (bloquea indexación o mide mal el negocio) · Alto · Medio · Bajo. Cada uno con evidencia reproducible.
curl -A Googlebot …/products/makers-mark-bourbon-whiskey-750ml → 190 KB; el texto visible del <body> es el menú, «Home / Collections / ZERO STOCK / Makers Mark…» y el footer. Sin H1, sin precio, sin descripción, sin add-to-cart. Tras renderizar en Chrome aparecen. Lo mismo en colecciones: el grid no está en el HTML. La consola registra Hydration failed because the initial UI does not match what was rendered on the server ×2–4 por página; React descarta el HTML del servidor y vuelve a pintar.
Arreglo: corregir el mismatch (el error señala <script type="application/ld+json"> con type null en servidor vs cliente, y la prop fetchPriority en <meta>) y renderizar nombre, precio, descripción y grid en el servidor — Hydrogen lo soporta; hoy está en defer/streaming.
Muestra de 61 productos de 8 sitemaps repartidos (1, 25, 60, 100, 140, 180, 220, 233): 49 OutOfStock / 12 InStock en el JSON-LD. Extrapolado a 28,108 URLs → ~22,500 páginas sin stock, todas index,follow, todas en el sitemap con changefreq: weekly. Entre ellas, inventario de POS: Perrier 11oz, Michelob Ultra 12oz, Red Bull 8oz, Faygo Cream Soda, «Plastic Coffee Mug 8 Oz 10pk».
Arreglo: agotado sin fecha de reposición → noindex + fuera del sitemap (+301 a la colección si lleva >90 días); sacar los productos de POS del canal Online Store (por canal, sin borrar); sitemap filtrado por disponibilidad.
31 enlaces del mega-menú («Shop by Region», «Shop by Country») → /wines?filter.region=Napa+Valley → 301 → /collections/wines?filter.region=Napa+Valley → canonical /collections/wines sin filtro. Las colecciones de región y país que sí existen (/collections/napa-valley, /collections/france-1, /collections/italy-1) no reciben ningún enlace desde el header.
Arreglo: apuntar el menú a las colecciones reales; si se mantiene el filtro, canonical al filtro de primer nivel y una colección por región/país.
/collections/cabernet-sauvignon: «357 Products», 12 enlaces a producto en el DOM y un <button>LOAD MORE</button>. ?page=2 devuelve 200 con canonical a la página 1. Los otros 345 productos sólo se descubren por sitemap.
Arreglo: paginación con <a href="?page=N"> real (Hydrogen Pagination), canonical auto-referente por página.
En el sitemap y con index,follow: zero-stock, no-image, no-description, no-description-spirits, in-stock-all, in-stock-import-wine, in-stock-domestic-wines, in-stock-spirits, wallys-products-to-archive, discountable, retag, fb-insta, popular-on-meta, mid-spirits, high-spirits, top-end, wine_offers. El breadcrumb de un PDP muestra «Home / Collections / ZERO STOCK / …».
Arreglo: noindex + fuera del sitemap + excluir del breadcrumb. Sin borrar nada: son colecciones de trabajo del equipo.
loire/loire-1, california-1/california-2, pinot-gris-grigio/-1, bordeaux-blend/bordeaux-blends, champagne/champagne-sparkling/champagne-sparkling-wine, wine/wines, gift-card/gift-cards, france-1, italy-1, united-states-1, alsace-1, burgundy-1, rhone-1. Ocho *-december-sale más mothers-day-baskets, fifa-world-cup-collection, thanksgiving-by-wallys, easter-passover-baskets, womens-day vivas hoy.
Arreglo: consolidar con 301; estacionales → noindex fuera de temporada o URL perenne que se rellena cada año.
/homepage duplica el home y tiene mejor metadescripción200, index,follow, canonical a sí mismo, en sitemap-sanity.xml, título «Shop Wally's | …». Es el documento de Sanity del home publicado como página aparte.
Arreglo: 301 a / y fuera del sitemap.
/Products/Makers-Mark-Bourbon-Whiskey-750ml → 200 con canonical a la versión en mayúsculas. Cualquier variante genera un duplicado indexable. Trailing slash sí canoniza bien.
El índice lista sitemap-empty.xml (devuelve HTML 404), sitemap/pages/1.xml y sitemap/articles/1.xml contienen únicamente /. Los 233 sitemaps de producto traen lastmod = hora de la petición. Tres tardaron >40 s en responder hoy.
/search y /collections indexablesAmbos 200, index,follow, canonical propio. /search con Klevu genera resultados infinitos.
/collections/all/collections/all → 302 a /products (debería ser 301). Los 404 devuelven 404 + noindex + 159 KB.
Lighthouse móvil: home Perf 56, LCP 3.8 s, TBT 1,020 ms, TTI 16.5 s, peso total 10,960 KiB, del cual cdn.sanity.io/files/…/d7145a0777fc….mp4 = 8,712 KiB. Hero de video sin poster optimizado, servido igual a móvil y escritorio.
Arreglo: poster WebP + preload="metadata", versión móvil ≤1 MB o imagen estática en móvil; mover el MP4 a Mux (ya está en el CSP).
| Página | Perf | LCP | TBT | CLS | TTI | Peso |
|---|---|---|---|---|---|---|
| Home | 56 | 3.8 s | 1,020 ms | 0 | 16.5 s | 10,960 KiB |
| /collections/caviar | 39 | 15.9 s | 530 ms | 0.245 | 19.0 s | 2,413 KiB |
| PDP Makers Mark 46 | 54 | 6.2 s | 670 ms | 0 | 17.3 s | 2,326 KiB |
El grid llega tarde (C1) y se mueve al cargar. JavaScript sin usar ~600 KiB por página; scripts totales 1.75 MB. Campo (CrUX): no comprobado — PageSpeed API 429 sin key.
454 requests por PDP. Klaviyo 73, Gorgias 63, UserWay 31, LinkedIn 11, Google Ads 10, Bing 9. Dos Hotjar. Tres proveedores de fuentes. GTM carga gtag/js + gtag/destination + gtm.js = 507 KB.
Arreglo: Gorgias/UserWay/Klaviyo tras interacción; eliminar un Hotjar; una fuente.
HTTPS en todo, HSTS 1 año, CSP con nonce, nosniff, sin mixed content. http://wallywine.com da dos saltos (→ https://wallywine.com → https://www).
PUBLIC_STOREFRONT_API_TOKEN, KLEVU_KEY, USERWAY_ACCOUNT_ID y SANITY_STUDIO_USE_PREVIEW_MODE: "true" viajan en el loader data. Los públicos son públicos por diseño; el flag de preview en producción conviene revisarlo con dev.
Renderizado en Chrome headless y headed (dos UAs, 3 corridas): el DOM del home tiene 0 <h1>, 0 <h2>, 0 <header>, 0 <nav>, 4 <h3> (FINE + RARE, CAVIAR, GIFT BASKETS, TASTINGS + EVENTS) y 16 enlaces únicos (3 a colecciones, resto footer y redes). Texto visible: 591 caracteres. En PDP y colecciones el header sí se monta (116 enlaces, 69 a colecciones). Desde el home, Google llega a 3 colecciones.
Verificar con el cliente: si el header ausente en / es intencional (landing de video) o un bug de la ruta _index. Para SEO es un home que no enlaza al catálogo.
Las 266 se descargaron hoy: 236 sin meta description, 266 con título terminado en «| Collection» (sin marca, sin modificador). El H1 de colección no está en el HTML servido (C1). No hay texto de colección arriba del grid.
Arreglo: plantilla «{Colección} — Buy Online | Wally's Wine & Spirits» + descripción desde Sanity/Shopify con fallback.
30 sin metadescripción; 28 con la descripción del JSON-LD truncada a ~150 caracteres terminando en «...». Las que existen son texto generado sin datos («In the soft hush of an evening fire, Makers Mark Bourbon Whiskey emerges as a quiet masterpiece…»): sin región, sin puntuación de crítica, sin maridaje, sin ABV. La consola avisa description should not be longer than 155 characters en cada carga.
Arreglo: descripción estructurada por atributos (los filtros ya los tienen: Varietal, Vintage, Region, Appellation, Size) + notas de cata; las puntuaciones de críticos que ya se muestran en tarjetas («WA | 98+», «V | 97») como texto y como Review.
Product con errores que Google va a marcarbrand.name = distribuidor, no marca: «Southern Wine & Spirits» (11/61), «Republic National Distributing Co.», «BREAKTHRU Beverage», «Coca Cola Refreshments», o nombres de persona («JOANNE», «Mark P Goodman»). El campo vendor de Shopify se mapea a brand.sku: "" en todos; sin gtin, sin aggregateRating, sin Review aunque las puntuaciones existen en la UI.offers.url con ?Title=Default+Title; description truncada con «...».BreadcrumbList con «Products» como raíz y sin item en el último nodo.Organization.url cambia por página y sameAs tiene 4 strings vacíos. WebPage.name: "Home page" en todas las páginas.Restaurant en las 4 tiendas, nada en /locations, sin horarios ni menúCorrección a la primera versión: /beverlyhills, /santamonica, /malibu y /lasvegas sí llevan JSON-LD Restaurant (medido en el DOM renderizado). Lo que falta: /locations sólo tiene Organization; horarios visibles sólo en Las Vegas; teléfono en 3 de 4; no existe página de menú (/menu → 404); las reservas van a OpenTable y SevenRooms sin acceptsReservations en el schema. Los campos del Restaurant quedan por verificar uno a uno en fase 2.
Renderizadas hoy: /locations (591 caracteres = banner de cookies + footer), /reservations (576) y /staffpicks (576) están vacías con 200, index,follow y en el sitemap. Además, seis borradores de rediseño publicados: /homepage-redesign, /restaurant-redesign, /beverlyhills-redesign, /events-redesign, /eventlisting-redesign, /redesign — todos 200, indexables, en blanco, con título genérico. /reservations y /locations son donde aterriza la búsqueda de marca de un restaurante. En TOOUS el 61 % de las vistas caía en páginas en blanco por una sección desactivada; aquí el mecanismo es distinto y el efecto es el mismo. Cuánto tráfico reciben: requiere GA4.
Arreglo: noindex + fuera del sitemap para los *-redesign; contenido real en /locations y /reservations (los enlaces de OpenTable ya existen en el footer de las páginas de tienda). /catering lleva el título de /private-dining; ninguna de las dos tiene H1.
alt2 de 8 en home y en cada plantilla (logo/hero). Arreglo trivial.
Correcto para el negocio actual. Nada que arreglar.
Autoridad y backlinks: no comprobado — Ahrefs no respondió hoy (token del conector inválido). Al reconectar: DR, dominios de referencia, backlinks rotos, keywords, top pages, competidores y tráfico con fecha y rango.
robots.txt no bloquea GPTBot, ClaudeBot, PerplexityBot ni Google-Extended: pueden entrar./llms.txt, sin /agents.md, sin endpoint MCP/UCP (/api/ucp/mcp → 404). Shopify lo da en Online Store; en Hydrogen hay que exponerlo.Product sí está en el HTML: hoy es la única señal legible por máquina — con brand = distribuidor y descripción cortada, es una señal equivocada.fbevents.js y signals/config/487230146902047 se descargan en cada página; 0 requests a facebook.com/tr en home + 2 PDPs + add-to-cart, antes y después de aceptar cookies. fbq existe y su cola está vacía. Si hay pauta en Meta, hoy no hay PageView, ViewContent ni AddToCart del pixel del navegador (CAPI desde Shopify, si existe, es aparte).
Requiere acceso: GTM (tag pausado o bloqueado por consentimiento) y Events Manager.
dataLayer e-commerce con items como objeto, no arreglo{"event":"view_item","ecommerce":{"currency":"USD","price":32,
"items":{"item_id":"gid://shopify/Product/8679633518842",
"item_name":"Makers Mark Bourbon Whiskey 750mL","price":32}}}
{"event":"add_to_cart","ecommerce":{"currency":"USD","value":40,
"items":{"item_id":"gid://shopify/Product/8733651435770",
"item_name":"Makers Mark 46 Bourbon Whiskey 750mL","price":40,"quantity":1}}}
GA4 espera items: [ {…} ]. Con un objeto, el evento llega sin ítems: informes de producto, ingresos por ítem y embudo quedan vacíos o parciales. item_id es el GID de Shopify, no el SKU. view_item sin value. No se observó view_item_list (la colección emite collection_viewed dos veces), ni select_item, ni begin_checkout. Checkout vive en cbbc83-3.myshopify.com: cross-domain no comprobado.
Requiere acceso: GA4 DebugView y GTM para confirmar que el tag no re-mapea el objeto.
El primer analytics.google.com/g/collect?en=page_view salió antes de tocar el banner de Shopify («We value your privacy… Accept / Decline»). El hit lleva gcd=13l3l3l3l1l1 y dma=0: no hay consent default/update. Klaviyo, Bing, LinkedIn y Hotjar también disparan de entrada. «Decline» no apaga nada.
Dos Hotjar (3902686, 2599820). collection_viewed ×2 por página. page_viewed custom además del page_view de GA4. UTMs: sin pauta activa observable desde fuera (no comprobado).
| Confirmado hoy desde fuera | Requiere GA4 / GTM / GSC / Ads |
|---|---|
| GTM, GA4, Ads, Meta, Bing, LinkedIn, Klaviyo, Hotjar ×2 presentes | Si el tag de Meta está pausado o bloqueado por consentimiento |
GA4 page_view se envía; Meta /tr no | Cross-domain hacia el checkout myshopify |
items es objeto en view_item y add_to_cart | Si GTM lo re-mapea antes de enviarlo a GA4 |
Sin Consent Mode (gcd), tags antes de aceptar | Enhanced conversions, CAPI, deduplicación event_id |
Sin view_item_list, select_item, begin_checkout en el front | purchase (sólo visible en checkout) |
Sin Ahrefs no hay comparación de tráfico ni autoridad (pendiente). Lo técnico, medido hoy con la misma llamada (HTML del servidor con UA Googlebot, home):
| Sitio | Plataforma | Texto en HTML servido | Enlaces internos | H1 en HTML |
|---|---|---|---|---|
| wallywine.com | Hydrogen/Oxygen | 1,334 chars | 8 | ninguno |
| flaskfinewines.com (LA) | Shopify OS | 11,134 | 130 | «Fine Wine & Whisky Merchants Since 1962» |
| hitimewine.net (Costa Mesa) | BigCommerce | 5,607 | 30 | «Hi-Time Wine Cellars» |
| klwines.com · wine.com | — | bloquean al UA Googlebot desde esta IP | ||
Los dos competidores regionales comparables entregan a Google entre 4 y 8 veces más contenido y de 4 a 16 veces más enlaces en el primer byte.
No comprobado hoy. Fuente prevista: Ahrefs (cuenta de pago, conector de claude.ai) → Access denied: MCP token is invalid en 2 llamadas. Índice de Bing: site:wallywine.com/products «About 118,000 results» y site:wallywine.com «About 50» — inconsistente, no sirve como cifra.
Al reconectar Ahrefs se entregan: tráfico orgánico mensual estimado y tendencia 24 meses, keywords por posición, top pages, branded vs non-branded, países, DR y dominios de referencia, backlinks rotos, competidores con solape. Con fecha, metodología y rango — nunca presentado como analítica interna.
Sin rediseño: código y configuración.
/wines?filter… (C3).noindex + fuera del sitemap: colecciones internas (A2), /homepage → 301 (A4), /search, sitemap-empty.xml (M2).dataLayer.items a arreglo, item_id = SKU, value en view_item (C5). Revisar tag de Meta (C4). Quitar un Hotjar (M8).preload=metadata al video del home (A5).brand desde metafield, sku del variant, sameAs limpio (M5).Necesita al equipo de Hydrogen.
Review/aggregateRating (A9, M5).Store con dirección, horario, geo para las 4 tiendas (M6).llms.txt, endpoint de catálogo para agentes (A10).view_item_list, select_item, begin_checkout, cross-domain, CAPI con event_id.Cómo se mide el éxito: cobertura en GSC (indexadas con contenido vs «Rastreada, sin indexar»), clics no-marca en colecciones de región/varietal, LCP de campo en colecciones, e-commerce de GA4 con ítems poblados. Baseline el día 1 del proyecto.
https://www.wallywine.com/G-DDRQ9T5MZ2 (DebugView, e-commerce) y GTM GTM-MNRVWXQ1070057468 y Meta Events Manager del pixel 487230146902047in-stock-*, no-image, retag son de operación diaria?Review real.