API Documentation

Generate beautiful Open Graph images with a single URL. No signup required.

# API Playground

Try the API right here β€” edit the parameters and see a live preview. No signup needed.

GET https://ogmagic.dev/api/og?template=gradient-mesh&title=Hello+World&description=Your+amazing+description+here&domain=example.com
<meta property="og:image" content="https://ogmagic.dev/api/og?template=gradient-mesh&title=Hello+World&description=Your+amazing+description+here&domain=example.com" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:image" content="https://ogmagic.dev/api/og?template=gradient-mesh&title=Hello+World&description=Your+amazing+description+here&domain=example.com" />

# Quick Start

Generate an OG image by making a GET request. No API key needed for the free tier:

https://ogmagic.dev/api/og?title=My%20Blog%20Post&description=A%20great%20article&template=gradient-mesh

Use it as your og:image meta tag:

<meta property="og:image" content="https://ogmagic.dev/api/og?title=My+Blog+Post&template=gradient-mesh" />

That's it. Your links now have beautiful social previews.

# API Reference

GEThttps://ogmagic.dev/api/og

Returns a 1200Γ—630 PNG image.

All parameters are passed as URL query strings. The response is a PNG image with CDN cache headers (24h edge cache, 1h browser cache).

# Quick Integration Examples

Copy-paste these examples to get OG images working in your project in under 2 minutes.

Next.js (App Router)

Dynamic OG images for any page using generateMetadata:

// app/blog/[slug]/page.tsx
import { Metadata } from 'next'

interface PageProps {
  params: { slug: string }
}

export async function generateMetadata({ params }: PageProps): Promise<Metadata> {
  const post = await getPost(params.slug) // Your data fetching
  
  return {
    title: post.title,
    description: post.excerpt,
    openGraph: {
      images: [
        {
          url: `https://ogmagic.dev/api/og?template=gradient-mesh&title=${encodeURIComponent(post.title)}&description=${encodeURIComponent(post.excerpt)}&domain=myblog.com`,
          width: 1200,
          height: 630,
        },
      ],
    },
  }
}

Next.js (Pages Router)

Using getStaticProps or getServerSideProps:

// pages/blog/[slug].tsx
import Head from 'next/head'

interface PostPageProps {
  post: { title: string; excerpt: string }
}

export default function PostPage({ post }: PostPageProps) {
  return (
    <>
      <Head>
        <meta property="og:image" content={`https://ogmagic.dev/api/og?template=gradient-mesh&title=${encodeURIComponent(post.title)}&domain=myblog.com`} />
        <meta property="og:image:width" content="1200" />
        <meta property="og:image:height" content="630" />
        <meta name="twitter:card" content="summary_large_image" />
      </Head>
      {/* Your page content */}
    </>
  )
}

React Component (Reusable)

Create a reusable OGImage component:

// components/OGImage.tsx
interface OGImageProps {
  title: string;
  description?: string;
  template?: string;
  domain?: string;
}

export function OGImage({ title, description, template = "gradient-mesh", domain }: OGImageProps) {
  const params = new URLSearchParams({
    template,
    title,
    ...(description && { description }),
    ...(domain && { domain }),
  });

  return (
    <>
      <meta property="og:image" content={`https://ogmagic.dev/api/og?${params.toString()}`} />
      <meta property="og:image:width" content="1200" />
      <meta property="og:image:height" content="630" />
      <meta name="twitter:card" content="summary_large_image" />
      <meta name="twitter:image" content={`https://ogmagic.dev/api/og?${params.toString()}`} />
    </>
  );
}

// Usage in any page:
// <OGImage title="My Post" description="My description" domain="mysite.com" />

Node.js / Express

Generate OG image URLs in your backend:

// utils/og-image.js
export function getOGImageUrl(title, options = {}) {
  const { description, template = 'gradient-mesh', domain } = options;
  
  const params = new URLSearchParams({
    template,
    title,
  });
  
  if (description) params.append('description', description);
  if (domain) params.append('domain', domain);
  
  return `https://ogmagic.dev/api/og?${params.toString()}`;
}

// Usage in Express route:
app.get('/blog/:slug', (req, res) => {
  const post = getPost(req.params.slug);
  const ogImage = getOGImageUrl(post.title, {
    description: post.excerpt,
    domain: 'myblog.com',
  });
  
  res.render('post', { post, ogImage });
});

Python / Flask

Add OG images to your Flask templates:

# app.py
from urllib.parse import urlencode

def get_og_image_url(title, description=None, template='gradient-mesh', domain=None):
    params = {'template': template, 'title': title}
    if description:
        params['description'] = description
    if domain:
        params['domain'] = domain
    return f"https://ogmagic.dev/api/og?{urlencode(params)}"

@app.route('/blog/<slug>')
def blog_post(slug):
    post = get_post(slug)
    og_image = get_og_image_url(
        post['title'],
        description=post['excerpt'],
        domain='myblog.com'
    )
    return render_template('post.html', post=post, og_image=og_image)

# In your template:
# <meta property="og:image" content="{{ og_image }}" />

Vue / Nuxt 3

Using useHead in Nuxt 3:

// pages/blog/[slug].vue
<script setup>
const route = useRoute()
const { data: post } = await useFetch(`/api/posts/${route.params.slug}`)

const ogImageUrl = computed(() => {
  const params = new URLSearchParams({
    template: 'gradient-mesh',
    title: post.value.title,
    description: post.value.excerpt,
    domain: 'myblog.com',
  })
  return `https://ogmagic.dev/api/og?${params.toString()}`
})

useHead({
  title: post.value.title,
  meta: [
    { property: 'og:image', content: ogImageUrl.value },
    { property: 'og:image:width', content: '1200' },
    { property: 'og:image:height', content: '630' },
    { name: 'twitter:card', content: 'summary_large_image' },
    { name: 'twitter:image', content: ogImageUrl.value },
  ],
})
</script>

Dynamic OG Image Generator

Create a helper that generates OG URLs for your entire site:

// lib/og-generator.ts
interface OGOptions {
  title: string;
  description?: string;
  template?: string;
  domain?: string;
  author?: string;
  accent?: string;
}

export class OGImageGenerator {
  private baseUrl = 'https://ogmagic.dev/api/og';
  private defaultDomain: string;

  constructor(defaultDomain: string) {
    this.defaultDomain = defaultDomain;
  }

  generate(options: OGOptions): string {
    const params = new URLSearchParams({
      template: options.template || 'gradient-mesh',
      title: options.title,
    });

    if (options.description) params.append('description', options.description);
    if (options.domain || this.defaultDomain) {
      params.append('domain', options.domain || this.defaultDomain);
    }
    if (options.author) params.append('author', options.author);
    if (options.accent) params.append('accent', options.accent);

    return `${this.baseUrl}?${params.toString()}`;
  }

  // Preset for blog posts
  blogPost(title: string, excerpt: string): string {
    return this.generate({
      title,
      description: excerpt,
      template: 'gradient-mesh',
    });
  }

  // Preset for product pages
  product(name: string, price: string): string {
    return this.generate({
      title: name,
      description: price + ' β€” Available now',
      template: 'minimal-dark',
    });
  }
}

// Usage:
const og = new OGImageGenerator('myblog.com');
const blogOG = og.blogPost('My Post', 'Great excerpt');
const productOG = og.product('My Product', '$99');

πŸ’‘ Pro tip: All examples use the free tier (50 calls/month, no signup). Add a key parameter with your Pro license key to unlock 5,000 calls/month and all 55+ templates.

# Parameters

ParameterTypeRequiredDescription
titlestringNo*Main text. Defaults to "Hello World"
descriptionstringNoSubtitle / description text
templatestringNoTemplate ID. Defaults to "gradient-mesh"
authorstringNoAuthor name (supported by some templates)
domainstringNoDomain / URL to display
accentstringNoAccent color override (e.g. %23ff6600 β€” URL-encode the #)
widthnumberNoImage width in px (Pro only, 200–2400, default 1200)
heightnumberNoImage height in px (Pro only, 200–1400, default 630)
keystringNoPro license key for premium templates & higher limits

# Templates

OGMagic ships with 50 templates across categories like Gradient, Dark, Minimal, Bold, Professional, Retro, and more.

Free Templates (5)

gradient-meshminimal-darksplit-cardbold-statementsunrise

Pro Templates (45+)

Includes Tokyo Night, Dracula, Nord, RosΓ© Pine, Synthwave, Linear Style, Vercel Style, and many more. Browse all in the editor β†’

Get a list of all templates via the API:

GET https://ogmagic.dev/api/templates

# Authentication

Free tier: No authentication needed. Just use the URL directly.

Pro tier: Add your license key as a key query parameter:

https://ogmagic.dev/api/og?title=My+Post&template=tokyo-night&key=YOUR_LICENSE_KEY

⚠️ Keep your license key private. Use environment variables in CI/CD, not hardcoded in public repos.

# Rate Limits

Free Tier

50 requests/month

IP-based. No signup needed.

Pro ($12)

5,000 requests/month

Key-based. One-time purchase.

Rate limit info is returned in response headers: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.

# Next.js Integration

Use the OGMagic API directly in your Next.js app β€” no packages to install.

App Router

// app/blog/[slug]/page.tsx
function ogUrl(params: Record<string, string>) {
  const qs = new URLSearchParams(params).toString();
  return `https://ogmagic.dev/api/og?${qs}`;
}

export function generateMetadata({ params }) {
  const post = getPost(params.slug);
  const image = ogUrl({
    template: "minimal-dark",
    title: post.title,
    description: post.excerpt,
  });

  return {
    openGraph: { images: [{ url: image, width: 1200, height: 630 }] },
    twitter: { card: "summary_large_image", images: [image] },
  };
}

Pages Router

// pages/blog/[slug].tsx
import Head from "next/head";

export default function BlogPost({ post }) {
  const ogImage = `https://ogmagic.dev/api/og?template=stripe-style&title=${encodeURIComponent(post.title)}&description=${encodeURIComponent(post.excerpt)}`;

  return (
    <>
      <Head>
        <meta property="og:image" content={ogImage} />
        <meta property="og:image:width" content="1200" />
        <meta property="og:image:height" content="630" />
        <meta name="twitter:card" content="summary_large_image" />
        <meta name="twitter:image" content={ogImage} />
      </Head>
      <article>{/* ... */}</article>
    </>
  );
}

# Remix Integration

Use OGMagic in your Remix routes with the meta export:

// app/routes/blog.$slug.tsx
import type { MetaFunction, LoaderFunctionArgs } from "@remix-run/node";

export const meta: MetaFunction<typeof loader> = ({ data }) => {
  const ogImage = `https://ogmagic.dev/api/og?${new URLSearchParams({
    template: "minimal-dark",
    title: data.post.title,
    description: data.post.excerpt,
    domain: "yourblog.com",
  })}`;

  return [
    { property: "og:image", content: ogImage },
    { property: "og:image:width", content: "1200" },
    { property: "og:image:height", content: "630" },
    { name: "twitter:card", content: "summary_large_image" },
    { name: "twitter:image", content: ogImage },
  ];
};

# SvelteKit Integration

In SvelteKit, set OG images in your +page.server.ts or +layout.server.ts:

<!-- src/routes/blog/[slug]/+page.svelte -->
<script>
  export let data;
  const ogImage = `https://ogmagic.dev/api/og?${new URLSearchParams({
    template: "stripe-style",
    title: data.post.title,
    description: data.post.excerpt,
  })}`;
</script>

<svelte:head>
  <meta property="og:image" content={ogImage} />
  <meta property="og:image:width" content="1200" />
  <meta property="og:image:height" content="630" />
  <meta name="twitter:card" content="summary_large_image" />
  <meta name="twitter:image" content={ogImage} />
</svelte:head>

# Astro Integration

Use the API URL directly in your Astro layouts β€” zero dependencies.

---
// src/layouts/BlogPost.astro
const { frontmatter } = Astro.props;

const ogParams = new URLSearchParams({
  template: "minimal-dark",
  title: frontmatter.title,
  description: frontmatter.description || "",
}).toString();

const ogImage = `https://ogmagic.dev/api/og?${ogParams}`;
---

<html>
<head>
  <meta property="og:image" content={ogImage} />
  <meta property="og:image:width" content="1200" />
  <meta property="og:image:height" content="630" />
  <meta name="twitter:card" content="summary_large_image" />
  <meta name="twitter:image" content={ogImage} />
</head>
<body>
  <slot />
</body>
</html>

# Gatsby Integration

Add OG images to your Gatsby pages using the Seo component or gatsby-plugin-react-helmet:

// src/components/seo.tsx
import { Helmet } from "react-helmet";

export function Seo({ title, description }: { title: string; description?: string }) {
  const ogImage = `https://ogmagic.dev/api/og?${new URLSearchParams({
    template: "minimal-dark",
    title,
    description: description || "",
    domain: "yourblog.com",
  })}`;

  return (
    <Helmet>
      <meta property="og:image" content={ogImage} />
      <meta property="og:image:width" content="1200" />
      <meta property="og:image:height" content="630" />
      <meta name="twitter:card" content="summary_large_image" />
      <meta name="twitter:image" content={ogImage} />
    </Helmet>
  );
}

// Usage in a page or template:
// <Seo title={post.frontmatter.title} description={post.frontmatter.excerpt} />

Works with both gatsby-plugin-react-helmet and Gatsby's built-in Head API (Gatsby 4.19+).

# Hugo Integration

Add OG images to your Hugo site by editing your base template (e.g., layouts/partials/head.html):

{{/* layouts/partials/head.html */}}
{{ $ogTitle := .Title | urlquery }}
{{ $ogDesc := .Description | urlquery }}
{{ $ogDomain := .Site.BaseURL | urlquery }}
{{ $ogImage := printf "https://ogmagic.dev/api/og?template=stripe-style&title=%s&description=%s&domain=%s" $ogTitle $ogDesc $ogDomain }}

<meta property="og:image" content="{{ $ogImage }}" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:image" content="{{ $ogImage }}" />

Hugo's urlquery function handles URL-encoding automatically. You can also use different templates per section using Hugo's section conditionals.

# WordPress Integration

Add OG images to your WordPress theme by editing functions.php or your theme's header.php:

<?php // functions.php
function ogmagic_meta_tags() {
    if (is_singular()) {
        $title = urlencode(get_the_title());
        $excerpt = urlencode(get_the_excerpt());
        $domain = urlencode(parse_url(home_url(), PHP_URL_HOST));
        $og_image = "https://ogmagic.dev/api/og?template=stripe-style&title={$title}&description={$excerpt}&domain={$domain}";
        
        echo '<meta property="og:image" content="' . esc_attr($og_image) . '" />' . "\n";
        echo '<meta property="og:image:width" content="1200" />' . "\n";
        echo '<meta property="og:image:height" content="630" />' . "\n";
        echo '<meta name="twitter:card" content="summary_large_image" />' . "\n";
        echo '<meta name="twitter:image" content="' . esc_attr($og_image) . '" />' . "\n";
    }
}
add_action('wp_head', 'ogmagic_meta_tags');

If you use Yoast SEO or Rank Math, you can use their OG image filter hooks instead. Works with any WordPress theme.

# Laravel Integration

Use OGMagic in your Laravel Blade templates:

{{-- resources/views/layouts/app.blade.php --}}
@php
    $ogImage = 'https://ogmagic.dev/api/og?' . http_build_query([
        'template' => 'minimal-dark',
        'title' => $title ?? config('app.name'),
        'description' => $description ?? '',
        'domain' => parse_url(config('app.url'), PHP_URL_HOST),
    ]);
@endphp

<meta property="og:image" content="{{ $ogImage }}" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:image" content="{{ $ogImage }}" />

Pass $title and $description from your controller or use the @section directive.

# Django / Python Integration

Add OG images in your Django templates:

{# base.html #}
{% load urlencode from django.utils.http %}

{% block og_meta %}
<meta property="og:image" content="https://ogmagic.dev/api/og?template=gradient-mesh&title={{ page_title|urlencode }}&description={{ page_description|urlencode }}&domain={{ request.get_host|urlencode }}" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:image" content="https://ogmagic.dev/api/og?template=gradient-mesh&title={{ page_title|urlencode }}" />
{% endblock %}

Or build the URL in your view with urllib.parse.urlencode() for full control. Works with Django, Flask, FastAPI, or any Python framework.

# Ruby on Rails Integration

Add OG images to your Rails views using a helper or directly in your layout:

<%# app/helpers/og_image_helper.rb %>
module OgImageHelper
  def og_image_url(title:, description: nil, template: "gradient-mesh", domain: nil)
    params = { template: template, title: title }
    params[:description] = description if description.present?
    params[:domain] = domain || request.host if domain != false
    "https://ogmagic.dev/api/og?#{params.to_query}"
  end
end

<%# app/views/layouts/application.html.erb %>
<% og_url = og_image_url(title: yield(:title) || "My App", description: yield(:description)) %>
<meta property="og:image" content="<%= og_url %>" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:image" content="<%= og_url %>" />

<%# In any view: %>
<% content_for(:title) { "My Blog Post" } %>
<% content_for(:description) { "A great article about Rails" } %>

Works with any Rails version. For API-only apps, build the URL in your serializer or controller.

# HTML Meta Tags

For any website, add these meta tags to your <head>:

<!-- Open Graph -->
<meta property="og:image" content="https://ogmagic.dev/api/og?title=My+Page&template=gradient-mesh" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />

<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:image" content="https://ogmagic.dev/api/og?title=My+Page&template=gradient-mesh" />

# Error Handling

StatusMeaning
200Success β€” PNG image returned
400Bad request β€” unknown template ID
429Rate limit exceeded
500Server error

Error responses return JSON with an error field:

{ "error": "Unknown template: foo. Available: gradient-mesh, minimal-dark, ..." }

Ready to get started?