Embedded and static tweet for Next.js applications.


Next.js 13.2.1 or higher is required in order to use react-tweet.

Install react-tweet using your package manager of choice:

pnpm add react-tweet
yarn add react-tweet
npm install react-tweet

Currently, react-tweet uses next/image behind the scenes. You can configure next/image to accept image URLs from Twitter, by using images.remotePatterns in next.config.js:

/** @type {import('next').NextConfig} */
const nextConfig = {
  images: {
    remotePatterns: [
      { protocol: 'https', hostname: '' },
      { protocol: 'https', hostname: '' },

Now follow the usage instructions below. No API keys are required.

Usage with App Router

In any component, import NextTweet from react-tweet and use it like so:

import { NextTweet } from 'react-tweet'

export default function Page({ params }: Props) {
  return <NextTweet id={params.tweet} />

NextTweet accepts the following props:

  • idstring: the tweet ID. For example in the tweet ID is 1629307668568633344.
  • notFoundOnErrorboolean: if true, the component will show a not found message if the tweet fails to load (invalid id, no longer exists, account went private, etc). Otherwise, it will throw an error. Defaults to false.

NextTweet takes care of fetching the tweet and rendering it. You can see it working in the Next.js sample app that’s part of this monorepo.

Choosing a theme

The prefers-color-scheme CSS media feature is used to select the theme of the tweet.

Toggling theme manually

The closest data-theme attribute on a parent element can determine the theme of the tweet. You can set it to light or dark, like so:

<div data-theme="dark">
  <NextTweet id={params.tweet} />

Alternatively, a parent with the class light or dark will also work:

<div className="dark">
  <NextTweet id={params.tweet} />

Usage in pages directory

Use the getTweet function from react-tweet to fetch the tweet and send it as props to the page component:

import { getTweet, type Tweet } from 'react-tweet/api'

export async function getStaticProps({
}: {
  params: { tweet: string }
}) {
  try {
    const tweet = await getTweet(params.tweet)
    return tweet ? { props: { tweet } } : { notFound: true }
  } catch (error) {
    return { notFound: true }

export async function getStaticPaths() {
  return { paths: [], fallback: true }

export default function Page({ tweet }: { tweet: Tweet }) {
  return <TweetPage tweet={tweet} />

The TweetPage component uses EmbeddedTweet to render the tweet, and TweetSkeleton to render a skeleton in case you need a loading state (e.g. when using fallback: true in getStaticPaths):

import { useRouter } from 'next/router'
import { EmbeddedTweet, TweetSkeleton } from 'react-tweet'
import type { Tweet } from 'react-tweet/api'

const TweetPage = ({ tweet }: { tweet: Tweet }) => {
  const { isFallback } = useRouter()

  return (
    <div data-theme="dark">
      {isFallback ? <TweetSkeleton /> : <EmbeddedTweet tweet={tweet} />}

export default TweetPage

You can see it working in the test app that’s part of this monorepo.

Running the test app

Clone this repository and run the following command:

pnpm install && pnpm dev

Now visit http://localhost:3000/light/1629307668568633344 to see the tweet in the app directory, and http://localhost:3000/dark/1629307668568633344 to see the tweet in the pages directory.

The test app uses the react-tweet package in the root directory, so you can make changes to the package and see the changes reflected in the test app immediately.


View Github