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.
13 KiB
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:
telephonenormalized 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).priceRangeis 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.imagecurrently points at an existing OG image already used elsewhere in the layout (ogImagedefault) — 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,aggregateRatingintentionally 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", nestedQuestion/Answertypes 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(CateringServicedoesn'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
serviceTypeproperty riding on that invalid type. - −5:
telephonenot in E.164 format (minor/cosmetic). - −3: No
BreadcrumbListdespite 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, andAggregateRating— 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, andcontactPointare properly structured and consistent across every page.