
Overview
When users share links to posts, songs, or books on WhatsApp, Telegram, or Twitter, the preview displays a generic placeholder. This results in lower engagement and inconsistent brand presentation across platforms.
Goal: Generate branded preview images automatically for each shareable resource.
Problem
| Platform |
Current Behavior |
Desired Behavior |
| WhatsApp |
Empty/generic thumbnail |
Branded image with content title |
| Telegram |
Missing preview |
Cover image + headline |
| Twitter |
Blank card |
Formatted social card |
Solution
Hybrid rendering approach: Canvas-based generation with KV caching for optimal performance.
Request Flow:
GET /api/v1/og?type=post&id=42&locale=de
├─ Check KV Cache
│ ├─ Hit: Return cached PNG (<10ms)
│ └─ Miss: Render new PNG (300-500ms) → Cache → Return
└─ Response: image/png (1200×630px)
Implementation
New Files
| File |
Purpose |
apps/api/src/services/og-generator.ts |
Canvas rendering logic for image generation |
apps/api/src/routes/og.ts |
API endpoint with KV caching |
Modified Files
| File |
Change |
apps/api/src/index.ts |
Mount og route |
apps/web/app/[locale]/posts/[slug]/page.tsx |
Configure generateMetadata() |
apps/web/app/[locale]/songbooks/[slug]/[id]/page.tsx |
Configure generateMetadata() |
apps/treasures/app/[locale]/books/[id]/page.tsx |
Configure generateMetadata() |
Dependencies
canvas - Server-side image rendering in Workers
API Endpoint
GET /api/v1/og?type={post|song|treasure}&id={id}&locale={de|en}
Returns: image/png (1200×630px)
Cache-Control: public, max-age=3600, immutable
Technical Details
Image Composition
- Background: Cover image (left 50%) with gradient overlay
- Text area: Title, excerpt, metadata (right 50%)
- Footer: Logo, publication date, type indicator
- Dimensions: 1200×630px (OpenGraph standard)
- Format: PNG with compression
Caching Strategy
| Layer |
Duration |
Invalidation |
| KV (Workers) |
24 hours |
Manual on content edit |
| HTTP Cache-Control |
1 hour |
Standard TTL expiry |
| Cloudflare Edge |
1 hour |
Standard TTL expiry |
Error Handling
- Cover image missing: Render with solid background color
- Data not found: Return 404
- Render timeout: Serve fallback from cache if available
- KV unavailable: Proceed with HTTP caching only
Acceptance Criteria
Testing
Manual validation:
# Generate OG image
curl "http://localhost:8787/api/v1/og?type=post&id=1&locale=de" > test.png
# Validate in tools
https://developers.facebook.com/tools/debug/sharing/
https://cards-dev.twitter.com/validator
Performance Targets
| Metric |
Target |
| First render latency |
<500ms |
| Cached request latency |
<10ms |
| Image file size |
<100KB |
| Cache hit ratio |
>95% |
Related
- Uses existing infrastructure: D1, R2, Workers KV
- Reuses canvas rendering patterns from existing codebase
- No new external services required
- GDPR compliant: no personal data collection

Overview
When users share links to posts, songs, or books on WhatsApp, Telegram, or Twitter, the preview displays a generic placeholder. This results in lower engagement and inconsistent brand presentation across platforms.
Goal: Generate branded preview images automatically for each shareable resource.
Problem
Solution
Hybrid rendering approach: Canvas-based generation with KV caching for optimal performance.
Request Flow:
Implementation
New Files
apps/api/src/services/og-generator.tsapps/api/src/routes/og.tsModified Files
apps/api/src/index.tsapps/web/app/[locale]/posts/[slug]/page.tsxapps/web/app/[locale]/songbooks/[slug]/[id]/page.tsxapps/treasures/app/[locale]/books/[id]/page.tsxDependencies
API Endpoint
Technical Details
Image Composition
Caching Strategy
Error Handling
Acceptance Criteria
Testing
Manual validation:
Performance Targets
Related