A signed image URL straight from generateMetadata — no request while the page renders.
The package signs the image URL inside `generateMetadata` with Web Crypto, so the same code runs in the Node.js and the Edge runtime. Nothing is fetched while Next.js renders the page: the image is drawn on the first crawler hit and cached, and a rebuild of the same post costs nothing against your quota.
app/blog/[slug]/page.tsx
// npm i @shareglint/next
// .env: SHAREGLINT_ACCOUNT_ID and SHAREGLINT_SIGNING_SECRET (dashboard)
import type { Metadata } from 'next';
import { ogImageMetadata } from '@shareglint/next';
export async function generateMetadata({ params }): Promise<Metadata> {
const post = await getPost((await params).slug);
return {
title: post.title,
// A signed URL built locally with Web Crypto - no request to the API,
// Node.js and Edge runtime alike. Adds openGraph.images and twitter.
...(await ogImageMetadata({
template: 'blog-og',
fields: { title: post.title, author: post.author, site: 'yourblog.com' },
alt: post.title,
})),
};
}
The same thing as one plain HTTP call — no dependency to install.
app/blog/[slug]/page.tsx
import type { Metadata } from 'next';
async function ogImage(title: string, author: string) {
const res = await fetch('https://shareglint.com/v1/images?wait=true', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.SHAREGLINT_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
template: 'blog-og',
modifications: { title, author, site: 'yourblog.com' },
}),
// Same post, same image - so the cache can live forever.
next: { revalidate: false },
});
const { url } = await res.json();
return url as string;
}
export async function generateMetadata({ params }): Promise<Metadata> {
const post = await getPost(params.slug);
return {
title: post.title,
openGraph: { images: [await ogImage(post.title, post.author)] },
twitter: { card: 'summary_large_image' },
};
}
The signing secret has to stay on the server. `generateMetadata` only runs there — import the helper into a client component and it refuses to sign rather than ship the secret to the browser. Calling the API directly instead? The API key has the same rule.
With ?wait=true the finished image arrives on the same connection — usually in about a second.
{
"id": "img_01m08s3ez1zcv28h335g9923bw",
"status": "completed",
"url": "https://cdn.shareglint.com/renders/img_01m08s3ez1zcv28h335g9923bw.png",
"duration_ms": 912
}
A hundred images a month free, then $9 for two thousand. The same post rendered twice returns the existing URL and uses no quota — so rebuilding your site costs nothing.