SEO for Developers

Why your link preview shows the wrong image: the fix

You fixed your Open Graph tags, shared the link, and the preview still shows the old picture. Or your headshot. Or nothing.

Sandipan Das
Sandipan Das · full-stack developer, Kolkata, IndiaPublished · 11 min read
Why your link preview shows the wrong image: the fix — cover image

What are Open Graph tags?

Open Graph tags are short lines of code in a page's head that tell apps like Facebook, LinkedIn, X and WhatsApp what to show when someone shares the link: the title, a short description, the image and the page address. If they are missing or wrong, the app guesses, and usually guesses badly.

The Open Graph rules list four tags every page needs: og:title, og:type, og:image and og:url. If a page has an og:image, the rules say it should also have og:image:alt, a description of what is in the picture (not a caption). Most pages need this block:

<meta property="og:title" content="Why your link preview shows the wrong image" />
<meta property="og:description" content="The image size each app uses and how to clear its cache." />
<meta property="og:type" content="article" />
<meta property="og:url" content="https://www.example.com/blog/link-preview" />
<meta property="og:image" content="https://www.example.com/images/link-preview-share.jpg" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:image:alt" content="A phone showing a link preview card with the wrong picture" />
<meta name="twitter:card" content="summary_large_image" />

Replace every value with your own. The width and height must be the real size of your image file, not numbers copied from this example.

Most broken previews don't have missing tags. The tags are there, but they point to the wrong address, the wrong image, or an old copy the app saved.

An app's crawler (a bot that visits your page) reads the head of your page once, builds the card, and saves a copy. After that, people see the saved copy, not your page.

Facebook explains this in its guide to images in link shares. The first time a link is shared, its crawler saves the page details. It has to see an image at least once before it can show it, so the first person who shares may see no picture. Adding og:image:width and og:image:height lets it show the image straight away. Facebook also saves images by their address, so if you replace an image but keep the same file name, the old picture stays.

So when a preview looks wrong, the problem is in one of three places: the tags on your page, the image they point to, or the copy the app saved. Check them in that order.

Open Graph tags diagram: the page head tags, the app's crawler that caches the card, and the link preview people see
How a link preview is built: the crawler reads your Open Graph tags once and saves the card

The image size each app asks for

One 1200 × 630 JPG under 5 MB works on Facebook, LinkedIn and X. Keep the important words and faces in the middle, because X uses a slightly wider shape and some apps crop.

App

Size in its own docs

Shape

File limit

How to refresh its saved copy

Facebook

Use images at least 1200 × 630 for the best display; at the minimum 600 × 315 for large link images; smallest allowed 200 × 200

Keep close to 1.91:1

Must not go over 8 MB

Sharing Debugger → "Scrape Again"

LinkedIn

Minimum 1200 × 627

Recommended 1.91:1

5 MB maximum

Post Inspector

X

Minimum 300 × 157, maximum 4096 × 4096

2:1

Under 5 MB; JPG, PNG, WEBP or GIF; no SVG

No public refresh tool (see below)

WhatsApp

No official numbers published

Not documented

Not documented

No refresh tool (see below)

Sources: Facebook, LinkedIn. The X figures come from X's card docs, which have since moved; the old page no longer opens (checked 31 October 2026).

A few things the table can't show:

  • X's shape is 2:1, not 1.91:1. A 1200 × 630 image is a little taller than 2:1, so X may trim a thin strip from the top and bottom. Keep text away from the edges.

  • X warns against one image for every page. Its docs say not to use a generic image such as your logo or author photo that appears on many pages. I'll come back to this, because I did exactly that.

  • X and WhatsApp have no public refresh tool. It isn't in their docs, but it's widely reported that both keep a saved card for a while, and that WhatsApp may skip images with a large file size. Keep the image to a few hundred KB. To get a fresh card, share the link with a small extra bit on the end, like ?v=2, which they treat as a new address.

  • LinkedIn only refreshes new posts. Post Inspector updates the preview for new shares. Posts already published keep the old card.

What I found on my own site

On 31 October 2026 I checked eight live pages of sandipandas.dev while logged out: the tags were all there, but the images and addresses had problems. Then I checked this post itself and found three more.

The first check covered the homepage, About, Hire, the SEO checker tool, the SEO services page and three blog posts. I opened each one in Chrome without cookies, read every og: and twitter: tag, and opened each og:image to measure its real size.

  • 8 of 8 had the basic tags: one og:title, a description, image alt text, and twitter:card set to summary_large_image.

  • 6 of 8 used the same image, my headshot, including two blog posts. That is exactly what X's docs warn against. Shared side by side, those posts look the same.

  • 2 posts said their image was 1200 × 630, but the file was 1400 × 854.

  • 4 pages gave no image size at all, so Facebook can't show their image on the first share.

  • Logged in, one post showed the homepage's tags. My dashboard's preview mode swapped them. Logged out, it was fine.

Then I checked this post itself, and it broke three of its own rules:

  • Its og:url and canonical use sandipandas.dev without "www", and that address redirects to the www version. A canonical (the address you tell Google is the main one) should never point to an address that redirects. This comes from my site's template, so it needs a code change. Until then, this page breaks its own rule.

  • Its share image was a WebP file, while the post tells readers to export a JPG. I've swapped it for a JPG.

  • Its share image alt text is just the title plus "cover image", which says nothing about what's in the picture. This also comes from the template and needs a code change.

What I did not test: all of the above was checked in a normal browser. Crawlers don't run JavaScript and send their own user agent (the name a visitor gives the server), and Next.js can send different HTML to them. So a browser check is not proof of what Facebook or LinkedIn sees. The Sharing Debugger and Post Inspector checks are the ones that count.

Open Graph tags test on 8 pages of sandipandas.dev, 31 October 2026: basics right on all 8, six share one headshot image, two declare the wrong image size
My Open Graph tags test, 31 Oct 2026: the tags were fine on all eight pages, the images weren't

Why your preview looks wrong: the causes, in order

Seven causes, in the order I'd check them. The first three take a minute each.

  1. The image address isn't a full address. og:image needs the whole https:// address, not /images/share.jpg. In Next.js, a short path only works if metadataBase is set; without it, the Next.js docs say you get a build error.

  2. The page or image address redirects. If og:url, the canonical or the image address sends the crawler somewhere else first (http to https, or no-www to www), the app may save the wrong address or skip the image. Pick one address for your site and use it everywhere.

  3. The app is showing its saved copy. Refresh it with the tool in the table above. If you changed the image, give the new file a new name, because Facebook saves images by address.

  4. Two sets of tags. A theme and an SEO plugin both print og:title. The Open Graph rules say the first tag from the top wins when there's a clash, though each app decides for itself, so the one you edited may be ignored.

  5. The crawler is blocked. A robots.txt rule, a firewall, bot protection (like Cloudflare's bot settings) or hotlink protection can stop the crawler from reading the page or the image. So can an image stored somewhere private.

  6. The image is too heavy or the wrong type. Over 5 MB fails on LinkedIn and X; SVG fails on X. Export a JPG.

  7. Page tags wiped out the site tags (Next.js). Next.js merges a layout's and a page's settings shallowly: if a page sets openGraph with only a title, the layout's Open Graph image and description are gone for that page.

Fixing a wrong link preview: causes of no picture, wrong title or image, and an old cached card, with the Open Graph tags fix for each
Fixing a wrong link preview: start from what the card shows, then check the causes in order

Open Graph tags in Next.js and WordPress

In Next.js, the best fix is to let Next.js make a separate share image for every post, so no page falls back to the same picture. Next.js has a built-in way to do this: a file called opengraph-image.tsx. It also writes the og:image, width, height, type and alt tags for you, so the size can never be wrong.

First, set your site address once in the root layout. Read it from an environment variable so it always matches your real domain:

// app/layout.tsx (checked against the Next.js 16 docs)
import type { Metadata } from 'next'

export const metadata: Metadata = {
  // NEXT_PUBLIC_SITE_URL = your one real address, e.g. https://www.example.com
  metadataBase: new URL(process.env.NEXT_PUBLIC_SITE_URL!),
}

Option A: a share image made by code for every post. Put this file next to your post page:

// app/blog/[slug]/opengraph-image.tsx (Next.js 16)
import { ImageResponse } from 'next/og'
import { getPost } from '@/lib/posts' // your own function that loads a post

export const alt = 'Blog post title card' // replace with a real description
export const size = { width: 1200, height: 630 }
export const contentType = 'image/png'

export default async function Image({
  params,
}: {
  params: Promise<{ slug: string }>
}) {
  const { slug } = await params
  const post = await getPost(slug)

  return new ImageResponse(
    (
      <div
        style={{
          width: '100%',
          height: '100%',
          display: 'flex',
          alignItems: 'center',
          padding: 80,
          background: '#fbfaf8',
          fontSize: 64,
        }}
      >
        {post.title}
      </div>
    ),
    { ...size }
  )
}

Because the same size value sets both the real image and the tags, they can't disagree. One thing to know: this file wins over any image you set in generateMetadata, so use Option A or Option B for a route, not both.

Option B: an image you upload for each post. Store the image's real width, height and alt text with the post when you upload it, and pass those values on. Use the parent value so pages without their own image keep the site's default:

// app/blog/[slug]/page.tsx (Next.js 16)
import type { Metadata, ResolvingMetadata } from 'next'
import { getPost } from '@/lib/posts' // your own function that loads a post

type Props = { params: Promise<{ slug: string }> }

export async function generateMetadata(
  { params }: Props,
  parent: ResolvingMetadata
): Promise<Metadata> {
  const { slug } = await params
  const post = await getPost(slug)
  const parentImages = (await parent).openGraph?.images ?? []

  return {
    title: post.title,
    alternates: { canonical: `/blog/${slug}` },
    openGraph: {
      title: post.title,
      description: post.excerpt,
      type: 'article',
      url: `/blog/${slug}`,
      images: post.image
        ? [{
            url: post.image.url,
            width: post.image.width,   // the file's real size, saved at upload
            height: post.image.height,
            alt: post.image.alt,       // what is in the picture
          }]
        : parentImages,
    },
  }
}

Newer Next.js versions can send page details after the first part of the page. The docs say that for bots that can't run JavaScript, such as facebookexternalhit, the tags are still put in the <head>. If you've changed the htmlLimitedBots setting, test with the Sharing Debugger.

In WordPress, the tags usually come from your SEO plugin. Some themes print their own too. Pick one source, set a default share image for the site, and set a specific image on every post you expect people to share. Then view the page source and search for og:title: if it appears twice, you've found cause 4.

If you'd like to see your own cards before touching any code, my free social link preview checker shows the Facebook, LinkedIn, X and WhatsApp cards side by side.

How to check your Open Graph tags

Check the page logged out, read the source, then let each app read it fresh. About five minutes:

  1. Open the page in a private window, not logged in. Admin previews can show different tags.

  2. View the source and search for "og:" (Ctrl+U, or Cmd+Option+U on a Mac). There should be one og:title. og:image and og:url should be full https:// addresses that don't redirect, and the image's real size should match og:image:width and og:image:height.

  3. Run the page through Facebook's Sharing Debugger and LinkedIn's Post Inspector. They show what their crawler sees today and refresh their saved copy.

  4. For X and WhatsApp, share it to yourself in a private chat or a draft post. If you see an old card, share it with ?v=2 on the end.

What's easy to get wrong

Five mistakes, in the order they usually bite.

  • Testing while logged in. You see the admin's version, not the visitor's, and not the crawler's.

  • Two addresses for one site. www and non-www, or http and https, mixed across canonical, og:url and share buttons.

  • Typing the image size by hand. If your code says 1200 × 630 for every post, it will be wrong the first time someone uploads a different size. Read the real size, or let Next.js make the image.

  • One image for every page. It passes every checker, X's own docs warn against it, and every share looks the same.

  • Alt text that repeats the title. Describe what's in the picture.

The tags are the easy part. The image (its own address, its real size, made for that page) and the one correct page address are where link previews go wrong.

If you'd rather have someone do this

I've been building Next.js and WordPress sites since 2017, more than 900 of them with my team in Kolkata. If your shared links all show the same picture, or the wrong one, we can set up one correct address, a share image for every page that matters, and refresh the old previews. Book a short call.

Questions

Questions this post answers

What size should an Open Graph image be?

1200 × 630 pixels as a JPG works almost everywhere. Facebook says to use images at least 1200 × 630 for the best display, LinkedIn's minimum is 1200 × 627 with a recommended 1.91:1 shape, and X uses a 2:1 shape. Keep the file under 5 MB, ideally a few hundred KB, and keep text in the middle so small crops don't cut it.

How do I clear the old link preview?

Facebook: paste the address into the Sharing Debugger and click "Scrape Again". LinkedIn: use Post Inspector (it only changes new posts, not old ones). X and WhatsApp have no public refresh tool, so share the link with something like ?v=2 on the end. If you changed the image itself, give the new file a new name first.

Why does my link preview show no image?

Usually one of five things: the og:image address isn't a full https:// address; the address redirects; a firewall, bot protection or robots.txt blocks the crawler; the file is too big or is an SVG; or the app saved the page before the image existed. Fix the cause, then refresh the app's saved copy.

Do I need Twitter card tags as well as Open Graph tags?

Mostly no. X reads your og: title, description and image when its own twitter: tags are missing. But add twitter:card set to summary_large_image if you want the large image card. Add separate twitter: tags only if you want different wording on X.

Can I use a WebP image for og:image?

X's docs list WEBP as supported, but not every app documents WebP support, and WhatsApp documents nothing at all. A JPG is the safer choice: every app in this post accepts it, and a well-compressed JPG is small enough anyway.

Should every page have its own share image?

The pages people actually share should. X's docs warn against generic images like a logo or author photo used on many pages, and identical images make every share look the same. In Next.js, opengraph-image.tsx can make one for every post automatically.

Share:X·LinkedIn·Email

Related

  • SEO for Developers

    Alternate page with proper canonical tag: when to fix it

    Search Console told me three of my pages were fine as "alternate" copies, yet all three were the exact pages my visitors land on. So "Alternate page with proper canonical tag" isn't always good news, and the two "Duplicate" rows…

    · 14 min read · by Sandipan Das
  • SEO for Developers

    How to check if a page is indexed by Google (3 ways)

    How do you check if a page is indexed by Google? Paste the page's full address into URL Inspection in Google Search Console. It will say "URL is on Google" or "URL is not on Google", with the reason. To…

    · 6 min read · by Sandipan Das
  • SEO for Developers

    Page with redirect in Search Console: fix it or ignore it?

    Search Console says 49 of my URLs are "not indexed" because of a redirect. When I checked the pages those redirects lead to, all 7 I tested were already on Google. So "Page with redirect" is often nothing to fix.…

    · 13 min read · by Sandipan Das

If you'd rather not do it yourself

Everything above works. You just need the time for it.

Follow the steps and fix it yourself. Or send the site to the team and get on with your day.

900+ projects completed since 2017, from Kolkata, India.