Every time you share a link on Twitter, Slack, Discord, or LinkedIn, the platform fetches your page's meta tags to build a preview card. The og:image tag controls what image shows up. If you don't set one, you get either nothing or whatever the crawler decides to grab from your page. Usually it picks your logo at 50x50 pixels. Looks awful.
I've spent way too long manually creating OG images in Figma, so here's what I've learned about the different ways to handle this.
What og:image actually does
It's a meta tag in your HTML head:
<meta property="og:image" content="https://yoursite.com/og-image.png" />
Social platforms read this when someone pastes your URL. Facebook, Twitter, LinkedIn, Discord, Slack — they all use it. The recommended size is 1200x630 pixels. Some platforms crop differently, but 1200x630 is the safe bet that works everywhere.
You also want og:title and og:description, but the image is what people actually notice. A link with a good preview image gets clicked. A link without one gets scrolled past.
The manual way
This is how most people start:
- Open Figma (or Canva, or whatever)
- Create a 1200x630 canvas
- Design something with your title, maybe a logo, some background
- Export as PNG
- Upload to your public assets
- Add the meta tag pointing to that file
It works fine if you have 5 pages. It falls apart when you have 50 blog posts and each one needs a unique image with the post title on it. I did this for a while. Every time I published something new, I'd spend 10 minutes in Figma tweaking text alignment. Not the worst use of time, but definitely repetitive.
The automated way
The idea is simple: instead of a static image URL, you use an API endpoint that generates the image on the fly from URL parameters.
Your meta tag ends up looking like this:
<meta property="og:image" content="https://ogpix-pi.vercel.app/api/og?title=My+Blog+Post&theme=dark" />
When a social platform crawls your page, it hits that URL, the API renders an image with your title text, and returns it. No Figma. No uploading files. The image is generated from the URL itself.
I built OGPix to do exactly this. You can pick from different themes, set your title and description as URL params, and get back a 1200x630 PNG. But the concept works with any OG image API — the integration pattern is the same regardless.
Code examples
Plain HTML
The simplest case. Just hardcode the meta tags:
<head>
<meta property="og:title" content="My Page Title" />
<meta property="og:description" content="A short description of the page" />
<meta property="og:image" content="https://ogpix-pi.vercel.app/api/og?title=My+Page+Title&theme=gradient" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
</head>
Include the width and height tags. Without them, some platforms delay rendering the preview because they have to fetch the image first to figure out dimensions.
Next.js (App Router)
In Next.js 13+ with the app router, you export a metadata object:
// app/blog/[slug]/page.tsx
export async function generateMetadata({ params }) {
const post = await getPost(params.slug);
const ogImage = \`https://ogpix-pi.vercel.app/api/og?title=\${encodeURIComponent(post.title)}&theme=minimal\`;
return {
title: post.title,
description: post.excerpt,
openGraph: {
title: post.title,
description: post.excerpt,
images: [{ url: ogImage, width: 1200, height: 630 }],
},
twitter: {
card: "summary_large_image",
images: [ogImage],
},
};
}
The nice thing here is that each blog post automatically gets its own OG image with the correct title. No manual work per post.
Astro
Astro handles this in the layout's head:
---
// src/layouts/BlogPost.astro
const { title, description } = Astro.props;
const ogImage = \`https://ogpix-pi.vercel.app/api/og?title=\${encodeURIComponent(title)}&theme=ocean\`;
---
<html>
<head>
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<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" />
</head>
<body>
<slot />
</body>
</html>
Same pattern. Build the URL from your page data, drop it in the meta tag.
Testing your OG tags
After adding the tags, you need to actually verify they work. Social platforms cache aggressively, and it's easy to have a typo in your URL that you won't notice until someone shares your link and it looks broken.
I built a free OG Tag Checker that shows you exactly how your link will appear on Twitter, Facebook, and LinkedIn. It also flags missing tags. I use it every time before I publish something.
Twitter also has its own Card Validator, and Facebook has the Sharing Debugger. Both are useful for clearing cached previews after you make changes.
Quick checklist
- Set og:image to a 1200x630 image URL
- Include og:image:width and og:image:height
- Set twitter:card to "summary_large_image" if you want the big preview
- Make sure the image URL is absolute (starts with https://)
- Test with a checker tool before publishing
- Remember that platforms cache previews, so use their debug tools to refresh
If you want to play around with different OG image styles before integrating, the OGPix playground lets you preview themes and copy the URL. It's free, no account needed.
Got questions about OG images or a different setup you'd like to see covered? Drop a comment.
Top comments (0)