OG Dashboard
Self-hosted Open Graph image generation with a template dashboard. Deploy to Cloudflare Workers in minutes.
Template Dashboard
Visual editor with live preview. 60+ Google Fonts.
Simple API
One endpoint per template. Query params in, PNG out.
Edge Deployed
Cloudflare Workers. Fast globally, scales automatically.
Self-Hosted
Your data, your infrastructure. No per-image pricing.
Quick Start
git clone https://github.com/furvur/og-dashboard.git
cd og-dashboard
./setup.sh
The setup script will:
- Install dependencies
- Log you into Cloudflare
- Create the D1 database
- Set your admin password and API key
- Deploy to Workers
Once deployed, visit your dashboard URL and log in to create templates.
Examples
Blog Post OG Image
A simple blog post template with title, author, and date.
<div style="display: flex; flex-direction: column; width: 100%; height: 100%; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 60px; font-family: 'Inter', sans-serif;">
<div style="flex: 1; display: flex; flex-direction: column; justify-content: center;">
<p style="color: rgba(255,255,255,0.8); font-size: 24px; margin-bottom: 16px;">{{ site | default: "My Blog" }}</p>
<h1 style="color: white; font-size: 56px; font-weight: 700; line-height: 1.2; margin: 0;">{{ title }}</h1>
</div>
<div style="display: flex; align-items: center; gap: 16px;">
<p style="color: rgba(255,255,255,0.9); font-size: 20px;">{{ author }}</p>
<span style="color: rgba(255,255,255,0.5);">•</span>
<p style="color: rgba(255,255,255,0.7); font-size: 20px;">{{ date }}</p>
</div>
</div>
/api/render/{token}?title=How%20to%20Build%20a%20Startup&author=Jane%20Smith&date=January%207,%202026
Product Launch
Announcement card with product name and tagline.
<div style="display: flex; flex-direction: column; align-items: center; justify-content: center; width: 100%; height: 100%; background: #0f172a; font-family: 'Inter', sans-serif;">
<p style="color: #22d3ee; font-size: 18px; text-transform: uppercase; letter-spacing: 2px; margin-bottom: 24px;">{{ label | default: "Now Available" }}</p>
<h1 style="color: white; font-size: 72px; font-weight: 800; margin: 0 0 16px 0;">{{ product }}</h1>
<p style="color: #94a3b8; font-size: 28px;">{{ tagline }}</p>
</div>
/api/render/{token}?product=Acme%20Pro&tagline=The%20future%20of%20productivity
Documentation Page
Clean documentation style with section and page title.
<div style="display: flex; width: 100%; height: 100%; background: white; font-family: 'Inter', sans-serif;">
<div style="width: 8px; background: {{ accent | default: '#6366f1' }};"></div>
<div style="flex: 1; display: flex; flex-direction: column; justify-content: center; padding: 60px;">
<p style="color: #6b7280; font-size: 20px; margin-bottom: 12px;">{{ section | default: "Documentation" }}</p>
<h1 style="color: #111827; font-size: 52px; font-weight: 700; margin: 0;">{{ title }}</h1>
</div>
</div>
/api/render/{token}?section=API%20Reference&title=Authentication&accent=%2310b981
Template Syntax
Templates use Liquid syntax (same as Shopify) with inline CSS styles.
Variables
Variables are passed as query parameters and rendered with double braces:
{{ title }}
{{ author | default: "Anonymous" }}
{{ date | default: "Today" }}
Conditionals
Show content based on whether a variable is provided:
{% if author %}
<p style="color: gray;">By {{ author }}</p>
{% endif %}
Filters
Transform values with filters:
{{ title | upcase }}
{{ name | capitalize }}
{{ description | truncate: 100 }}
{{ price | default: "Free" }}
Note: Templates must use inline CSS styles. Satori (the rendering engine) doesn't support external stylesheets or <style> tags.
API Reference
Render Image
Each template gets a unique render token. Use it to generate images:
curl "https://og-dashboard.example.workers.dev/api/render/abc123?title=Hello&author=World"
Query Parameters:
- Any parameter becomes a template variable
- URL-encode special characters
Response:
- Returns
image/png - 1200×630 pixels (standard OG size)
- Cached via CDN headers
Admin API
Manage templates programmatically with the Admin API. Authenticate with your ADMIN_API_KEY:
Authorization: Bearer YOUR_ADMIN_API_KEY
| Method | Endpoint | Purpose |
|---|---|---|
GET |
/api/admin/templates | List all templates |
POST |
/api/admin/templates | Create template |
GET |
/api/admin/templates/:id | Get template |
PUT |
/api/admin/templates/:id | Update template |
DELETE |
/api/admin/templates/:id | Delete template |
POST |
/api/admin/templates/:id/regenerate-token | Regenerate render token |
Create Template
curl -X POST https://og-dashboard.example.workers.dev/api/admin/templates \
-H "Authorization: Bearer $ADMIN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Blog Post",
"description": "OG image for blog posts",
"content": "<div style=\"display: flex; ...\">{{ title }}</div>",
"fonts": ["Inter"]
}'
Fonts
Templates can use any of the 60+ included Google Fonts. Select fonts in the dashboard editor or specify them via the API:
<div style="font-family: 'Poppins', sans-serif;">
{{ title }}
</div>
Popular fonts included:
Tech Stack
Hono
Web framework
Satori
HTML to SVG
LiquidJS
Templating
Drizzle
ORM
Cloudflare Workers
Runtime
D1
Database