Generate Dynamic Open Graph Images with Astro, Satori & Vercel

Generate Dynamic Open Graph Images with Astro, Satori & Vercel

Generate Dynamic Open Graph Images with Astro, Satori & Vercel

In today’s competitive online landscape, having attractive Open Graph (OG) images is essential for improving SEO and boosting social media engagement. In this guide, we’ll walk through how to create dynamic OG images using Astro, Satori, and Vercel.

Why Dynamic OG Images?

Social media platforms like Twitter, Facebook, and LinkedIn use OG images to display rich previews of your content. By generating these images dynamically, you can:

  • Enhance SEO: Unique images per post improve click-through rates.
  • Increase Social Engagement: Custom-designed visuals attract more attention.
  • Maintain Branding: Dynamically inject your post data (title, description, tags, etc.) into the image.

Step 1: Setting Up Your Astro Project

If you haven’t already set up an Astro project, create one using pnpm:

# Create a new Astro project using the latest version
pnpm create astro@latest my-astro-project
# Change into the project directory
cd my-astro-project
# Install project dependencies
pnpm install

Step 2: Install Required Packages

We will use the following packages:

  • Satori: Converts HTML & CSS to SVG.
  • Sharp: Converts SVG to PNG.
  • fs & path: To read font files.

Install them using pnpm:

# Install required packages for dynamic OG image generation
pnpm add satori satori-html sharp

Step 3: Create an API Route for OG Images

Inside your Astro project, create a new API route: src/pages/api/og.ts

import satori from "satori";
import { html } from "satori-html";
import { readFileSync } from "fs";
import { join } from "path";
import sharp from "sharp";

export const prerender = false;

// Load fonts
const fontRegular = readFileSync(join(process.cwd(), 'public/fonts/Inter-Regular.ttf'));
const fontBold = readFileSync(join(process.cwd(), 'public/fonts/Inter-Bold.ttf'));

export async function GET({ request }: { request: Request }) {
  if (request.method !== "GET") {
    return new Response("Only GET method is supported", { status: 405 });
  }

  const url = new URL(request.url);
  const title = url.searchParams.get("title") || "Blog Post";
  const description = url.searchParams.get("description") || "";
  const pubDate = url.searchParams.get("pubDate") || "";
  const tags = url.searchParams.get("tags")?.split(",") || [];
  const authorName = url.searchParams.get("authorName") || "";

  const markup = html(`
    <div class="flex flex-col w-full h-full bg-[#1f1f23] p-12 text-white">
      <h1 class="text-5xl font-bold mb-4">${title}</h1>
      ${description && `<p class="text-xl text-zinc-400 mb-6">${description}</p>`}
      ${tags.length > 0 ? `<div class="flex flex-wrap mb-6">${tags.map(tag => `<span class="px-3 py-1 bg-zinc-600 text-zinc-300 rounded-full text-sm mr-2 mb-2">${tag}</span>`).join('')}</div>` : ""}
      <div class="flex items-center mt-auto">
        <p class="font-bold">${authorName}</p>
        ${pubDate && `<p class="text-sm ml-4 text-zinc-400">Published on ${pubDate}</p>`}
      </div>
    </div>
  `);

  const svg = await satori(markup, {
    width: 1200,
    height: 500,
    fonts: [
      { name: "Inter", data: fontRegular, weight: 400, style: "normal" },
      { name: "Inter", data: fontBold, weight: 700, style: "normal" },
    ],
  });

  const pngBuffer = await sharp(Buffer.from(svg)).png().toBuffer();

  return new Response(pngBuffer, {
    headers: {
      "Content-Type": "image/png",
      "Cache-Control": "public, max-age=31536000, immutable",
    },
  });
}

Step 4: Deploy to Vercel

Once your API route is set up, push your project to GitHub and deploy it on Vercel:

# Initialize a new Git repository
git init

# Add all files to the staging area
git add .

# Commit the changes with a message
git commit -m "Initial commit"

# Rename the default branch from 'master' to 'main'
git branch -M main

# Add a remote repository named 'origin'
git remote add origin https://github.com/your-username/my-astro-project.git

# Push the changes to the remote repository
git push -u origin main

Then, deploy using the Vercel CLI:

# Install Vercel CLI globally
pnpm add -g vercel
# Deploy the project to Vercel
vercel

Step 5: Use the OG Image

Now you can use the generated OG image in your blog posts:

<meta property="og:image" content="https://your-vercel-app.vercel.app/api/og?title=My%20Blog%20Post&description=An%20amazing%20article" />

Additional Resources

Final Thoughts

By following these steps, you can dynamically generate OG images for your Astro blog, making your content more shareable and visually appealing on social media.

Let me know if you have any questions or need further improvements! 🚀