ReviewOS

stacks/paweldregan

SEO: per-page Open Graph + Twitter Card meta tags (revisit pattern)

#5
Closed glennmichael123 opened this 8 days ago ·
8 days ago

Context

Link-preview crawlers (Slack, Twitter, iMessage, agent integrations) currently render no preview when a paweldregan.com URL is shared — the pages have no Open Graph or Twitter Card meta tags. An agent recently flagged it because it couldn't find the site reliably from a shared link.

A first attempt landed in commit 07b21ef — full per-page <meta property="og:*"> + <meta name="twitter:*"> blocks added directly inside each page's <head>. That implementation was reverted in the working tree because it duplicated meta blocks across all 5 pages and bypassed the site-level config.

The image assets transferred from stacksjs/ultrarunner-paw (public/images/*.jpg, including og.jpg) are still committed and useful here either way.

Goal

Hook OG / Twitter meta into the existing site.config.ts per-page metadata so each page automatically renders the right tags without duplicating boilerplate per .stx file.

The shape is already there:

// site.config.ts
pages: {
  '/': {
    title: '…',
    description: '…',
    priority: 1.0,
    changefreq: 'weekly',
  },
  '/about': { … },
  '/races': { … },
  '/coaching': { … },
}

Each page declaration just needs to extend with (or default to) an image field, and the layout/head needs to render the resolved values into the right <meta> tags.

Scope

  • Extend site.config.ts pages: {} entries with an optional image field (defaults to a site-wide seo.defaultImage).
  • Add an seo.defaultImage to defineSiteConfig's seo section pointing at /images/og.jpg.
  • Implement a single shared <head> partial / mechanism that, given the current route, looks up the page config and emits:
    • <meta name="description"> (uses page's description)
    • Open Graph: og:type, og:site_name, og:title, og:description, og:url, og:image, og:image:width, og:image:height, og:locale
    • Twitter: twitter:card=summary_large_image, twitter:site=@ultrarunnerpaw, twitter:title, twitter:description, twitter:image
  • Locale-aware: when the active locale is de or pl, the meta description should pull from the matching translation. Same for og:locale (en_US / de_DE / pl_PL).
  • 404 page: keep <meta name="robots" content="noindex"> but still render a sensible OG block (so a shared 404 link still previews the brand).

Verification

  • View-source on each page (/, /about, /races, /coaching, plus a 404) and confirm the meta tags are present + correct.
  • Paste each URL into the Twitter Card validator and the Facebook Sharing Debugger — preview should show the right title, description, and image.
  • Paste in Slack/iMessage — same.

Out of scope

Dynamic per-page OG image rendering (Swiss Alps bg + per-page text overlay) is its own issue.

8 days ago

Resolved in 353e857. layouts/default.stx is now meta-free; per-page <title>, <meta description>, og:, twitter:, canonical, and hreflang are injected at build time by buildStaticSite from site.config.ts pages[*]. Verified against bun run build output for /, /about, /races, /coaching, /404 across en/de/pl.

Sign in to comment on this issue.