Open Source

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

Terminal
git clone https://github.com/furvur/og-dashboard.git
cd og-dashboard
./setup.sh

The setup script will:

  1. Install dependencies
  2. Log you into Cloudflare
  3. Create the D1 database
  4. Set your admin password and API key
  5. 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.

Template
<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>
Usage
/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.

Template
<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>
Usage
/api/render/{token}?product=Acme%20Pro&tagline=The%20future%20of%20productivity

Documentation Page

Clean documentation style with section and page title.

Template
<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>
Usage
/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:

GET /api/render/{token}
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

POST /api/admin/templates
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:

Inter Poppins Roboto Open Sans Montserrat Playfair Display Source Code Pro + 50 more

Tech Stack

Hono

Web framework

Satori

HTML to SVG

LiquidJS

Templating

Drizzle

ORM

Cloudflare Workers

Runtime

D1

Database

Ready to deploy?

Get your OG image service running in under 5 minutes.

View on GitHub