# SEO, Schema and Launch Audit

> **Scope:** frontend-seo
> **Layer:** 3
> **Keywords:** seo, meta tags, open graph, schema.org, json-ld, rich results, lighthouse, accessibility, go-live audit
> **Load When:** any public-facing page is being built or is about to go live

**Verified against:** Schema.org vocabulary + Lighthouse via Chrome DevTools MCP, shipped to production. Last-verified: 2026-08-21.

---

A page that cannot be found and does not share well is half delivered. This layer is cheap (almost all of it lives in `<head>`) and pays for itself. Covers the essential meta set, Open Graph, JSON-LD by business type, the accessibility items that also affect ranking, and the audit to run before going live.

---

## Section 1: Essential Meta

```html
<title>{Brand} · {short value proposition in {city}}</title>
<meta name="description" content="{1-2 sentences: what it does, where, and a differentiator or proof}" />
<link rel="canonical" href="https://{domain}/" />
<meta name="theme-color" content="{brand background color}" />
<link rel="icon" type="image/png" href="/img/{favicon}.png" />

<!-- font preconnect: measurable performance win -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
```

- **`title`**: brand plus proposition plus place, when it is a local business. Do not stuff keywords.
- **`description`**: what it sells, to whom, where, plus a proof hook (rating, years, differentiator).
- **`canonical`**: always present, to avoid duplicate-URL dilution.
- **`lang`**: set the real locale on `<html>` (for example `lang="pt-BR"`).

---

## Section 2: Open Graph and Twitter Cards

Without these, a link pasted into WhatsApp, Instagram or LinkedIn renders as a bare, ugly card. With them, it renders as an image card.

```html
<meta property="og:type" content="website" />
<meta property="og:locale" content="pt_BR" />
<meta property="og:site_name" content="{Brand}" />
<meta property="og:title" content="{share title, can be more emotional than the SEO title}" />
<meta property="og:description" content="{one sentence}" />
<meta property="og:url" content="https://{domain}/" />
<meta property="og:image" content="https://{domain}/img/{share-image}.jpg" />
<meta name="twitter:card" content="summary_large_image" />
```

`og:image` should be 1200x630 and must use an absolute URL. Use the strongest image on the page.

---

## Section 3: Schema.org (JSON-LD) by Business Type

Structured data is what earns rich results (stars, address, opening hours). Pick `@type` from the business:

| Business | `@type` |
|---|---|
| Retail, fashion, tailoring | `ClothingStore` or `Store` |
| Local service (clinic, studio, workshop) | `LocalBusiness` or a specific subtype |
| Property developer, real estate | `RealEstateAgent`, or `Residence` / `Apartment` |
| Restaurant, food | `Restaurant` |
| SaaS, software | `SoftwareApplication` or `Organization` |
| Independent professional | `ProfessionalService` |

```html
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "ClothingStore",
  "name": "{Brand}",
  "image": "https://{domain}/img/{hero}.jpg",
  "description": "{description}",
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "{street, number}", "addressLocality": "{city}",
    "addressRegion": "{state}", "postalCode": "{zip}", "addressCountry": "BR"
  },
  "telephone": "+55-XX-XXXXX-XXXX",
  "url": "https://{domain}/",
  "aggregateRating": { "@type": "AggregateRating", "ratingValue": "4.9", "reviewCount": "74" },
  "openingHours": "Mo-Fr 09:00-18:00"
}
</script>
```

**Include only true fields.** `aggregateRating` goes in only with a real number from a real source (for example the client's Google rating and review count). Never invent a rating. With no real data, omit the block entirely. Fabricated structured data is both a trust problem and a manual-action risk.

---

## Section 4: Accessibility (Also An SEO Signal)

- `lang` set correctly on `<html>`.
- Descriptive `alt` on every content image, including video posters.
- Sufficient contrast for text over media. Check against the brightest frames, not the average. See `frontend/design-system/premium-finish.md`.
- Logical focus order, visible `:focus-visible`.
- Overlays carry `role`, `aria-modal`, and close on Escape.
- `prefers-reduced-motion` honored: scroll-driven effects do not mount.
- Coherent heading hierarchy: exactly one `<h1>`, then `<h2>` / `<h3>`.

---

## Section 5: Pre-Launch Audit

"Premium" is confirmed by measurement, not by vibe. Run this before the go-live gate and fix what hurts:

| Check | How | Pass condition |
|---|---|---|
| Lighthouse | Chrome DevTools MCP `lighthouse_audit` | Performance, SEO, Best Practices, Accessibility reviewed and explained |
| Console | Desktop and mobile viewport | Zero errors |
| Share card | Paste the URL into an OG validator or a test chat | Image card renders with the right title |
| Technical SEO | `seo-analyzer` pass over meta, headings, links | No missing or duplicated essentials |
| Cross-device | Desktop, tablet, mobile; Safari or iOS included | Layout holds, motion fallbacks fire |

**On Performance specifically:** a heavy frame sequence (see `frontend/scroll-driven/frame-scrub.md`) will cost Performance points. That is an accepted, deliberate trade. What must be confirmed is that the cost sits in the scrub and not in unoptimized images, dead JS, or missing compression. State the trade explicitly rather than letting a low score pass unexamined.

Record the audited viewports and the Lighthouse result alongside the go-live decision.

---

## Checklist

- [ ] Title, description, canonical, theme-color, favicon in place
- [ ] `lang` correct on `<html>`
- [ ] Font preconnects present
- [ ] Full Open Graph set with an absolute 1200x630 `og:image`
- [ ] JSON-LD present, `@type` matched to the business, every field true
- [ ] `aggregateRating` backed by real data, or omitted
- [ ] Alt text, focus order, heading hierarchy, reduced-motion verified
- [ ] Lighthouse run; any Performance cost traced to a deliberate trade
- [ ] Console clean, share card verified, cross-device pass recorded
