mirror of
https://github.com/hanzoai/next.js.git
synced 2026-09-24 17:00:51 +00:00
### Change the `next/server` to `next/og` to support the upgrade to Next 14 - Next 14 users will experience a deprecation warning when trying to import from `next/server` - Not the biggest change, but it caused some confusion while reading <!-- Thanks for opening a PR! Your contribution is much appreciated. To make sure your PR is handled as smoothly as possible we request that you follow the checklist sections below. Choose the right checklist for the change(s) that you're making: ## For Contributors ### Improving Documentation - Run `pnpm prettier-fix` to fix formatting issues before opening the PR. - Read the Docs Contribution Guide to ensure your contribution follows the docs guidelines: https://nextjs.org/docs/community/contribution-guide ### Adding or Updating Examples - The "examples guidelines" are followed from our contributing doc https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md - Make sure the linting passes by running `pnpm build && pnpm lint`. See https://github.com/vercel/next.js/blob/canary/contributing/repository/linting.md ### Fixing a bug - Related issues linked using `fixes #number` - Tests added. See: https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs - Errors have a helpful link attached, see https://github.com/vercel/next.js/blob/canary/contributing.md ### Adding a feature - Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. (A discussion must be opened, see https://github.com/vercel/next.js/discussions/new?category=ideas) - Related issues/discussions are linked using `fixes #number` - e2e tests added (https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs) - Documentation added - Telemetry added. In case of a feature if it's used or not. - Errors have a helpful link attached, see https://github.com/vercel/next.js/blob/canary/contributing.md ## For Maintainers - Minimal description (aim for explaining to someone not on the team to understand the PR) - When linking to a Slack thread, you might want to share details of the conclusion - Link both the Linear (Fixes NEXT-xxx) and the GitHub issues - Add review comments if necessary to explain to the reviewer the logic behind a change ### What? ### Why? ### How? Closes NEXT- Fixes # -->
429 lines
14 KiB
Plaintext
429 lines
14 KiB
Plaintext
---
|
|
title: opengraph-image and twitter-image
|
|
description: API Reference for the Open Graph Image and Twitter Image file conventions.
|
|
---
|
|
|
|
The `opengraph-image` and `twitter-image` file conventions allow you to set Open Graph and Twitter images for a route segment.
|
|
|
|
They are useful for setting the images that appear on social networks and messaging apps when a user shares a link to your site.
|
|
|
|
There are two ways to set Open Graph and Twitter images:
|
|
|
|
- [Using image files (.jpg, .png, .gif)](#image-files-jpg-png-gif)
|
|
- [Using code to generate images (.js, .ts, .tsx)](#generate-images-using-code-js-ts-tsx)
|
|
|
|
## Image files (.jpg, .png, .gif)
|
|
|
|
Use an image file to set a route segment's shared image by placing an `opengraph-image` or `twitter-image` image file in the segment.
|
|
|
|
Next.js will evaluate the file and automatically add the appropriate tags to your app's `<head>` element.
|
|
|
|
| File convention | Supported file types |
|
|
| ----------------------------------------------- | ------------------------------- |
|
|
| [`opengraph-image`](#opengraph-image) | `.jpg`, `.jpeg`, `.png`, `.gif` |
|
|
| [`twitter-image`](#twitter-image) | `.jpg`, `.jpeg`, `.png`, `.gif` |
|
|
| [`opengraph-image.alt`](#opengraph-imagealttxt) | `.txt` |
|
|
| [`twitter-image.alt`](#twitter-imagealttxt) | `.txt` |
|
|
|
|
### `opengraph-image`
|
|
|
|
Add an `opengraph-image.(jpg|jpeg|png|gif)` image file to any route segment.
|
|
|
|
```html filename="<head> output"
|
|
<meta property="og:image" content="<generated>" />
|
|
<meta property="og:image:type" content="<generated>" />
|
|
<meta property="og:image:width" content="<generated>" />
|
|
<meta property="og:image:height" content="<generated>" />
|
|
```
|
|
|
|
### `twitter-image`
|
|
|
|
Add a `twitter-image.(jpg|jpeg|png|gif)` image file to any route segment.
|
|
|
|
```html filename="<head> output"
|
|
<meta name="twitter:image" content="<generated>" />
|
|
<meta name="twitter:image:type" content="<generated>" />
|
|
<meta name="twitter:image:width" content="<generated>" />
|
|
<meta name="twitter:image:height" content="<generated>" />
|
|
```
|
|
|
|
### `opengraph-image.alt.txt`
|
|
|
|
Add an accompanying `opengraph-image.alt.txt` file in the same route segment as the `opengraph-image.(jpg|jpeg|png|gif)` image it's alt text.
|
|
|
|
```txt filename="opengraph-image.alt.txt"
|
|
About Acme
|
|
```
|
|
|
|
```html filename="<head> output"
|
|
<meta property="og:image:alt" content="About Acme" />
|
|
```
|
|
|
|
### `twitter-image.alt.txt`
|
|
|
|
Add an accompanying `twitter-image.alt.txt` file in the same route segment as the `twitter-image.(jpg|jpeg|png|gif)` image it's alt text.
|
|
|
|
```txt filename="twitter-image.alt.txt"
|
|
About Acme
|
|
```
|
|
|
|
```html filename="<head> output"
|
|
<meta property="twitter:image:alt" content="About Acme" />
|
|
```
|
|
|
|
## Generate images using code (.js, .ts, .tsx)
|
|
|
|
In addition to using [literal image files](#image-files-jpg-png-gif), you can programmatically **generate** images using code.
|
|
|
|
Generate a route segment's shared image by creating an `opengraph-image` or `twitter-image` route that default exports a function.
|
|
|
|
| File convention | Supported file types |
|
|
| ----------------- | -------------------- |
|
|
| `opengraph-image` | `.js`, `.ts`, `.tsx` |
|
|
| `twitter-image` | `.js`, `.ts`, `.tsx` |
|
|
|
|
> **Good to know**
|
|
>
|
|
> - By default, generated images are [**statically optimized**](/docs/app/building-your-application/rendering/server-components#static-rendering-default) (generated at build time and cached) unless they use [dynamic functions](/docs/app/building-your-application/rendering/server-components#server-rendering-strategies#dynamic-functions) or uncached data.
|
|
> - You can generate multiple Images in the same file using [`generateImageMetadata`](/docs/app/api-reference/functions/generate-image-metadata).
|
|
|
|
The easiest way to generate an image is to use the [ImageResponse](/docs/app/api-reference/functions/image-response) API from `next/og`.
|
|
|
|
```tsx filename="app/about/opengraph-image.tsx" switcher
|
|
import { ImageResponse } from 'next/og'
|
|
|
|
// Route segment config
|
|
export const runtime = 'edge'
|
|
|
|
// Image metadata
|
|
export const alt = 'About Acme'
|
|
export const size = {
|
|
width: 1200,
|
|
height: 630,
|
|
}
|
|
|
|
export const contentType = 'image/png'
|
|
|
|
// Image generation
|
|
export default async function Image() {
|
|
// Font
|
|
const interSemiBold = fetch(
|
|
new URL('./Inter-SemiBold.ttf', import.meta.url)
|
|
).then((res) => res.arrayBuffer())
|
|
|
|
return new ImageResponse(
|
|
(
|
|
// ImageResponse JSX element
|
|
<div
|
|
style={{
|
|
fontSize: 128,
|
|
background: 'white',
|
|
width: '100%',
|
|
height: '100%',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
}}
|
|
>
|
|
About Acme
|
|
</div>
|
|
),
|
|
// ImageResponse options
|
|
{
|
|
// For convenience, we can re-use the exported opengraph-image
|
|
// size config to also set the ImageResponse's width and height.
|
|
...size,
|
|
fonts: [
|
|
{
|
|
name: 'Inter',
|
|
data: await interSemiBold,
|
|
style: 'normal',
|
|
weight: 400,
|
|
},
|
|
],
|
|
}
|
|
)
|
|
}
|
|
```
|
|
|
|
```jsx filename="app/about/opengraph-image.js" switcher
|
|
import { ImageResponse } from 'next/og'
|
|
|
|
// Route segment config
|
|
export const runtime = 'edge'
|
|
|
|
// Image metadata
|
|
export const alt = 'About Acme'
|
|
export const size = {
|
|
width: 1200,
|
|
height: 630,
|
|
}
|
|
|
|
export const contentType = 'image/png'
|
|
|
|
// Image generation
|
|
export default async function Image() {
|
|
// Font
|
|
const interSemiBold = fetch(
|
|
new URL('./Inter-SemiBold.ttf', import.meta.url)
|
|
).then((res) => res.arrayBuffer())
|
|
|
|
return new ImageResponse(
|
|
(
|
|
// ImageResponse JSX element
|
|
<div
|
|
style={{
|
|
fontSize: 128,
|
|
background: 'white',
|
|
width: '100%',
|
|
height: '100%',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
}}
|
|
>
|
|
About Acme
|
|
</div>
|
|
),
|
|
// ImageResponse options
|
|
{
|
|
// For convenience, we can re-use the exported opengraph-image
|
|
// size config to also set the ImageResponse's width and height.
|
|
...size,
|
|
fonts: [
|
|
{
|
|
name: 'Inter',
|
|
data: await interSemiBold,
|
|
style: 'normal',
|
|
weight: 400,
|
|
},
|
|
],
|
|
}
|
|
)
|
|
}
|
|
```
|
|
|
|
```html filename="<head> output"
|
|
<meta property="og:image" content="<generated>" />
|
|
<meta property="og:image:alt" content="About Acme" />
|
|
<meta property="og:image:type" content="image/png" />
|
|
<meta property="og:image:width" content="1200" />
|
|
<meta property="og:image:height" content="630" />
|
|
```
|
|
|
|
### Props
|
|
|
|
The default export function receives the following props:
|
|
|
|
#### `params` (optional)
|
|
|
|
An object containing the [dynamic route parameters](/docs/app/building-your-application/routing/dynamic-routes) object from the root segment down to the segment `opengraph-image` or `twitter-image` is colocated in.
|
|
|
|
```tsx filename="app/shop/[slug]/opengraph-image.tsx" switcher
|
|
export default function Image({ params }: { params: { slug: string } }) {
|
|
// ...
|
|
}
|
|
```
|
|
|
|
```jsx filename="app/shop/[slug]/opengraph-image.js" switcher
|
|
export default function Image({ params }) {
|
|
// ...
|
|
}
|
|
```
|
|
|
|
| Route | URL | `params` |
|
|
| ------------------------------------------ | ----------- | ------------------------- |
|
|
| `app/shop/opengraph-image.js` | `/shop` | `undefined` |
|
|
| `app/shop/[slug]/opengraph-image.js` | `/shop/1` | `{ slug: '1' }` |
|
|
| `app/shop/[tag]/[item]/opengraph-image.js` | `/shop/1/2` | `{ tag: '1', item: '2' }` |
|
|
| `app/shop/[...slug]/opengraph-image.js` | `/shop/1/2` | `{ slug: ['1', '2'] }` |
|
|
|
|
### Returns
|
|
|
|
The default export function should return a `Blob` | `ArrayBuffer` | `TypedArray` | `DataView` | `ReadableStream` | `Response`.
|
|
|
|
> **Good to know**: `ImageResponse` satisfies this return type.
|
|
|
|
### Config exports
|
|
|
|
You can optionally configure the image's metadata by exporting `alt`, `size`, and `contentType` variables from `opengraph-image` or `twitter-image` route.
|
|
|
|
| Option | Type |
|
|
| ----------------------------- | --------------------------------------------------------------------------------------------------------------- |
|
|
| [`alt`](#alt) | `string` |
|
|
| [`size`](#size) | `{ width: number; height: number }` |
|
|
| [`contentType`](#contenttype) | `string` - [image MIME type](https://developer.mozilla.org/docs/Web/HTTP/Basics_of_HTTP/MIME_types#image_types) |
|
|
|
|
#### `alt`
|
|
|
|
```tsx filename="opengraph-image.tsx | twitter-image.tsx" switcher
|
|
export const alt = 'My images alt text'
|
|
|
|
export default function Image() {}
|
|
```
|
|
|
|
```jsx filename="opengraph-image.js | twitter-image.js" switcher
|
|
export const alt = 'My images alt text'
|
|
|
|
export default function Image() {}
|
|
```
|
|
|
|
```html filename="<head> output"
|
|
<meta property="og:image:alt" content="My images alt text" />
|
|
```
|
|
|
|
#### `size`
|
|
|
|
```tsx filename="opengraph-image.tsx | twitter-image.tsx" switcher
|
|
export const size = { width: 1200, height: 630 }
|
|
|
|
export default function Image() {}
|
|
```
|
|
|
|
```jsx filename="opengraph-image.js | twitter-image.js" switcher
|
|
export const size = { width: 1200, height: 630 }
|
|
|
|
export default function Image() {}
|
|
```
|
|
|
|
```html filename="<head> output"
|
|
<meta property="og:image:width" content="1200" />
|
|
<meta property="og:image:height" content="630" />
|
|
```
|
|
|
|
#### `contentType`
|
|
|
|
```tsx filename="opengraph-image.tsx | twitter-image.tsx" switcher
|
|
export const contentType = 'image/png'
|
|
|
|
export default function Image() {}
|
|
```
|
|
|
|
```jsx filename="opengraph-image.js | twitter-image.js" switcher
|
|
export const contentType = 'image/png'
|
|
|
|
export default function Image() {}
|
|
```
|
|
|
|
```html filename="<head> output"
|
|
<meta property="og:image:type" content="image/png" />
|
|
```
|
|
|
|
#### Route Segment Config
|
|
|
|
`opengraph-image` and `twitter-image` are specialized [Route Handlers](/docs/app/building-your-application/routing/route-handlers) that can use the same [route segment configuration](/docs/app/api-reference/file-conventions/route-segment-config) options as Pages and Layouts.
|
|
|
|
| Option | Type | Default |
|
|
| -------------------------------------------------------------------------------------------------- | -------------------------------------------------------- | ---------- |
|
|
| [`dynamic`](/docs/app/api-reference/file-conventions/route-segment-config#dynamic) | `'auto' \| 'force-dynamic' \| 'error' \| 'force-static'` | `'auto'` |
|
|
| [`revalidate`](/docs/app/api-reference/file-conventions/route-segment-config#revalidate) | `false \| 'force-cache' \| 0 \| number` | `false` |
|
|
| [`runtime`](/docs/app/api-reference/file-conventions/route-segment-config#runtime) | `'nodejs' \| 'edge'` | `'nodejs'` |
|
|
| [`preferredRegion`](/docs/app/api-reference/file-conventions/route-segment-config#preferredregion) | `'auto' \| 'global' \| 'home' \| string \| string[]` | `'auto'` |
|
|
|
|
```tsx filename="app/opengraph-image.tsx" switcher
|
|
export const runtime = 'edge'
|
|
|
|
export default function Image() {}
|
|
```
|
|
|
|
```jsx filename="app/opengraph-image.js" switcher
|
|
export const runtime = 'edge'
|
|
|
|
export default function Image() {}
|
|
```
|
|
|
|
### Examples
|
|
|
|
#### Using external data
|
|
|
|
This example uses the `params` object and external data to generate the image.
|
|
|
|
> **Good to know**:
|
|
> By default, this generated image will be [statically optimized](/docs/app/building-your-application/rendering/server-components#static-rendering-default). You can configure the individual `fetch` [`options`](/docs/app/api-reference/functions/fetch) or route segments [options](/docs/app/api-reference/file-conventions/route-segment-config#revalidate) to change this behavior.
|
|
|
|
```tsx filename="app/posts/[slug]/opengraph-image.tsx" switcher
|
|
import { ImageResponse } from 'next/og'
|
|
|
|
export const runtime = 'edge'
|
|
|
|
export const alt = 'About Acme'
|
|
export const size = {
|
|
width: 1200,
|
|
height: 630,
|
|
}
|
|
export const contentType = 'image/png'
|
|
|
|
export default async function Image({ params }: { params: { slug: string } }) {
|
|
const post = await fetch(`https://.../posts/${params.slug}`).then((res) =>
|
|
res.json()
|
|
)
|
|
|
|
return new ImageResponse(
|
|
(
|
|
<div
|
|
style={{
|
|
fontSize: 48,
|
|
background: 'white',
|
|
width: '100%',
|
|
height: '100%',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
}}
|
|
>
|
|
{post.title}
|
|
</div>
|
|
),
|
|
{
|
|
...size,
|
|
}
|
|
)
|
|
}
|
|
```
|
|
|
|
```jsx filename="app/posts/[slug]/opengraph-image.js" switcher
|
|
import { ImageResponse } from 'next/og'
|
|
|
|
export const runtime = 'edge'
|
|
|
|
export const alt = 'About Acme'
|
|
export const size = {
|
|
width: 1200,
|
|
height: 630,
|
|
}
|
|
export const contentType = 'image/png'
|
|
|
|
export default async function Image({ params }) {
|
|
const post = await fetch(`https://.../posts/${params.slug}`).then((res) =>
|
|
res.json()
|
|
)
|
|
|
|
return new ImageResponse(
|
|
(
|
|
<div
|
|
style={{
|
|
fontSize: 48,
|
|
background: 'white',
|
|
width: '100%',
|
|
height: '100%',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
}}
|
|
>
|
|
{post.title}
|
|
</div>
|
|
),
|
|
{
|
|
...size,
|
|
}
|
|
)
|
|
}
|
|
```
|
|
|
|
## Version History
|
|
|
|
| Version | Changes |
|
|
| --------- | ------------------------------------------------- |
|
|
| `v13.3.0` | `opengraph-image` and `twitter-image` introduced. |
|