Files
MNQ-Catering-y-Evento/docs/seo-audit/mnqcatering.com-audit/findings/schema.md
T
manuyasm87 b084aeff6e fix(seo): exclude noindex aviso-legal page from sitemap; add full audit report
Sitemap filter was excluding cookies/ and privacidad/ but not
aviso-legal/, even though that page is marked noindex,follow -- a
noindexed page has no business being listed for crawl discovery.

Also adds docs/seo-audit/mnqcatering.com-audit/ -- the full multi-agent
SEO audit run this session against the corrected live domain
(www.mnqeventos.es), including the FULL-AUDIT-REPORT.md, ACTION-PLAN.md,
and per-category findings files.
2026-09-15 10:19:00 +02:00

13 KiB
Raw Blame History

Structured Data (JSON-LD) Audit — mnqcatering.com

Audited: 2026-09-15 Method: Source review (src/layouts/MainLayout.astro, src/pages/*.astro) cross-checked against the actual SSR output. Live https://www.mnqcatering.com was not directly reachable from this environment (no outbound DNS/network), so the site's own Node/Astro SSR server (@astrojs/node, output: 'server') was built and run locally against the committed HEAD (0e242a6, working tree clean for src/), and pages were requested with Host: www.mnqcatering.com to reproduce byte-identical rendered HTML for /, /bodas-reales, /corporativo-business, /reuniones-familiares, /contacto. This is equivalent to fetching the live pages for structured-data purposes since output is fully server-rendered (no client-side JSON-LD injection to compare against — raw and rendered HTML are the same thing here).

Summary

Every page emits one sitewide JSON-LD block (business identity) via MainLayout.astro, plus a page-specific FAQPage block on four pages. Both blocks are syntactically valid JSON, use https://schema.org as @context, and (for FAQPage) mirror the visible on-page FAQ content — no invisible/mismatched schema found. However, the sitewide block uses @type: "CateringService", which is not a valid schema.org type — this is a critical defect that likely causes the whole block to be ignored or mis-typed by Google and other consumers. There's also a non-standard property (serviceType) riding on the invalid type. BreadcrumbList, image, priceRange, geo, and sameAs are all missing opportunities. FAQPage markup is correctly kept per the current no-rich-result policy (see below).

Detection Results

Page Blocks found
/ (home) 1× CateringService (site-wide)
/bodas-reales 1× CateringService + 1× FAQPage (3 Q&A)
/corporativo-business 1× CateringService + 1× FAQPage (3 Q&A)
/reuniones-familiares 1× CateringService + 1× FAQPage (3 Q&A)
/contacto 1× CateringService + 1× FAQPage (3 Q&A)
/nosotros, /aviso-legal, /privacidad, /cookies 1× CateringService only (no page-specific schema — expected, no FAQ content on these)

Format: JSON-LD only (no Microdata/RDFa found), injected via <script is:inline type="application/ld+json" set:html={JSON.stringify(schema)} /> in MainLayout.astro:137. Correctly server-rendered (present in raw HTML, not client-injected).

Validation Results

1. Sitewide business block — @type: "CateringService" — FAIL (Critical)

Evidence (identical on every page, e.g. homepage):

{
  "@context": "https://schema.org",
  "@type": "CateringService",
  "name": "MNQ Catering y Evento",
  "url": "https://www.mnqcatering.com",
  "description": "Servicio de catering para bodas, eventos corporativos y reuniones familiares con enfoque premium.",
  "telephone": "+34 678 17 15 13",
  "serviceType": ["Bodas", "Eventos corporativos", "Reuniones familiares"],
  "address": { "@type": "PostalAddress", "streetAddress": "Calle Camino Vivero, 6", "postalCode": "29014", "addressLocality": "Málaga", "addressRegion": "Málaga", "addressCountry": "ES" },
  "areaServed": [{ "@type": "City", "name": "Málaga" }, { "@type": "AdministrativeArea", "name": "Provincia de Málaga" }],
  "contactPoint": { "@type": "ContactPoint", "contactType": "customer service", "telephone": "+34 678 17 15 13", "availableLanguage": ["es"] }
}

Problem: CateringService does not exist in the schema.org vocabulary. The correct type for a catering business is CateringBusiness, a LocalBusiness → FoodEstablishment subtype (schema.org/CateringBusiness). Because CateringService isn't a recognized type, Google's Rich Results Test / structured data parsers will either flag it as an unrecognized type or silently drop type-specific interpretation, and any generic-type fallback loses LocalBusiness inheritance (address, telephone, geo, openingHoursSpecification, priceRange, image all become meaningless without a valid business type backing them).

A second, compounding issue: serviceType is a property of schema.org's Service type, not of LocalBusiness/FoodEstablishment/CateringBusiness. Even after fixing the @type, serviceType would still be an out-of-vocabulary property on this type. The three service lines (Bodas, Eventos corporativos, Reuniones familiares) are better modeled as makesOffer → Offer.itemOffered → Service entities, or dropped from the top-level entity and left for each landing page's own content/FAQ.

Recommendation — fix @type to CateringBusiness and restructure services in MainLayout.astro:

{
  "@context": "https://schema.org",
  "@type": "CateringBusiness",
  "name": "MNQ Catering y Evento",
  "url": "https://www.mnqcatering.com",
  "description": "Servicio de catering para bodas, eventos corporativos y reuniones familiares con enfoque premium.",
  "telephone": "+34678171513",
  "priceRange": "$$$",
  "image": "https://www.mnqcatering.com/images/foto-bodas.jpg",
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "Calle Camino Vivero, 6",
    "postalCode": "29014",
    "addressLocality": "Málaga",
    "addressRegion": "Málaga",
    "addressCountry": "ES"
  },
  "areaServed": [
    { "@type": "City", "name": "Málaga" },
    { "@type": "AdministrativeArea", "name": "Provincia de Málaga" }
  ],
  "contactPoint": {
    "@type": "ContactPoint",
    "contactType": "customer service",
    "telephone": "+34678171513",
    "availableLanguage": ["es"]
  },
  "makesOffer": [
    { "@type": "Offer", "itemOffered": { "@type": "Service", "name": "Catering para bodas" } },
    { "@type": "Offer", "itemOffered": { "@type": "Service", "name": "Catering para eventos corporativos" } },
    { "@type": "Offer", "itemOffered": { "@type": "Service", "name": "Catering para reuniones familiares" } }
  ]
}

Notes on this snippet:

  • telephone normalized to E.164 (+34678171513, no spaces) — more consistently parsed than "+34 678 17 15 13" (minor, non-blocking, but worth fixing while editing this block anyway).
  • priceRange is a placeholder pattern ("$$$") — replace with a real value the business is comfortable publishing, or omit if there's no defensible public price band yet. Do not ship a placeholder string.
  • image currently points at an existing OG image already used elsewhere in the layout (ogImage default) — reuse rather than invent a new asset, but confirm it visually represents the business (a plated dish or venue photo would be preferable to a wedding hero if one exists).
  • geo, sameAs, aggregateRating intentionally omitted here — see dedicated sections below (all pending real data, not fabricated).

2. FAQPage on 4 pages — PASS (structurally), Info-priority per current Google policy

Evidence: bodas-reales.astro, corporativo-business.astro, reuniones-familiares.astro, contacto.astro each emit a FAQPage with 3 Question/acceptedAnswer pairs. Checked against rendered output — all 3 Q&A pairs on each page are also rendered as visible <article class="faq-item"> content in the same page, so there's no hidden/mismatched-content violation.

Structural validation:

  • ✅ @context: "https://schema.org"
  • ✅ @type: "FAQPage", nested Question/Answer types correct
  • ✅ Required properties present (mainEntity, name, acceptedAnswer.text)
  • ✅ No placeholder text
  • ✅ Content matches visible page content

Policy note (per current Google guidance): Google retired FAQ rich results for all sites (May 7, 2026), so this markup no longer produces a SERP rich result. Per current guidance this is Info priority, not a defect — keep it in place, since it still aids AI/LLM citation and entity/answer extraction (ChatGPT, Perplexity, Gemini, AI Overviews). No action required; do not remove it, and do not add more FAQPage blocks expecting SERP benefit — any future FAQ-style page should be evaluated as GEO/AI-visibility content, not a rich-result play.

One structural nit worth a look: these are genuinely marketing FAQ content (pricing/coverage questions the business anticipates), not a user-generated Q&A page, so FAQPage (not QAPage) is the correct type choice here — no change needed.

3. Missing: BreadcrumbList — Opportunity (Medium)

Evidence: No BreadcrumbList found on any page. Google supports breadcrumb rich results (still active, not deprecated), and the site has a clear, shallow hierarchy (Home > Bodas Reales, Home > Corporativo & Business, Home > Reuniones Familiares, Home > Contacto) that maps directly to nav (SiteHeader.astro activeNav).

Recommendation (example for /bodas-reales):

{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [
    { "@type": "ListItem", "position": 1, "name": "Inicio", "item": "https://www.mnqcatering.com/" },
    { "@type": "ListItem", "position": 2, "name": "Bodas Reales", "item": "https://www.mnqcatering.com/bodas-reales" }
  ]
}

Repeat per page with the matching second crumb (Corporativo & Business → /corporativo-business, Reuniones Familiares → /reuniones-familiares, Contacto → /contacto). Cheapest way to add this: compute it in MainLayout.astro from the existing activeNav/title props and pass it into the structuredDataScripts array alongside the FAQ block, rather than hand-writing it on each page.

4. Missing: geo (GeoCoordinates) — Acknowledged, correctly deferred

Confirmed absent from the address block. Per the known-state note, this is intentionally withheld pending a confirmed Google Business Profile pin rather than an oversight — correct call; do not fabricate lat/long. Once available:

"geo": { "@type": "GeoCoordinates", "latitude": 36.xxxxx, "longitude": -4.xxxxx }

5. Missing: sameAs — Acknowledged, correctly deferred

No social profile URLs in the schema, matching the known state (no confirmed profiles yet). Do not add placeholder/guessed URLs. Once Instagram/Facebook/LinkedIn profiles are confirmed live and owned by the business:

"sameAs": ["https://www.instagram.com/<handle>", "https://www.facebook.com/<handle>"]

6. Missing: Review / AggregateRating — Acknowledged, correctly deferred

No review schema present, matching known state. Do not add this without real, verifiable reviews — AggregateRating/Review markup requires genuine user-submitted reviews per Google's structured data policy; fabricating or estimating a rating is a policy violation that can trigger a manual action. Revisit once real reviews exist (Google Business Profile, testimonials with attribution, etc.).

7. Duplicate sitewide block per page — Info, not a defect

Every page repeats the full CateringBusiness/CateringService block rather than referencing a single @id-linked entity via @graph. This is common and acceptable practice for a small static-ish site (each page is self-contained for crawlers that don't execute JS or follow references), so not flagged as an issue — but if the block grows substantially (e.g., after adding makesOffer, geo, sameAs, image), consider consolidating into a @graph with @id references from per-page WebPage/FAQPage nodes to avoid repeating a large block on every request. Not urgent.

Score: 62 / 100

Deductions:

  • −25: Invalid @type (CateringService doesn't exist) on the one schema block present on every page of the site — this is the single highest-impact fix available, since it currently likely undermines rich-result/entity recognition for the whole business identity block.
  • −5: Non-standard serviceType property riding on that invalid type.
  • −5: telephone not in E.164 format (minor/cosmetic).
  • −3: No BreadcrumbList despite a hierarchy that trivially supports it.

Not deducted (correctly deferred, not defects): missing geo, sameAs, Review/AggregateRating — all withheld pending real data, which is the right call rather than fabricating values.

What already works well

  • JSON-LD only, no legacy Microdata/RDFa to reconcile — clean baseline.
  • https:// context, absolute URLs throughout, ISO-correct address structure.
  • Server-rendered, present in raw HTML (not client-injected) — fully crawlable without JS execution.
  • FAQ schema content matches visible page content exactly — no hidden-text schema abuse anywhere.
  • Correct restraint on geo, sameAs, and AggregateRating — nothing fabricated or guessed to fill gaps, which is exactly right per Google's structured-data policies.
  • No deprecated types used (no HowTo, SpecialAnnouncement, CourseInfo, etc.).
  • Address, areaServed, and contactPoint are properly structured and consistent across every page.