Builder.io Open Graph Tags: Add OG Meta to Your Visual CMS
How to add og:title, og:image, and og:description to Builder.io-powered sites — with custom fields, Next.js generateMetadata, and dynamic OG images.
Builder.io and OG tags
Builder.io is a visual headless CMS where marketers drag-and-drop content while developers retain full control of rendering. OG metadata lives in custom model fields you define in the Builder dashboard, and your Next.js (or React) frontend reads them via the Builder Content API.
The workflow: define SEO fields in your Builder model → editors fill them → your frontend queries them in generateMetadata.
Step 1: Add OG fields to your Builder model
In the Builder.io dashboard, open your content model (e.g., "Page") and add a custom field group for SEO:
- Field name:
seoTitle— Type: Short Text - Field name:
seoDescription— Type: Long Text - Field name:
ogImage— Type: File (image)
Editors can then fill these fields in the visual editor sidebar for each page.
Step 2: Query OG fields in Next.js
Use the @builder.io/sdk-react or the REST API to fetch content including your custom SEO fields:
// app/[[...page]]/page.tsx
import type { Metadata } from "next";
import { fetchOneEntry } from "@builder.io/sdk-react/rsc";
export async function generateMetadata({
params,
}: {
params: { page?: string[] };
}): Promise<Metadata> {
const urlPath = "/" + (params.page?.join("/") || "");
const content = await fetchOneEntry({
model: "page",
apiKey: process.env.NEXT_PUBLIC_BUILDER_API_KEY!,
userAttributes: { urlPath },
fields: "data.title,data.seoTitle,data.seoDescription,data.ogImage",
});
if (!content) return { title: "Page Not Found" };
const { title, seoTitle, seoDescription, ogImage } = content.data || {};
const ogTitle = seoTitle || title || "My Site";
const ogDesc = seoDescription || "";
return {
title: ogTitle,
description: ogDesc,
openGraph: {
title: ogTitle,
description: ogDesc,
type: "website",
images: ogImage ? [{ url: ogImage, width: 1200, height: 630 }] : [],
},
twitter: {
card: "summary_large_image",
title: ogTitle,
description: ogDesc,
images: ogImage ? [ogImage] : [],
},
};
}Step 3: Dynamic OG images for Builder pages
Add a catch-all OG image route that reads the Builder page title and generates an image on the fly:
// app/api/og/route.tsx
import { ImageResponse } from "next/og";
export const runtime = "edge";
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const title = searchParams.get("title") || "Builder.io Page";
return new ImageResponse(
(
<div
style={{
display: "flex",
flexDirection: "column",
background: "#0f172a",
width: "100%",
height: "100%",
padding: "60px",
justifyContent: "flex-end",
borderBottom: "8px solid #7c3aed",
}}
>
<div style={{ fontSize: 60, fontWeight: 900, color: "#fff", lineHeight: 1.2 }}>
{title}
</div>
<div style={{ fontSize: 28, color: "#94a3b8", marginTop: 20 }}>
yoursite.com
</div>
</div>
),
{ width: 1200, height: 630 }
);
}
// In generateMetadata, use:
// images: [{ url: `/api/og?title=${encodeURIComponent(ogTitle)}` }]Common Builder.io OG pitfalls
- Cache invalidation: Builder content is served from a CDN. After editing OG fields, purge your Next.js ISR cache with
revalidatePath - Image CDN URLs: Builder stores images on CDN — these URLs are absolute and public by default, which is what you want for OG
- Catchall routing: If using Builder's catchall page model, make sure your
generateMetadatais in the same route segment - Missing fields: If you didn't add OG fields to all existing pages, fall back to the page title/description gracefully
Preview your Builder.io OG tags
After deploying, paste your page URL into OGFixer to verify how your social previews look on Twitter, LinkedIn, Discord, and Slack.
Check your OG tags free →