Directus Open Graph Tags: Add OG Meta to Your Headless CMS Site
How to add og:title, og:image, and og:description to Directus-powered sites — with custom fields, REST API queries, and Next.js generateMetadata.
How Directus handles OG metadata
Directus is a headless CMS with a REST and GraphQL API. Like KeystoneJS and Contentful, it doesn't render HTML — so OG tags are generated by your frontend (Next.js, Nuxt, SvelteKit, etc.) using data from the Directus API.
The recommended pattern is to add dedicated OG fields to your content collections in Directus, then query those fields in your frontend's metadata layer. This gives editors full control over social preview appearance.
Step 1: Add SEO fields to your Directus collection
In the Directus admin panel, add these fields to your content collection (e.g., posts):
seo_title— Input (String) — fallback totitleseo_description— Textarea (String) — fallback toexcerptseo_image— Image (UUID) — Directus file relation
Using a Directus M2O relation to the directus_files table for the image field lets you leverage Directus's built-in image transformation API (crop, resize, format) to ensure the correct 1200×630 dimensions.
Step 2: Query OG data from the Directus REST API
// lib/directus.ts
const DIRECTUS_URL = process.env.DIRECTUS_URL!;
const DIRECTUS_TOKEN = process.env.DIRECTUS_TOKEN!;
export async function getPost(slug: string) {
const res = await fetch(
`${DIRECTUS_URL}/items/posts?filter[slug][_eq]=${slug}&fields[]=title,excerpt,content,seo_title,seo_description,seo_image.*&limit=1`,
{
headers: {
Authorization: `Bearer ${DIRECTUS_TOKEN}`,
},
next: { revalidate: 60 },
}
);
const { data } = await res.json();
return data[0] || null;
}
// Directus image URL with transformation
export function directusImageUrl(
fileId: string,
width = 1200,
height = 630
): string {
return `${DIRECTUS_URL}/assets/${fileId}?width=${width}&height=${height}&format=webp&quality=85`;
}Step 3: Generate metadata in Next.js
// app/posts/[slug]/page.tsx
import type { Metadata } from "next";
import { getPost, directusImageUrl } from "@/lib/directus";
export async function generateMetadata({
params,
}: {
params: { slug: string };
}): Promise<Metadata> {
const post = await getPost(params.slug);
if (!post) return { title: "Not Found" };
const title = post.seo_title || post.title;
const description = post.seo_description || post.excerpt;
const imageUrl = post.seo_image?.id
? directusImageUrl(post.seo_image.id)
: undefined;
return {
title,
description,
openGraph: {
title,
description,
type: "article",
images: imageUrl
? [{ url: imageUrl, width: 1200, height: 630 }]
: [],
},
twitter: {
card: "summary_large_image",
title,
description,
images: imageUrl ? [imageUrl] : [],
},
};
}
export default async function PostPage({
params,
}: {
params: { slug: string };
}) {
const post = await getPost(params.slug);
return <article><h1>{post.title}</h1></article>;
}Using Directus image transformations for OG
One major advantage of Directus is the built-in image transformation API. When editors upload a high-res image, you can generate an optimized 1200×630 OG crop on-the-fly:
// Directus image transformation URL parameters
const ogImage = `${DIRECTUS_URL}/assets/${fileId}?` + new URLSearchParams({
width: "1200",
height: "630",
fit: "cover", // crop to exact dimensions
format: "webp", // optimized format
quality: "85", // file size balance
}).toString();
// Result: https://your-directus.com/assets/uuid?width=1200&height=630&fit=cover&format=webp&quality=85This eliminates the need to manually create OG-sized images — editors upload once, Directus crops to fit.
Directus Flow for automatic OG image generation
For advanced setups, use a Directus Flow (webhook trigger) to auto-generate OG images when content is published:
- Trigger: Item Updated on the posts collection
- Condition: status changed to "published"
- Action: HTTP Request to your OG image generator API with the post title
- Action: Update the
seo_imagefield with the generated image ID
Common pitfalls with Directus OG
- CORS on assets: Configure Directus
ASSETS_TRANSFORM_IMAGE_MAX_DIMENSIONand ensure your assets URL is accessible from social crawlers - Authentication on assets: Use
PUBLIC_ROLEpermissions so social scrapers can fetch OG images without auth tokens - Missing fallback: Always fall back to a default OG image if
seo_imageis null - Cache headers: Set
ASSETS_CACHE_TTLappropriately — too long and OG updates won't propagate
Verify your Directus OG tags live
After deploying, paste your page URL into OGFixer to see exactly how your social previews render on Twitter, LinkedIn, Discord, and Slack.
Check your OG tags free →