# OG image not showing? A checklist to fix your link preview

[Canonical HTML page](https://gradiently.design/guide/og-image-not-showing)

Your page looks right, the tag is there, and the preview is still blank or stuck on an old picture. Here is the order to check things in, and how to clear each platform's cache.

## The short version

- An OG image not showing is almost always one of five causes: a relative URL, a tag added by JavaScript, an image the crawler cannot fetch, a file that is too large, or a cached old preview.
- The og:image value must be a full https URL that appears in the HTML the server sends, because most link crawlers do not run JavaScript.
- The image itself must return a 200 status with an image content type, without a login, a redirect loop or a robots.txt rule blocking the crawler.
- Facebook allows OG images up to 8 MB and LinkedIn up to 5 MB, but a designed 1200×630 PNG should weigh far less, which also helps apps like WhatsApp that publish no limit.
- Platforms cache images by URL, so after changing an OG image give it a new filename, then refresh the preview in Facebook's Sharing Debugger or LinkedIn's Post Inspector.

**OG image not showing** on a shared link? The cause is nearly always one of five things: the `og:image` address is relative, the tag is added by JavaScript after the page loads, the crawler cannot fetch the image, the file breaks a platform's limits, or the platform is still showing a cached preview. Check them in that order. Each step below takes a minute and rules one cause out for good.

| Symptom | Likely cause | Fix |
| --- | --- | --- |
| No image anywhere | Relative URL or tag missing from server HTML | Full `https://` URL, rendered on the server |
| Image on some apps, not others | Crawler blocked, file too heavy, or wrong format | Allow the bots, compress, use PNG or JPEG |
| Small square thumbnail instead of a large card | Image too narrow, or no `twitter:card` | 1200×630 image and `summary_large_image` |
| Old image keeps appearing | Platform cache | New filename, then re-scrape in the inspector |
| Works locally, not in production | Base URL points at localhost or a preview domain | Set the production domain as the base URL |

Match what you see to the row, then jump to that step.

## Step 1: use an absolute https URL

A crawler reading your page has no idea where `/og.png` lives. It needs the whole address, protocol and domain included. Relative paths, protocol-relative paths (`//example.com/og.png`) and plain `http://` addresses are the most common reason a preview comes up blank.

```html
<!-- Broken: the crawler cannot resolve these -->
<meta property="og:image" content="/og/launch.png" />
<meta property="og:image" content="//example.com/og/launch.png" />

<!-- Working: full https URL, size and alt declared -->
<meta property="og:image" content="https://example.com/og/launch-v2.png" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:image:alt" content="Launch week, on a deep violet background" />
<meta name="twitter:card" content="summary_large_image" />
```

The tags that fix most blank previews. `twitter:card` uses `name`, the Open Graph tags use `property`.

Declaring the width and height matters on the first share: Facebook says that without them, a page may appear without its image until the crawler has fetched it once. [Open Graph tags](https://gradiently.design/guide/open-graph-tags) covers the rest of the set.

## Step 2: make sure og:image is in the server HTML

Your browser's inspector shows the page *after* JavaScript has run, so a tag can look perfect there and still be invisible to crawlers. Single page apps that set meta tags in the browser (with a client-side head manager, for example) are the classic case. Check what a crawler actually receives:

```bash
# The HTML a crawler receives: is og:image in it?
curl -s -A "facebookexternalhit/1.1" https://example.com/launch | grep -i 'og:image'

# The image itself: expect HTTP 200 and an image content type
curl -sI https://example.com/og/launch-v2.png | grep -iE '^HTTP|content-type|content-length'
```

Two checks from a terminal. If the first prints nothing, the tag is added in the browser and crawlers never see it.

In Next.js with the App Router, set the tags in `metadata` so they are rendered on the server. Put `metadataBase` in the root layout so relative image paths become full URLs, and point it at your production domain, not `localhost` or a preview deployment.

```ts
// app/layout.tsx
import type { Metadata } from 'next'

export const metadata: Metadata = {
  metadataBase: new URL('https://example.com'),
  openGraph: {
    images: [{ url: '/og/launch-v2.png', width: 1200, height: 630, alt: 'Launch week' }],
  },
  twitter: {
    card: 'summary_large_image',
  },
}
```

`/og/launch-v2.png` resolves to `https://example.com/og/launch-v2.png` in the rendered `head`. Next.js also reads an `opengraph-image.png` file placed in a route folder.

## Step 3: check the image is reachable by crawlers

The page loading is not enough: the crawler then makes a second request for the image, and that request can fail on its own. Open the image URL in a private window, then work through this list.

1. **No login, no cookie wall** The image must load for a stranger. Images behind auth, a staging password or a consent screen come back as an HTML page, not a picture.
2. **Status 200, no redirect chains** A 404, a 403 from a firewall or bot protection, or a redirect to a login page all end in a blank preview. One clean redirect is usually fine; several are not.
3. **robots.txt allows the bots** X's crawler identifies as `Twitterbot` and follows robots.txt, and LinkedIn names a blocked crawler as a common cause. A blanket `Disallow` on `/images/` or `/_next/` can block the preview.
4. **A real image content type** The server should send `Content-Type: image/png` or `image/jpeg`. A file served as `text/html` or `application/octet-stream` is often ignored. See [Content-Type on MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type).
5. **PNG or JPEG, not SVG** Crawlers broadly do not render SVG previews. Use PNG for designed cards and JPEG for photos; [PNG vs JPEG](https://gradiently.design/guide/png-vs-jpeg) explains the trade.

## Step 4: stay inside size and file weight limits

An image that is too small gets demoted to a thumbnail, and one that is too heavy may not be fetched at all. These are the limits the platforms publish themselves. Where a platform publishes no number, keep the file light and test.

| Platform | Published guidance |
| --- | --- |
| Facebook | At least 200×200, 1200×630 recommended, at most 8 MB |
| LinkedIn | At least 1200×627, 1.91:1, at most 5 MB; under 401 px wide shows as a thumbnail |
| X | The crawler typically downloads images up to 5 MB; use `summary_large_image` for the large card |
| WhatsApp, Slack, Discord, iMessage | No published limits: a lean PNG or JPEG is the safe choice |

Taken from each platform's own documentation. Numbers change, so treat them as ceilings, not targets.

A designed 1200×630 card with flat colour and type rarely needs to be large. Compressing it helps the apps without published limits, where heavy images are a common reason a preview quietly fails. [Image compression](https://gradiently.design/guide/image-compression) shows how to cut weight without banding.

- Link preview 1200×630: 1200 × 630
- LinkedIn link image 1200×627: 1200 × 627
- Too narrow: 400×210: 400 × 210

The standard preview, LinkedIn's near-identical size, and an image narrow enough to be shown as a small thumbnail.

## Step 5: clear each platform's cache

If the old picture keeps showing, the platform cached it. Facebook says it caches images by URL, so the same address will keep serving the old image even after you replace the file. The reliable fix everywhere is a **new filename** for the new image, then a refresh where the platform offers one.

| Platform | How to refresh |
| --- | --- |
| Facebook, Messenger | Sharing Debugger, then Scrape Again |
| LinkedIn | [Post Inspector](https://www.linkedin.com/post-inspector/): inspect the URL to fetch it fresh |
| X | No preview tool: change the image URL and draft a new post to check |
| WhatsApp | No tool: change the image URL, then send the link in a new chat |
| Slack, Discord | No tool: a new image URL, or a query string on the page link, triggers a fresh fetch |
| iMessage | Previews are built on the sender's device: send the link again after the image URL changes |

Refreshing only affects new shares. Posts already published keep the preview they were made with.

### Avoid

- Overwriting `og.png` with a new design
- Waiting for caches to expire
- Deleting the old image straight away

### Do

- Uploading `og-v2.png` or a hashed filename
- Re-scraping in the Sharing Debugger and Post Inspector
- Keeping the old file live for posts that still point to it

Hashed filenames from your build tool or a version suffix (`launch-v2.png`) do this automatically. A query string such as `?v=2` on the image URL also works for most crawlers, but a new path is the safer bet.

## A preview worth fixing

Once the plumbing works, the image still has to earn the click at thumbnail size: a short line, large type and the key words in the centre, where square crops keep them. [OG image size](https://gradiently.design/guide/open-graph-image-size) covers the layout, and [link preview image](https://gradiently.design/guide/link-preview-image) the design side. If you make a fresh image per post, [dynamic OG images](https://gradiently.design/guide/dynamic-og-images) generates them from the title.

A 1200 by 630 link preview reading Launch week on a gradient background

A 1200×630 preview that survives every crop: one short line in the centre and a small site name above it.

In Gradiently, **Link preview (Open Graph) 1200×630** is a built-in size and exports as PNG, so the file arrives at the right dimensions. Export each new version under a new filename and the cache problem never starts. The same steps apply to a repository card; see [GitHub social preview](https://gradiently.design/guide/github-social-preview).

## FAQ

### Why is my OG image not showing on LinkedIn?

Most often the image is under 1200×627, over 5 MB, behind a login, or blocked from LinkedIn's crawler. Fix the file, then inspect the URL in LinkedIn Post Inspector to fetch it again.

### Why does Facebook show my old OG image?

Facebook caches images by URL. Upload the new image under a new filename, update og:image, then click Scrape Again in the Sharing Debugger.

### Why is my Twitter card image not showing on X?

Check that og:image or twitter:image is a full https URL in the server HTML, that robots.txt does not block Twitterbot, and that twitter:card is set to summary_large_image for the large card.

### Does og:image work if it is added with JavaScript?

Usually not. Most link crawlers read the HTML the server sends and do not run scripts, so set the tags on the server.

### What format should an OG image be?

PNG for designed cards with type and flat colour, JPEG for photos, at 1200×630. Avoid SVG, which crawlers broadly do not render as a preview.
