Peekly

Open Graph tags in Next.js

The App Router writes the meta tags for you. Export a metadata object from a Server Component, and add an opengraph-image file when you want the image generated. Deploy it, then paste that public URL into the checker above.

Free. No signup. Public pages only.

Add the tags

  • The metadata object. Only a Server Component can export metadata. A file marked "use client" cannot. Set metadataBase once, in the root layout, to your absolute origin. Relative image and canonical paths are joined to it, and a relative path without metadataBase fails the build. An absolute URL in a field ignores metadataBase. title and description are the document title and the meta description. Repeat them on openGraph so the share card has its own title and description. Set twitter.card to summary_large_image, or X shows a small thumbnail. X will fall back to og:image, but the card type is what selects the large layout. When the title depends on the route, export generateMetadata instead of a static object. In Next.js 15, params on that function is a Promise, so await it before you read the slug.
    import type { Metadata } from "next";
    
    export const metadata: Metadata = {
      title: "Post title",
      description: "One or two sentences.",
      openGraph: {
        title: "Post title",
        description: "One or two sentences.",
        url: "/post",
        images: [
          {
            url: "/og.png",
            width: 1200,
            height: 630,
          },
        ],
      },
      twitter: {
        card: "summary_large_image",
        title: "Post title",
        description: "One or two sentences.",
        images: ["/og.png"],
      },
    };
  • opengraph-image. Put opengraph-image.tsx, or a png, jpg, or gif of that name, in the route segment. Next.js serves the file and adds og:image, og:image:type, og:image:width, and og:image:height. Export alt and it adds og:image:alt. A file deeper in the tree replaces one above it. When twitter.images is unset, Next.js copies the Open Graph images onto the Twitter card, and if a Twitter image is present while twitter.card is unset it emits summary_large_image. Set the card in metadata anyway, so the choice sits in the file you maintain. Add a twitter-image file only when that image should differ. A static opengraph-image over 8 MB, or a twitter-image over 5 MB, fails the build. The code version uses ImageResponse from next/og. The JSX it accepts is flexbox; display:grid will not work. On a dynamic route the image function can read params. Next.js 15.5 passes that value as a plain object. Newer App Router docs type it as a Promise. Follow the types in the version you have installed.
    import { ImageResponse } from "next/og";
    
    export const alt = "Post title";
    export const size = { width: 1200, height: 630 };
    export const contentType = "image/png";
    
    export default function Image() {
      return new ImageResponse(
        (
          <div
            style={{
              fontSize: 64,
              background: "white",
              width: "100%",
              height: "100%",
              display: "flex",
            }}
          >
            Post title
          </div>
        ),
        { ...size },
      );
    }
  • What a crawler receives. On a static page the tags are in the first HTML response. On a dynamic page Next.js can stream metadata after the UI, except for crawlers on its htmlLimitedBots list, which includes Twitterbot and Slackbot. Those still get the tags in the initial HTML. The checker above sends a user agent that includes Twitterbot, so a Next.js page returns the tags in that first response. Paste the public URL, not a localhost address. The checker only fetches public pages, and it grades og:title, og:description, og:image, and the Twitter card from the HTML your server sends.

Tags covered: og:title · og:description · og:image · og:url · twitter:card · twitter:image

More checkers

Twitter Card ValidatorOpen Graph CheckerLinkedIn Link Preview CheckerDiscord Embed PreviewWhatsApp Link Preview CheckerSlack Link Preview CheckeriMessage Link Preview CheckerFacebook Link Preview CheckerOpen Graph Image SizeTelegram Link Preview CheckerReddit Link Preview CheckerRefresh a Link Preview CacheAll platforms

What each platform reads

  • X / Twittertwitter:card, twitter:* → og:* fallback1200×630 (min 300×157), < 5 MB
  • Facebookog:title, og:description, og:image1200×630, 1.91:1
  • LinkedInog:title, og:image (og: only)1200×627, 1.91:1
  • Discordog:site_name, og:*, theme-color, twitter:cardLarge image needs summary_large_image
  • Slackog:site_name, og:title, og:description, og:image1200×630
  • WhatsAppog:title, og:description, og:imageKeep < 300 KB

Guidance based on each platform's public documentation and observed behavior. Platforms change their rules without notice.

FAQ

+Is Peekly free?

Yes. Checking a single URL is free forever — no signup and no limit on one-off checks. Batch watching and monitoring may arrive later as a paid Pro plan; the free single-URL tool stays.

+Why does my link show no image when I share it?

Usually one of four things: there's no og:image tag, the image URL is relative instead of absolute, the image is behind a login, firewall or bot block, or the file is too big or in an unsupported format like SVG. Peekly checks all four and tells you which one it is.

+What size should my og:image be?

1200×630 pixels (a 1.91:1 ratio) as a PNG or JPG under about 300 KB. That size works for large cards on X, Facebook, LinkedIn, Discord, Slack and WhatsApp.

+Do I need twitter: tags if I already have Open Graph tags?

X reads og:title, og:description and og:image as fallbacks, but you still need twitter:card set to summary_large_image if you want the big image card. Without it, X shows a small thumbnail.

+I fixed my tags but the old preview still shows. Why?

Platforms cache link previews, sometimes for days. Facebook and LinkedIn let you force a refresh with their own debugging tools. On X, Slack and Discord the cache usually expires on its own, or you can add a query string such as ?v=2 to the URL.

+Do you store the pages I check?

No. We fetch the page once to read its <head>, show you the result, and don't save the page or the result. We only fetch public http(s) URLs, and private or internal addresses are blocked.

+Are the previews pixel-perfect?

They're close approximations of each platform's current card layout, built from the same tags the platforms read. Platforms change their designs from time to time, so treat them as a very good guide rather than a screenshot.

$9

One time

A written fix for the batch.

Up to 25 URLs. We check og:image, Twitter cards, size, redirects, and cache, then send copy-paste meta tags within 48 hours. The free single-URL check stays free.

Get the fix report — $9