@growth-labs/opengraph
v0.2.0
Published
Generates branded Open Graph images using Cloudflare Browser Rendering (Puppeteer). Screenshots HTML templates, caches in R2, serves via on-demand route. Two sizes per page: 1200×630 (Facebook/LinkedIn/Twitter) and 1200×675 (Google Discover 16:9).
Readme
@growth-labs/opengraph
Generates branded Open Graph images using Cloudflare Browser Rendering (Puppeteer). Screenshots HTML templates, caches in R2, serves via on-demand route. Two sizes per page: 1200×630 (Facebook/LinkedIn/Twitter) and 1200×675 (Google Discover 16:9).
Requires: Cloudflare Workers Paid plan (Browser Rendering access).
Config
import opengraph from '@growth-labs/opengraph'
opengraph({
publicDomain: 'media.fedweek.com', // R2 custom domain
r2Binding: 'MEDIA_BUCKET',
browserBinding: 'BROWSER',
brandName: 'FEDweek',
brandColors: {
primary: '#1a365d',
accent: '#e53e3e',
text: '#ffffff',
},
logoUrl: 'https://media.fedweek.com/logos/og-logo.png',
fontFamily: 'Inter',
fontWeight: '600',
route: { enabled: true, regenerateSecret: '...' },
format: 'png',
timeout: 10_000,
})What It Injects
Route: GET /og/[...path].png — on-demand OG image generation. First request renders via Browser Rendering + caches to R2. Subsequent requests served from R2.
Standalone Utilities
import { getOgImageUrl, getOgDiscoverUrl } from '@growth-labs/opengraph/utils'
import { generateOgImage } from '@growth-labs/opengraph/utils'
getOgImageUrl('media.fedweek.com', '/news/my-article')
// → https://media.fedweek.com/og/news/my-article.png
// Or generate programmatically (e.g. in publish workflow)
await generateOgImage(env.BROWSER, env.MEDIA_BUCKET, templateData, options)Custom Templates
Override the built-in template with a function that returns HTML:
opengraph({
template: (data) => `<html><body><h1>${data.title}</h1></body></html>`,
})Template receives: { title, subtitle, description, category, authorName, authorImageUrl, pageType }
Wrangler Bindings
[browser]
binding = "BROWSER"
[[r2_buckets]]
binding = "MEDIA_BUCKET"
bucket_name = "fedweek-public-media"
compatibility_flags = ["nodejs_compat"]Integration Points
- With @growth-labs/seo: Consumer passes OG image URL into
generateMeta(). No direct import between packages. - With @growth-labs/media: Writes to
og/prefix in the same R2 bucket.ogKey()in media utils generates matching keys.
Key Patterns
- Virtual module:
virtual:growth-labs/opengraph/config - R2 key convention:
og/{page-path}.png(aligns with@growth-labs/media/utilsogKey()) ?regenerate=truewith shared secret to force re-render- Browser Rendering has per-account concurrency limits — timeout protects against hangs
