#og
1 messages · Page 1 of 1 (latest)
The error is happening because searchParams is not a supported prop for opengraph-image in Next.js. For opengraph-image and twitter-image, the only documented prop is params (for dynamic route segments), and in Next.js 16 it is a promise. [OG props; Async params change]
So this signature is not valid:
export default async function Image({
searchParams,
}: {
searchParams: Promise<{ date?: string }>
}) {
const { date } = await searchParams
}
searchParams will be undefined, which is why destructuring fails.
How to fix
For an OG image under /api/leaderboard/opengraph-image, you have two options:
-
Use the request URL (recommended for API-style OG routes)
Instead ofopengraph-image.tsx, use a route handler like in Vercel’s OG docs and read the query fromrequest.url:// app/api/leaderboard/opengraph-image/route.tsx import { ImageResponse } from 'next/og' export async function GET(request: Request) { const { searchParams } = new URL(request.url) const date = searchParams.get('date') if (!date) { return new Response('Missing date parameter', { status: 400 }) } return new ImageResponse( <div>{date}</div>, { width: 1200, height: 630 }, ) }This pattern is exactly how Vercel shows passing
?title=as a URL parameter for OG images. [Dynamic text OG] -
If you really need the
opengraph-imagefile convention
You can only receiveparams(dynamic segments), notsearchParams. The documented signature is:
export default async function Image({
params,
}: {
params: Promise<{ slug: string }>
}) {
const { slug } = await params
// ...
}
[OG props]
In this case, query string like ?date=... is not available via searchParams prop.
Given your URL (/api/leaderboard/opengraph-image?date=...), switching to a route.tsx handler and reading new URL(request.url).searchParams is the correct and supported way to access date.
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@jaunty hound Kapa.ai is still learning and improving, please let me know how I did by reacting below.
how cache this as its very heavy @vague magnet
Let me check the knowledge base for you again. Give me one moment! :books:
You’re generating an OG image at /api/leaderboard/opengraph-image and want to cache it because it’s heavy.
From the docs, there are two relevant caching layers:
- Next.js Data/HTML cache (App Router OG routes)
- Vercel CDN cache via
Cache-Controlheaders
1. Use the built‑in OG route caching
opengraph-image.tsx is a special Route Handler that is cached by default unless you use Dynamic APIs or dynamic config. [OG route caching]
So if your opengraph-image.tsx:
- Only uses cached
fetch(e.g.cache: 'force-cache'ornext: { revalidate: ... }), or - Only uses static data,
then Next.js will statically optimize and cache the generated image automatically. [OG route caching]
To make heavy data fetching cheaper, cache that data:
const res = await fetch('<https://your-api/leaderboard',> {
cache: 'force-cache',
next: { revalidate: 3600 }, // revalidate every hour
})
const data = await res.json()
This uses the Data Cache and revalidates in the background (stale‑while‑revalidate style). [Data cache; Time-based revalidate]
2. If you use an API route (/api/og) instead
If you switch to an API route (e.g. app/api/leaderboard/opengraph-image/route.tsx returning new ImageResponse(...)), Vercel will automatically cache OG images on the CDN when using @vercel/og / next/og. [Vercel OG benefits; Next.js on Vercel OG]
You can further control CDN caching with Cache-Control headers from the route handler (it’s just a function response):
import { ImageResponse } from 'next/og'
export const runtime = 'nodejs' // if needed
export async function GET(request: Request) {
// heavy work here...
const image = new ImageResponse(<div>...</div>, {
width: 1200,
height: 630,
})
// Wrap in a Response to add headers
return new Response(image.body, {
status: 200,
headers: {
'Content-Type': 'image/png',
// cache 10 minutes, serve stale while revalidating 50 minutes
'Cache-Control': 'public, s-maxage=600, stale-while-revalidate=3000',
},
})
}
Vercel’s CDN will then cache this response according to s-maxage / stale-while-revalidate. [How to cache responses; stale-while-revalidate]
3. Summary of practical options
- Inside the OG route:
- Cache heavy data with
fetch(..., { cache: 'force-cache', next: { revalidate: N } }). [Next fetch caching]
- Cache heavy data with
- At the image level:
- If using
opengraph-image.tsxfile convention, rely on its default static optimization and caching (avoid dynamic APIs where possible). [OG route caching] - If using an API route (
route.tsx), addCache-Control: s-maxage=..., stale-while-revalidate=...so Vercel’s CDN caches the generated image. [How to cache responses]
- If using