Files
goobyandGitHub 9b4b0847ed typo: changed from next/server to next/og (#58143)
### 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 #

-->
2023-11-07 18:38:57 +01:00

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. |