OctoWiki
Memory Appendix

Og Image Per Page Routes

When adding /blog/[slug], /cards/[slug], or similar shareable page types to octopus-website, ensure the corresponding /og/<section>/[slug] route handler exists

Source memory file: feedback_og_image_per_page_routes.md · Category: Feedback / working-preference This is a verbatim dump of Claude's persistent memory for the Octopus project. Rendered inside a code block so nothing is altered.

---
name: New shareable page sections need per-page OG image routes
description: When adding /blog/[slug], /cards/[slug], or similar shareable page types to octopus-website, ensure the corresponding /og/<section>/[slug] route handler exists — page.tsx can declare OG URLs that silently 404
type: feedback
originSessionId: a1e9a8ef-0505-4d0d-ae0a-97b98d29076c
---
When adding a new `/<section>/[slug]` page type to `frontend/octopus-website/` where the pages will be shared on social/chat (cards, blog posts, product detail pages, etc.), create a matching `src/app/og/<section>/[slug]/route.tsx` that renders a per-page OG card — not just the root `opengraph-image.tsx` fallback.

**Why:** We found that `src/app/cards/[slug]/page.tsx` had been declaring:

```ts
openGraph: { images: [{ url: `${SITE_URL}/og/cards/${slug}`, ... }] }
```

…but no route handler existed at that path. Every card page was advertising a **broken 404 OG image URL**. Next.js doesn't warn; the page builds cleanly; unfurlers silently fail. Root OG image does NOT fall back in — an explicit per-page `openGraph.images` override replaces the inherited root, so pages end up worse than pages with no override at all.

**How to apply:**

When you add or review a new shareable page type in `src/app/`:

1. Check `generateMetadata` in the page — does it declare `openGraph.images` or `twitter.images`?
2. If yes, either:
   - **Remove** the override (fall back to root `opengraph-image.tsx`) if a generic card is fine, OR
   - **Create** the route handler at the exact URL declared, following the pattern in `src/app/og/cards/[slug]/route.tsx` (uses `@takumi-rs/image-response`, `generateStaticParams`, reads brand logo + card art as base64 data URIs at build time).
3. Add `Content-Type: image/png` to `public/_headers` for the new path (see `feedback_cloudflare_pages_extensionless_routes.md`).
4. Verify with `file out/og/<section>/<slug>` that the PNG emitted correctly after build.

**Pattern reference:** `src/app/og/cards/[slug]/route.tsx` — reads product data via `@/lib/products`, composes brand header + product art + name + category chip at 1200×630, works for PNG/SVG/WebP/JPEG card art via a `assetDataUri` helper.

**Skip this for:** legal pages, contact, FAQs, about — these rarely get shared; the inherited root card is appropriate.