Skip to content

CE: Add og:image + Twitter large-card social previews#313

Merged
ericflo merged 1 commit intomainfrom
ce/og-image
Apr 16, 2026
Merged

CE: Add og:image + Twitter large-card social previews#313
ericflo merged 1 commit intomainfrom
ce/og-image

Conversation

@ericflo
Copy link
Copy Markdown
Owner

@ericflo ericflo commented Apr 16, 2026

What

Adds a real 1200x630 branded social-share image so links to modelrelay.io render as professional cards on Twitter, Slack, Discord, iMessage, LinkedIn, etc.

Why

Verified gap before doing the work: `curl https://modelrelay.io/ | grep -iE "og:image|twitter:image"` returned nothing. Every page_shell page and the two static templates (index.html, pricing.html) declared og:title/description/url but no image, and twitter:card was set to `summary` (small thumbnail). Sharing a modelrelay.io link today shows a bare URL with no preview, which looks unfinished next to peers like Stripe, Vercel, Linear.

Changes

  • New `crates/modelrelay-cloud/assets/og-image.png` — 1200x630 PNG, purple-to-blue gradient with the ModelRelay wordmark, tagline, and a minimalist relay icon. Generated with OpenAI gpt-image-1.5 at low quality, cropped and resized to exact social-card dimensions with Pillow.
  • New `/og-image.png` route in `crates/modelrelay-cloud/src/routes/mod.rs`. The PNG is baked into the binary via `include_bytes!` so it ships everywhere the cloud service runs and the CSP `img-src 'self' data:` header stays unchanged (no external host needed). Served with `Cache-Control: public, max-age=86400, immutable`. `/og-image.png` is also added to `SESSION_EXEMPT_ROUTES` so the session guard does not block it.
  • `page_shell_custom` in `crates/modelrelay-web/src/templates.rs` now emits `og:image`, `og:image:width`, `og:image:height`, `og:image:alt`, `twitter:image`, `twitter:image:alt`, and `twitter:card` upgraded from `summary` to `summary_large_image`.
  • The two static templates `crates/modelrelay-cloud/templates/index.html` and `crates/modelrelay-cloud/templates/pricing.html` were updated the same way so every page has a full social-card set.

Tests

  • New `og_image_returns_png` — hits `/og-image.png`, asserts 200, `Content-Type: image/png`, `Cache-Control` with a `max-age`, body > 1000 bytes, and leading PNG magic bytes.
  • New `landing_page_includes_og_image_meta` — confirms the rendered `/` HTML contains og:image, twitter:image, and `twitter:card=summary_large_image`.
  • Updated `pricing_page_has_og_url_and_canonical` to require `summary_large_image` instead of `summary`.
  • `cargo nextest run -p modelrelay-cloud -p modelrelay-web` → 70 passed, 0 failed.
  • `cargo fmt --check` and `cargo clippy -p modelrelay-cloud -p modelrelay-web --tests -- -D warnings` clean.

Manual verification after deploy

- New crates/modelrelay-cloud/assets/og-image.png (1200x630, generated
  via OpenAI gpt-image-1.5) baked into the binary via include_bytes!
- New /og-image.png route in routes/mod.rs (served same-origin so the
  CSP img-src 'self' data: stays unchanged, cache-control 24h) and
  added to SESSION_EXEMPT_ROUTES so session_guard doesn't block it
- page_shell_custom (modelrelay-web) gains og:image/width/height/alt +
  twitter:image/alt, and twitter:card upgraded to summary_large_image
- Static templates index.html and pricing.html updated the same way
- New og_image_returns_png + landing_page_includes_og_image_meta tests
  verify route + PNG magic bytes + meta tags; updated pricing test to
  assert summary_large_image
@ericflo ericflo merged commit f90cd86 into main Apr 16, 2026
12 checks passed
@ericflo ericflo deleted the ce/og-image branch April 16, 2026 18:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant