GuideTechnical SEO
OG image not showing: fix WhatsApp, Slack, LinkedIn and X previews
Most missing OG images are fetch failures: a relative URL, a blocked crawler, a login wall or tags added by JavaScript. Check each, then clear the cache.

An OG image that does not show is usually a fetch problem, not a tag typo: the platform's crawler could not load the page or the image. Check, in order, that og:image is an absolute https:// URL, that the image returns 200 with an image content type and no login, that your firewall lets the crawler through, that the tags are in the raw HTML rather than added by JavaScript, and then clear the platform's cached preview.
Each platform sends its own crawler, and each caches what it fetched. That is why a preview can work on Slack and fail on LinkedIn, or keep showing an old image after you fixed it. Test the way the crawler fetches, not the way your browser does.
Why is my OG image not showing?
A browser test hides most of these causes, because your browser is logged in, runs JavaScript and is never blocked by your own firewall. The table lists each cause with the check that exposes it.
| Cause | How to check | Fix |
|---|---|---|
og:image is a relative path | View source: content="/og.png" | Use the full https:// URL |
| Image returns 404, 403 or a redirect to HTML | curl -sI the image URL | Serve the file at a stable URL with a 200 |
| Wrong or missing content type | curl -sI shows text/html or nothing | Serve image/png or image/jpeg |
| Login, cookie wall or deployment protection | Open the page and image in a private window | Test on the public production URL |
| Firewall or bot protection blocks the crawler | curl with the crawler's user agent | Allow the preview crawlers |
| Tags added by JavaScript | curl the page and grep for og:image | Render the tags on the server |
| Image too large or too small | Check file size and dimensions | Stay under 5 MB and use 1200 x 630 px |
| Platform cache | The page is fixed but the preview is old | Re-scrape with the platform's tool |
Is og:image an absolute https URL?
It must be. Facebook's link sharing FAQ answers the relative-URL question directly: "All URLs must be absolute as they represent the canonical location of a resource." The Next.js metadata docs annotate every Open Graph image with "Must be an absolute URL". A crawler reads the tag's value and fetches it as written, with no page to resolve a relative path against.
A complete image block, using the optional properties the Open Graph protocol defines:
<meta property="og:title" content="Invoicing software for freelancers">
<meta property="og:type" content="website">
<meta property="og:url" content="https://www.example.com/">
<meta property="og:image" content="https://www.example.com/og/home-1200x630.png">
<meta property="og:image:type" content="image/png">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:image:alt" content="Acme invoice editor with a paid invoice">
The protocol lists og:title, og:type, og:image and og:url as the four required properties for every page. Declaring og:image:width and og:image:height helps too: Facebook says the tags let its crawler "render the image immediately without having to asynchronously download and process it," which avoids a blank first share. The right dimensions for each platform are in OG image size.
In Next.js, relative image paths only work when metadataBase is set, and a relative path without it is a build error. The framework-specific causes are in Next.js Open Graph image not working.
Does the image URL return 200 with an image content type?
Fetch the image URL itself and read the response headers. You want a 200 status and a content-type that starts with image/. A 404, a 403, a redirect to a login page, or a text/html content type means the crawler got something that is not an image, and the preview shows nothing or a blank box.
curl -sI https://www.example.com/og/home-1200x630.png
# expect:
# HTTP/2 200
# content-type: image/png
Keep the file within every platform's limits at once:
| Platform | Stated image limits |
|---|---|
| Facebook and Meta apps | Minimum 200 x 200 px, maximum 8 MB; at least 1200 x 630 px recommended |
| X | Under 5 MB; JPG, PNG, WEBP and GIF supported; SVG not supported |
| Minimum 1200 x 627 px, maximum 5 MB, 1.91:1 recommended |
A 1200 x 630 PNG or JPEG under 5 MB satisfies all three. If you replace an image, give the new one a new URL. Facebook says it caches "all images referenced based on each image's URL," so an overwritten file at the same URL keeps showing the old picture, and it asks you not to delete old images because existing posts still reference them.
Can each platform's crawler reach the page and the image?
Link previews come from crawlers, not browsers, and each identifies itself with its own user agent. If a firewall, bot-protection rule, login wall or deployment protection answers that crawler with a challenge or a 401, the preview fails even though the page loads fine for you.
| Platform | User agent contains | robots.txt behaviour, per its own docs |
|---|---|---|
| Facebook, Instagram, Messenger | facebookexternalhit/1.1 | Honoured, but may be bypassed for security or integrity checks |
| X | Twitterbot | Implements Google's robots.txt specification |
LinkedInBot | Not documented on the pages read | |
| Slack | Slackbot-LinkExpanding 1.0 | Not honoured: Slack says it does not currently honor robots.txt |
WhatsApp | Not documented |
The user agent strings for LinkedIn and WhatsApp come from the list of link-preview bots in the Next.js source code; neither company documents its crawler on the pages read for this article.
Simulate the crawler with curl. Meta publishes an exact command for its crawler:
curl -v --compressed -H "Range: bytes=0-524288" -H "Connection: close" \
-A "facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php)" \
"https://www.example.com/"
Repeat with -A "Twitterbot/1.0", -A "LinkedInBot/1.0" and -A "Slackbot-LinkExpanding 1.0 (+https://api.slack.com/robots)", and then fetch the image URL the same way. A 403, a 503 with a challenge page, or a redirect to a login screen points at the blocker. Meta recommends adding "either the user agent strings or the IP addresses (more secure) used by the crawler" to your allow list.
Two blockers catch teams out:
- Deployment protection blocks crawlers. On Vercel, Standard Protection "protects all domains except production domains," and protected URLs send visitors to a Vercel login. A crawler has no login, so previews of preview deployments fail. Test on the production domain.
- Cookie walls and geo redirects replace your page. A consent page or a country redirect served to the crawler replaces your tags with the interstitial's tags. The crawler must get the real page on its first request.
Are the Open Graph tags in the raw HTML?
They have to be. Preview crawlers read the HTML the server sends, and some read only the start of it. The Next.js docs describe facebookexternalhit as an HTML-limited bot that "can't execute JavaScript," Slack's crawler "fetches as little of the page as it can (using HTTP Range headers) to extract meta tags," and Meta says Open Graph properties must appear "before the first 1 MB" of the page.
Check the served HTML:
curl -s https://www.example.com/ | grep -io '<meta[^>]*og:image[^>]*>'
If nothing prints, the tags are added client-side, by a single-page app, a tag manager or a head library running after load. Render them on the server instead. Keep them near the top of the <head>, above large inline scripts or styles, so a crawler reading a limited byte range reaches them. X's archived troubleshooting notes its crawler also has a 2 MB limit on page responses.
Next.js handles this for you with one caveat: metadata from generateMetadata can be streamed into the <body> for browsers, but for HTML-limited bots Next.js keeps blocking so the tags land in the <head>. Its list of those bots includes facebookexternalhit, Twitterbot, LinkedInBot, Slackbot, Discordbot and WhatsApp. If you override htmlLimitedBots, keep those in it.
How do you clear a cached link preview?
Each platform caches the preview it fetched, so a fixed page can keep showing the broken one. Clear or wait out each cache separately, using the platform's own tool. The table gives the cache behaviour each platform documents and the way to refresh it.
| Platform | Cache, as documented | How to refresh |
|---|---|---|
| Facebook, Messenger | A standard 24-hour update period; images cached by URL | Enter the URL in the Sharing Debugger, which triggers a new scrape; refresh old posts with Refresh share attachment |
| Previously shared URLs show the cached image | Enter the URL in Post Inspector at linkedin.com/post-inspector; existing posts keep the old preview | |
| X | "Cached for up to 7 days before being refreshed" | Paste the link in the post composer to preview; add a query parameter to the image URL to force a new fetch |
| Slack | Cached "for around 30 minutes" | Wait for the cache to expire, then post the link again |
| Not documented | Test in a new chat |
Facebook adds a detail worth knowing: the first share of a URL may show no image, because "the crawler has to see an image at least once before it can be rendered." Running the URL through the Sharing Debugger before you post pre-caches it.
For platform-specific detail, see X card not showing an image, which covers the twitter:* tags and X's fallbacks to Open Graph, and LinkedIn link preview not working, which maps Post Inspector's output to fixes.
Check the page conditions previews depend on
A preview needs a public, fast, valid page before any platform can build it. Run the free scan on LaunchScaler with the page's URL, no account needed. It does not render your social card, but its checks cover conditions previews depend on: invalid markup that closes the <head> early and drops the tags below it, primary content that only appears after JavaScript runs, redirect chains, and an incomplete or expired TLS certificate chain. Fix those, confirm the tags with curl as above, then re-scrape the URL on each platform.
Questions, answered
What people ask about this
01Why is my OG image not showing?
- Usually the platform's crawler could not fetch it: the og:image URL is relative, the image needs a login or sits behind deployment protection, a firewall blocks the crawler, or the tags are added by JavaScript the crawler never runs. If all of that is fine, the platform is showing a cached preview.
02Does og:image need to be an absolute URL?
- Yes. Facebook's link sharing FAQ says all URLs must be absolute, and the Next.js docs mark every Open Graph image URL 'Must be an absolute URL'. Use the full https:// address of the image.
03Why is my OG image not showing on WhatsApp?
- WhatsApp does not publish its link preview rules. Apply the same checks as for other platforms: an absolute https og:image, an image that returns 200 without a login, a crawler that is not blocked by your firewall, and tags present in the raw HTML. Then paste the link into a chat to test.
04How do I refresh a cached OG image?
- Each platform has its own cache. Run the URL through Facebook's Sharing Debugger to re-scrape it, inspect it in LinkedIn's Post Inspector, and for X paste the link into the post composer; X says card data is cached for up to 7 days. Slack caches unfurls for around 30 minutes.
05Do link preview crawlers run JavaScript?
- Treat them as if they do not. The Next.js docs describe facebookexternalhit as an HTML-limited bot that can't execute JavaScript, and Slack's crawler fetches as little of the page as it can to read the meta tags. Put the Open Graph tags in the server-rendered HTML.
Sources
- The Open Graph protocologp.me
- Meta for Developers: Meta web crawlersdevelopers.facebook.com
- Meta for Developers: Images in link sharesdevelopers.facebook.com
- Meta for Developers: Link sharing FAQdevelopers.facebook.com
- X Developers: Card Validator preview removal (August 2022)web.archive.org
- X Developers: Troubleshooting cards (archived)web.archive.org
- LinkedIn Help: Make your website shareable on LinkedInlinkedin.com
- LinkedIn Help: Use Post Inspector to refresh URLlinkedin.com
- Slack: Slack robotsapi.slack.com
- Next.js docs: generateMetadata (openGraph, streaming metadata)nextjs.org
- Next.js source: HTML-limited bot user agentsgithub.com
- Vercel docs: Deployment Protectionvercel.com


