OG Screenshot Worker
Generate dynamic Open Graph images using Cloudflare Browser Rendering.
This Cloudflare Worker takes live screenshots of pages on soderlind.no and serves them as OG images for social media previews.
How It Works · Setup · Configuration · Usage · Cache Warmup
How It Works
Section titled “How It Works”When someone shares a link to soderlind.no/plugins/wp-loupe/, social platforms fetch https://og.soderlind.no/plugins/wp-loupe.png. The worker:
- Checks KV cache — Returns cached screenshot if available
- Launches headless browser — Uses Cloudflare Browser Rendering
- Takes screenshot — Captures the page at 1200×630 pixels (OG standard)
- Caches result — Stores in KV for 7 days
- Returns PNG — Serves the image with proper headers
Request: https://og.soderlind.no/plugins/wp-loupe.png ↓Worker extracts slug: "plugins/wp-loupe" ↓Navigates to: https://soderlind.no/plugins/wp-loupe/ ↓Takes screenshot → Caches → Returns PNGPrerequisites
Section titled “Prerequisites”- Cloudflare Workers Paid plan (required for Browser Rendering)
wranglerCLI installed
1. Create KV Namespace
Section titled “1. Create KV Namespace”cd workers/og-screenshotnpx wrangler kv namespace create CACHECopy the returned id into wrangler.toml.
2. Deploy Worker
Section titled “2. Deploy Worker”npm installnpx wrangler deploy3. Add DNS Record
Section titled “3. Add DNS Record”In Cloudflare Dashboard → DNS → Add record:
| Type | Name | Content | Proxy |
|---|---|---|---|
| AAAA | og | 100:: | Proxied |
This routes og.soderlind.no to the worker.
4. Update Head Component
Section titled “4. Update Head Component”In your Astro site, set the og:image URL:
---const ogSlug = Astro.locals.starlightRoute?.id || slug || 'index';const ogImage = `https://og.soderlind.no/${ogSlug}.png`;---
<meta property="og:image" content={ogImage} /><meta property="og:image:width" content="1200" /><meta property="og:image:height" content="630" />Configuration
Section titled “Configuration”wrangler.toml
Section titled “wrangler.toml”name = "og-screenshot"main = "src/index.ts"compatibility_date = "2025-01-01"compatibility_flags = ["nodejs_compat"]
[browser]binding = "BROWSER"
[[kv_namespaces]]binding = "CACHE"id = "your-kv-namespace-id"
[[routes]]pattern = "og.soderlind.no/*"zone_name = "soderlind.no"Environment Variables
Section titled “Environment Variables”| Binding | Type | Description |
|---|---|---|
BROWSER | Browser | Cloudflare Browser Rendering binding |
CACHE | KV Namespace | Screenshot cache storage |
URL Format
Section titled “URL Format”https://og.soderlind.no/{slug}.pngExamples
Section titled “Examples”| Page | OG Image URL |
|---|---|
| Homepage | https://og.soderlind.no/index.png |
| About | https://og.soderlind.no/about.png |
| WP Loupe | https://og.soderlind.no/plugins/wp-loupe.png |
| AI Router | https://og.soderlind.no/ai/ai-router.png |
Cache Headers
Section titled “Cache Headers”X-Cache: HIT— Served from KV cacheX-Cache: MISS— Fresh screenshot generated
Testing
Section titled “Testing”# Check if workingcurl -I https://og.soderlind.no/about.png
# Verify cache hit on second requestcurl -I https://og.soderlind.no/about.png | grep X-CacheCache Warmup
Section titled “Cache Warmup”A GitHub Action runs weekly to warm the OG image cache, ensuring fast social media previews.
Automatic Warmup
Section titled “Automatic Warmup”The workflow runs every Sunday at 06:00 UTC:
name: Warm OG Image Cache
on: schedule: - cron: '0 6 * * 0' # Weekly on Sunday at 06:00 UTC workflow_dispatch:
jobs: warm-cache: runs-on: ubuntu-latest steps: - name: Fetch sitemap and warm OG cache run: | curl -s https://soderlind.no/sitemap.xml | \ sed -n 's/.*<loc>https:\/\/soderlind\.no\/\([^<]*\)<\/loc>.*/\1/p' | \ sed 's/\/$//' | \ while read slug; do [ -z "$slug" ] && slug="index" curl -s -o /dev/null "https://og.soderlind.no/${slug}.png" doneManual Warmup
Section titled “Manual Warmup”Trigger the workflow manually from GitHub Actions, or run locally:
cat sitemap.xml | \ sed -n 's/.*<loc>https:\/\/soderlind\.no\/\([^<]*\)<\/loc>.*/\1/p' | \ sed 's/\/$//' | \ while read slug; do [ -z "$slug" ] && slug="index" curl -s -o /dev/null -w "%{http_code} ${slug}\n" "https://og.soderlind.no/${slug}.png" doneFallback Behavior
Section titled “Fallback Behavior”If screenshot fails (timeout, browser error), the worker falls back to the static Satori-generated OG image at /og/{slug}.png.
Cost Considerations
Section titled “Cost Considerations”Browser Rendering is included in Workers Paid plan:
- First 1,000 browser sessions/month free
- $0.02 per additional session
With 7-day caching, typical documentation sites stay well within free tier.