guides

Facebook link preview not updating — the 11 causes (and how to diagnose each)

the linkboo team·20 min read·updated Mon Jun 01 2026 17:00:00 GMT-0700 (Pacific Daylight Time)
On this page

what this guide does

You shared a link to Facebook and the preview is wrong. The old title is still showing. The image is from last year's version of the page. Or there's no preview at all and Facebook composed something generic from your URL slug. You updated the metadata on your site. Facebook didn't notice.

This is one of eleven distinct problems, not one. The fix depends on which one you've hit. Read the diagnostic flowchart below, identify your symptom, jump to the matching cause section.

For a click-by-click walkthrough of the Sharing Debugger UI — the tool that resolves about 70% of these cases — see the Sharing Debugger UI walkthrough. This guide treats the Debugger as a verification tool; the sibling is the UI reference.

When a Facebook link is shared for the first time — in a post, in Messenger, in an Instagram DM, on WhatsApp — Meta's crawler hits the URL and parses metadata. The crawler identifies itself as facebookexternalhit/1.1 (mobile traffic uses facebookexternalhit/1.1 (iPhone) or the equivalent Android string), and it follows specific rules documented in Facebook's official crawler reference — rules that almost no SEO article in the field cites directly.

The crawler reads Open Graph meta tags from the first 1MB of HTML, specifically: og:title, og:description, og:image, og:url, and og:type. It expects gzip or deflate encoding. It sends Range: headers and expects the origin to either honor them or ignore them gracefully. It usually respects robots.txt but reserves the right to bypass for security and integrity checks. The result of one successful parse is cached for approximately 30 days.

That cache is one cache, shared across all of Meta's preview surfaces. The same cached object serves the preview in Facebook feed, Messenger, Instagram DMs, and WhatsApp. This is the single most under-leveraged fact in the SERP: when you fix the cache once via the Sharing Debugger, you've fixed it for all four surfaces simultaneously.

                  ┌──────────────────────────────┐
   Your page  ──► │  Meta's OG preview cache     │ ──► Facebook feed
                  │  (~30-day TTL per URL)       │ ──► Messenger threads
                  │                              │ ──► Instagram DMs
                  └──────────────────────────────┘ ──► WhatsApp chats

The cache will not refresh on its own when you update the page. You have to force it — or work around one of the eleven failure modes below that prevent the refresh from taking effect.

diagnose first — match your symptom to the cause

Skim this flowchart, identify the line that matches what you're seeing, jump to the cause section.

What are you seeing?
 ├─ Old title/image shows; page itself is updated and correct
 │   → Cause 1 (cache hasn't refreshed)
 │
 ├─ No preview at all; Facebook generated something generic from the URL
 │   → Cause 2 (missing/malformed OG tags) or Cause 3 (crawler blocked)
 │
 ├─ Wrong image appears (not the one in your og:image tag)
 │   → Cause 4 (image spec violation), Cause 5 (duplicate tags), or Cause 6 (CDN cache)
 │
 ├─ Debugger shows the right preview; shared post shows the wrong one
 │   → Cause 6 (CDN edge cache) or Cause 10 (mobile/in-app cache)
 │
 ├─ "We can't review this website because the content doesn't meet our Community Standards"
 │   → Cause 7 (domain classifier flag)
 │
 ├─ Title is locked and won't update no matter what you do
 │   → Cause 8 (50-share title lock)
 │
 ├─ Scrape Again button does nothing — same cached preview keeps appearing
 │   → Cause 9 (Debugger backend / fbrefresh workaround)
 │
 ├─ Preview works on Facebook desktop web; breaks in the app or in-app browsers
 │   → Cause 10 (per-surface app cache divergence)
 │
 └─ Worked once, then suddenly stopped working with no metadata change
     → Cause 11 (CDN regression, JS-injected tags, SSR failure)

Every cause section below has the same shape: one-line symptom, why it happens, the exact fix.

cause 1 — Facebook's preview cache hasn't refreshed

Symptom. You updated your page. The preview still shows the old version.

Why it happens. Meta caches the parsed OG data for ~30 days per URL. The cache does not auto-invalidate when your page changes. Until you force a refresh, every new share continues to draw from the stale cached object.

The fix. Run the URL through the Sharing Debugger and click Scrape Again. The first click invalidates the cache. The second click (after a short wait) returns the freshly-parsed preview, which Facebook then uses for all subsequent shares. The click-by-click Debugger guide covers the exact button positions, the Show Existing Scrape Information toggle, and the meaning of each "warnings" message.

The workaround when Scrape Again silently fails. Append ?fbrefresh=ANYTHING_RANDOM to the URL and submit that to the Debugger. Facebook treats it as a new URL, fetches fresh OG data, and the side effect tends to refresh the canonical URL's cached entry too. This trick has worked since at least 2019; it still works as of 2026.

Why this fix propagates everywhere. A successful Scrape Again invalidates Meta's shared cache. The next time anyone shares the URL — to Messenger, Instagram DM, WhatsApp, or back to Facebook — the preview is regenerated from your current page. One action, four surfaces fixed.

When this fix won't work. If the preview is wrong for reasons other than stale cache — missing OG tags, blocked crawler, image-spec violation, CDN serving the wrong HTML, dynamic content — Scrape Again will faithfully re-fetch the same broken state. Work down the cause list below.

cause 2 — your Open Graph tags are missing or malformed

Symptom. No preview. Facebook composes a generic card from the page <title> and an arbitrary image, or shows just the URL.

Why it happens. Facebook needs five tags inside <head>: og:title, og:description, og:image, og:url, og:type. Missing tags trigger clumsy fallbacks; malformed tags get skipped.

<meta property="og:title"       content="Your title — under 90 chars renders cleanly" />
<meta property="og:description" content="One or two sentences, under 200 chars." />
<meta property="og:image"       content="https://yoursite.com/og/page.jpg" />
<meta property="og:url"         content="https://yoursite.com/page" />
<meta property="og:type"        content="article" />

Common malformations.

  • Tag placed outside <head> — the parser stops at </head>.
  • name= instead of property=. Facebook reads property; Twitter reads name. Mixing them up is the most common mistake.
  • Missing content= attribute, or content="".
  • og:url set to a relative path. Must be absolute.
  • Duplicate tags from competing sources (covered in cause 5).

Verify. View Source (not Inspect Element — DevTools shows the post-JavaScript DOM, not what the crawler sees). Search og:. Each of the five properties should appear exactly once.

The 1MB head-parsing limit. Per Facebook's crawler documentation, the crawler parses only the first 1MB of HTML. OG tags placed late in <head> after large inline CSS, JSON-LD, or inlined JavaScript can fall outside the parsed region and be treated as missing. (Earlier guidance cited 60KB; the current official cutoff is 1MB. Some legacy articles still quote the old number — both have been real cutoffs depending on era.) Place OG tags as early in <head> as possible, before large inline assets.

WordPress note. Yoast, Rank Math, and All in One SEO each emit their own OG tags. If two are active, you ship duplicates. Pick one and disable OG output in the others.

cause 3 — Facebook's crawler can't reach your page

Symptom. The Debugger reports a fetch error — 403, 404, 5xx, timeout, or "URL returned a bad HTTP response code."

Why it happens. Something between the public internet and your origin is refusing the crawler's request. Five common variants.

1. robots.txt blocks facebookexternalhit. Add an explicit allow:

User-agent: facebookexternalhit
Disallow:

User-agent: Facebot
Disallow:

Facebook's docs note the crawler may bypass robots.txt for security and integrity checks, but defaults to respecting it.

2. Firewall or WAF blocks Meta. Cloudflare's Bot Fight Mode, Sucuri, AWS WAF sometimes classify facebookexternalhit as bad-bot traffic. Whitelist the UA string. Meta does not publish a stable IP allowlist; UA-based allowlisting is the practical approach.

3. HTTP basic auth, IP allowlist, or paywall. The crawler can't authenticate. Move the page to a public URL or stage a public preview version specifically for the Debugger pass.

4. Slow first-byte, no gzip. Facebook's docs require gzip/deflate. Uncompressed HTML or first-byte time over ~10 seconds breaks the scrape. Enable gzip at the CDN or origin.

5. Range-request misbehavior. The crawler sends Range: headers. Misconfigured CDNs return 416 Range Not Satisfiable instead of honoring the range or returning 200. Test with curl: Range: bytes=0-500 should return 206 or 200, never 416.

cause 4 — your og:image violates Facebook's spec

Symptom. No image, a generic placeholder, or a downscaled image that looks blurry in feed.

Why it happens. Facebook has strict image rules. Quiet violations cause silent fallback.

Constraint Spec On violation
Recommended dimensions 1200 × 630 (1.91:1) Cropped or scaled, visibly degraded
Absolute minimum 200 × 200 Image ignored; fallback shown
Aspect ratio 1.91:1 ideal 3:2 and 4:3 render smaller
File size < 8MB recommended, < 300KB ideal Slow scrape times out
Format JPG or PNG; GIF for static WebP fails silently as of 2026
URL Absolute HTTPS Relative or HTTP-only frequently fail
Access Public, no auth, no Vary-by-cookie 401/403 on crawler IP breaks scrape

The WebP gotcha. The most under-known issue in the SERP. Modern build pipelines default to WebP — Next.js next/image, Astro <Image />, the Cloudinary URL grammar. WebP is excellent for in-page imagery and supported in every modern browser. Facebook's preview pipeline does not render it reliably. For og:image specifically, override to JPG or PNG.

// app/blog/[slug]/page.tsx — Next.js
export async function generateMetadata({ params }) {
  return {
    openGraph: {
      images: [{
        url: 'https://yoursite.com/og/post-cover.jpg',  // static JPG, not /_next/image WebP
        width: 1200, height: 630, alt: 'Post cover',
      }],
    },
  };
}

Per Facebook's sharing best practices, serve the image at a stable, versioned path (/og/post-cover-v2.jpg, not /og/post-cover.jpg?t=12345) so CDN caching of the image itself doesn't fight your preview-cache refresh strategy.

cause 5 — duplicate or conflicting Open Graph tags

Symptom. The Debugger picks "a" preview, but not the one you intended. Title or image appears chosen at random across shares.

Why it happens. Facebook's behavior with duplicates is inconsistent — sometimes the first wins, sometimes the last, sometimes the page is treated as ambiguous and falls back. Duplicates come from three places.

  1. Competing WordPress plugins — Yoast + Jetpack + theme-level OG output frequently produces three og:title tags. Disable OG output in two of the three.
  2. Headless CMS rendering at two layers — Next.js with both layout-level and page-level <Head>, or Astro with both layout <head> and page <head> injection. Audit the head-merging path.
  3. Server template + client hydration both emitting tags — server HTML and next/head / vue-meta both write OG tags, you ship two copies.

Verify. View Source, Cmd-F for og:title. Count should be exactly 1 per property.

Resolve. Pick one source-of-truth layer — usually the framework's metadata API (Next.js generateMetadata, Astro layout slot, Nuxt useHead). Disable OG output everywhere else.

cause 6 — your CDN is serving stale HTML to Facebook

Symptom. You updated the OG tags on your origin. The Debugger shows the old tags. View Source on your origin URL shows the new tags. The CDN edge is the discrepancy.

Why it happens. Cloudflare, Fastly, BunnyCDN, AWS CloudFront, and Vercel's edge network all cache HTML under some configurations. Facebook's crawler hits the edge and gets stale HTML.

The fix. Purge the URL from your CDN cache, then Scrape Again. Order matters: if you Scrape Again before purging, Facebook re-caches the stale version for another 30 days.

Cloudflare. "Cache Everything" page rules are the most common offender. Even without them, Cloudflare caches HTML when your origin sends Cache-Control: public. See Cloudflare's cache-purging docs for the API call.

The og:image sub-failure. If the image URL itself is CDN-cached, updating the image at the same URL doesn't help — the edge serves the old bytes. Versioned image URLs (/og/cover-v2.jpg) bypass this. Treat every new og:image as a new URL.

cause 7 — Facebook flagged your domain as low-quality or unsafe

Symptom. The Debugger shows "We can't review this website because the content doesn't meet our Community Standards." Or your shares are silently suppressed in feed.

Why it happens. Meta runs a classifier across linked domains. Triggers include aggressive redirect chains, spam-report history, association with malware or banned accounts, or false-positives — no public trigger list. This is the same machinery behind the Instagram-side classifier with the same root.

The fix is procedural.

  1. Appeal through Facebook Business Support. Cite the URL, request manual review. Turnaround 5–14 days.
  2. Audit the actual triggers. Remove redirect chains. Check public blocklists (Google Safe Browsing, Sucuri).
  3. If your domain has a history of domain-level blocks on Instagram, the issue is cross-Meta — fixing it on the Instagram side often fixes Facebook.

Faster workaround. Route traffic through a clean custom domain with no shared blocklist history while the appeal is in flight.

Symptom. Image and description update via Scrape Again. Title refuses to change.

Why it happens. Meta's anti-misinformation rule: once a URL accumulates approximately 50 combined shares, likes, or comments, the title is frozen. Image and description remain editable; the title does not. The threshold has been historically fuzzy and Meta does not publish a strict number, but ~50 is the consistently-observed cutoff. Spammers used to bait engagement on a benign-titled link, then edit the title to misrepresent the content. Facebook removed manual title editing from the composer years ago for the same reason.

The fix is "you waited too long." Not fixable on the original URL. Two real options:

  1. Republish at a new URL and 301-redirect the old. Fresh title-edit window. Costs accumulated shares.
  2. Update only the image and description. Accept the title is permanent. Sometimes acceptable for evergreen content.

The cost of a new URL — losing accumulated social proof — is real. Whether it's worth paying depends on how visible the wrong title is.

cause 9 — Scrape Again doesn't do anything

Symptom. Click Scrape Again. Same cached preview. Click again. Same preview.

Why it happens. Meta's Debugger backend has transient issues. Or the URL is stuck in a cache state the standard refresh path doesn't break. Or you're hitting a rate limit on rapid calls. The Debugger doesn't say which.

Workaround 1 — the ?fbrefresh= trick. Append ?fbrefresh= plus any random string and submit that URL. Facebook treats it as a new URL, fetches fresh, and the canonical URL's cached entry tends to refresh as a side effect.

https://yoursite.com/post          ← refuses to refresh
https://yoursite.com/post?fbrefresh=20260519a   ← forces fresh parse

Workaround 2 — switch www / non-www. Facebook treats https://yoursite.com/page and https://www.yoursite.com/page as distinct URLs. Scraping the variant you don't normally share can shake loose the canonical. Make sure your og:url is set correctly so the canonical wins regardless.

Workaround 3 — use the Sharing API. Call the Graph API directly:

curl -X POST "https://graph.facebook.com/v18.0/" \
  -d "id=https://yoursite.com/post" -d "scrape=true" -d "access_token=YOUR_TOKEN"

This bypasses the Debugger UI entirely.

Workaround 4 — wait 30 minutes. If all three above fail in the same session, it's plausibly Meta. Retry. If the retry succeeds without changes, it was a backend incident.

cause 10 — preview works on desktop but breaks on mobile or in-app browsers

Symptom. Sharing Debugger shows the right preview. Facebook desktop web shows the right preview. But when a friend opens the post in the Facebook mobile app, or when the link appears as a shared preview inside Instagram's in-app browser specifically or TikTok's in-app browser, the old preview shows.

Why it happens. Mobile app and in-app browser preview-rendering paths cache at multiple layers — in-process, app-data persistence, mobile network edge — separate from the central OG cache the Debugger invalidates. Scrape Again clears the central cache; per-device local caches still hold the old version until they age out.

The fix is per-surface.

  • Facebook / Instagram / WhatsApp app: force-quit and reopen. iOS: swipe up, remove from app switcher. Android: Recent Apps + swipe away. Reopen, re-share to a test conversation.
  • In-app browsers (TikTok, Instagram): caches age out on a ~24-hour edge TTL. Force-quit the app and wait at least a few hours before re-testing.
  • Last resort on iOS: delete and reinstall. Nukes all local caches.

Bridge to the linkboo thesis. This per-surface cache divergence is the same class of isolation that produces the in-app browser logged-out problem. Each in-app browser maintains its own cache state, sandboxed from the system browser and from sibling in-app browsers. The OG preview cache is one example; the cookie jar is another, more consequential one. How webview cookie isolation works covers the engineering view.

If your audience is sharing your Facebook links from inside TikTok's or Instagram's in-app browser, both problems compound. The preview can show stale, and the destination can log them out. The first is annoying. The second loses the conversion.

cause 11 — JavaScript-injected OG tags, dynamic content, SSR failures

Symptom. Your SPA shows the correct OG tags in Inspect Element, but the Debugger reports them as missing. Or the Debugger worked, then stopped after a deploy.

Why it happens. Facebook's crawler executes very limited JavaScript. Recent updates have added some support, but it's unreliable, undocumented, and not safe to depend on. OG tags injected by React, Vue, Svelte, or any client-side framework after hydration usually aren't seen. This is the dominant failure mode for SPAs built with Create React App, vanilla Vue, vanilla Svelte, and any client-side router that mutates <head> post-load.

Fixes ranked by effort.

  1. Server-side render. Next.js (generateMetadata), Nuxt, SvelteKit, Astro with SSR — emit OG tags in the initial HTML response before any JavaScript runs. The right long-term answer.
  2. Static-render at build time. Astro static, Next.js SSG, Eleventy. Works when content is known at build time. Requires a rebuild per content change.
  3. Prerender service. Prerender.io, Rendertron — detect crawler UAs and serve a pre-rendered snapshot to bots, the live SPA to humans. Useful when migrating off an SPA is non-trivial.
  4. Hardcode OG tags in the static index.html that ships before hydration. Works for evergreen pages with stable metadata; not for per-route dynamic metadata.

Headless CMS gotcha. When your CMS publishes new content, your build pipeline must rebuild the affected pages before Facebook re-scrapes. ISR in Next.js and Astro's equivalent handle this with revalidate hints. Pure SSG requires a redeploy webhook from CMS to build pipeline. Without that wire, content updates land but the crawler keeps seeing the old static build.

Detect the crawler by UA:

const isFacebookCrawler =
  /facebookexternalhit|facebot|meta-externalagent/i.test(req.headers['user-agent'] || '');

For the broader pattern set, see the UA-string detection patterns reference. If you're rebuilding a smart-link layer server-side, linkboo's link API and deployment docs cover the route — also relevant if you're evaluating smart-link alternatives after Firebase Dynamic Links sunset.

CSP and X-Frame-Options note. A Content-Security-Policy restricting img-src does not break Facebook's preview — Facebook fetches your og:image directly with its crawler, not via your page's CSP context. Permissions-Policy doesn't affect preview either. The only header that breaks preview is one that returns non-200 to the crawler's GET on the image URL. Verify the image URL is publicly accessible with no auth, no IP filter, no rate-limit interfering.

did the fix work — verify across Meta's surfaces

You ran Scrape Again. The Debugger shows the new preview. Confirm it propagated.

  1. Re-run the Sharing Debugger. Confirm og:title, og:description, and og:image match what you intended. The "Warnings That Should Be Fixed" section should be empty.
  2. Share to Messenger — send the URL to yourself.
  3. DM on Instagram — send the URL to yourself.
  4. WhatsApp — send to a saved-messages chat.

All four surfaces should show the new preview within a few minutes. If three work and one doesn't, you're hitting cause 10 — force-quit the stuck app.

For a deeper view of what Meta has cached, the Open Graph object echo endpoint shows the raw OG object representation Facebook stores. Useful when the Sharing Debugger UI is ambiguous about which field it's actually serving.

when to walk away from the original URL

Some causes don't reward effort. The honest answer is to migrate.

  • Cause 7 (classifier flag). Appeals often fail. A clean custom domain is usually faster than the appeal cycle.
  • Cause 8 (50-share title lock). Not fixable on the original URL. Republish at a new URL and 301 the old.
  • Cause 11 with no rebuild path. If your CMS doesn't trigger rebuilds and you can't add that wiring quickly, a new URL with correct tags ships faster than a rebuild pipeline.

Accumulated likes, shares, and comments stay attached to the original URL. Sometimes the new URL is worth it; sometimes the old URL's social proof outweighs the wrong title. Treat it as a tradeoff, not a default.

the in-app browser side of this problem

Even after you fix the preview cache, your viewers can hit a related but distinct problem: the destination behind the share doesn't behave.

When a viewer in TikTok's or Instagram's in-app browser taps a shared Facebook link, two cache layers are in play. The preview belongs to one isolated jar — that's causes 6 and 10. The destination session — whether the viewer is logged in to your storefront, has a saved payment method, has a stored cart — belongs to a different isolated jar. Fixing the preview doesn't fix the session.

This is the structural problem covered in linkboo's thesis on in-app browser cookie isolation. The preview can look perfect and the destination can still log the viewer out. If you want to see which in-app browser a given visitor lands in, test which in-app browser your viewers land in — the result is often surprising.

linkboo fixes the destination-side problem by bouncing the tap out of the in-app browser before the destination loads, so your audience hits your page in their system browser with their existing session intact. Start free on linkboo → — or see linkboo's plans.

frequently asked

How long does Facebook cache link previews? Approximately 30 days by default. The Sharing Debugger forces an immediate refresh; the new preview then becomes the cached version for the next ~30 days.

Does fixing the Facebook preview also fix WhatsApp and Instagram DMs? Yes. Meta runs one preview cache across all four surfaces — Facebook, Messenger, Instagram DMs, and WhatsApp. A single successful Scrape Again propagates everywhere within minutes.

Why isn't the Scrape Again button working? Try the ?fbrefresh=ANYTHING query-string trick — append a random string and submit the new URL to the Debugger. If that fails, switch between www and non-www variants. If both fail, wait 30 minutes — the Debugger backend has transient issues. The click-by-click Debugger guide walks through the exact button sequence.

Can I edit the title in the Facebook composer? No. Meta removed manual title editing years ago to prevent misinformation. The title must be set on your page in og:title, then refreshed via the Sharing Debugger.

Why does the preview work on web but not in the app? The mobile app and in-app browsers maintain separate cache layers from Facebook's central preview cache. Force-quit and reopen the app, or wait 24 hours for the local cache to age out naturally.

Does Facebook respect robots.txt? Generally yes. Per Facebook's own documentation, the crawler may bypass it for security and integrity checks, but the default behavior respects standard User-agent: facebookexternalhit directives.

Will Facebook see OG tags injected by JavaScript? Usually no. Facebook's crawler executes very limited JavaScript and the behavior is unreliable. Server-render the OG tags, static-render at build time, or use a prerender service that detects crawler UAs.

Is WebP supported for og:image? Not reliably as of 2026. Use JPG or PNG for og:image specifically, even if your in-page images are WebP. The engineering view on cookie jars covers the broader pattern of why in-app and platform-specific rendering pipelines diverge from system browser behavior.

Stop losing the click after the tap.

linkboo escapes the in-app browser so your real page loads — fast.

Start for free →