You added all the Open Graph tags. You deployed. You paste the URL into Slack or Twitter — and the preview is wrong, blank, or showing an old image from three months ago.
Here is a systematic guide to diagnosing and fixing broken link previews.
Step 1: Check if Your Tags Are Actually in the HTML
First, confirm the tags exist and are correct in the raw HTML. Do not trust your browser's "view source" — that shows the initial HTML, not what JavaScript may inject later.
Use curl to see exactly what a crawler receives:
curl -A "facebookexternalhit/1.1" -L "https://yoursite.com/page" | grep -i "og:"
The -A flag sets the User-Agent to Facebook's crawler. Some sites serve different HTML to bots, so this matters.
You should see output like:
<meta property="og:title" content="Your Title" />
<meta property="og:image" content="https://yoursite.com/image.png" />
If you see nothing, the tags are either missing or rendered by JavaScript (see below).
Step 2: The JavaScript Rendering Problem
Open Graph tags must be in the initial server-rendered HTML. Most social crawlers do not execute JavaScript.
If your site is a React SPA that injects meta tags via document.title or a library like react-helmet without server-side rendering, crawlers will never see your OG tags.
Symptoms:
- Tags look correct in browser DevTools
-
curlreturns no OG tags - Link previews are blank
Solutions:
- Enable SSR or static generation (Next.js, Nuxt, Astro, etc.)
- Use a prerendering service (Prerender.io, Rendertron)
- Set tags server-side before sending the HTML response
Quick test: compare curl output vs browser source:
# What crawlers see
curl -s "https://yoursite.com" | grep "og:image"
# If different from browser source, JS rendering is your problem
Step 3: Platform Cache Is Showing Old Data
This is the most common source of confusion. You fixed your tags but the preview still shows old content. That is because every platform caches OG data independently, often for days.
Force a cache refresh:
| Platform | How to Refresh |
|---|---|
| Sharing Debugger → Scrape Again | |
| Post Inspector → Inspect | |
| Twitter/X | Card Validator |
| Slack | Re-paste the URL; or use / command to unfurl |
| Discord | Append ?v=2 to the URL temporarily |
| Telegram | Bot Father has no manual refresh; usually updates within hours |
Key insight: even after you refresh Facebook's cache, users who already saw the old preview in a post will still see the old version. The cache refresh only affects new shares.
Step 4: Check Your Image URL
The og:image URL is the most common source of broken previews. Run through this checklist:
Is it absolute?
<!-- Wrong -->
<meta property="og:image" content="/images/og.png" />
<!-- Right -->
<meta property="og:image" content="https://yoursite.com/images/og.png" />
Is it HTTPS?
HTTP images often fail silently on HTTPS pages. Check:
curl -I "https://yoursite.com/images/og.png"
# Should return 200, not 301/403/404
Is it accessible without authentication?
Crawlers cannot log in. Images behind auth walls, VPN, or IP allowlists will fail.
Does it meet size requirements?
| Platform | Minimum | Recommended |
|---|---|---|
| 200×200px | 1200×630px | |
| 144×144px | 1200×675px | |
| 200×200px | 1200×627px |
Images below the minimum are silently ignored.
Is the Content-Type correct?
curl -sI "https://yoursite.com/og.png" | grep content-type
# Should be: content-type: image/png or image/jpeg
Some servers return application/octet-stream for images, which crawlers reject.
Step 5: Encoding and Special Characters
If your title or description contains special HTML characters, they must be properly escaped:
<!-- Wrong — will break the tag -->
<meta property="og:title" content="5 Tips & Tricks for <Developers>" />
<!-- Right -->
<meta property="og:title" content="5 Tips & Tricks for <Developers>" />
Also watch out for:
- Smart quotes (
"") — fine in content, but not as attribute delimiters - Newlines inside attribute values — break the tag
- Missing closing
/>— can invalidate subsequent tags
Step 6: Duplicate Tags
If you have a CMS, template engine, or third-party plugin, you may end up with duplicate OG tags. Most platforms use the first match, but some use the last, and behavior varies.
curl -s "https://yoursite.com" | grep -c "og:title"
# Should be 1, not 2 or 3
Common causes: WordPress Yoast + theme hardcoded tags, or a header partial included twice.
Step 7: The og:url Mismatch
If your og:url does not match the actual URL being shared, Facebook in particular will associate the metadata with the canonical URL, not the shared URL. This causes weird de-duplication where multiple different URLs show the same preview.
<!-- Make sure this exactly matches the canonical URL -->
<meta property="og:url" content="https://yoursite.com/exact-page-url" />
A Debugging Script
Here is a Node.js script that checks OG tags for any URL and reports common issues:
async function debugOG(url) {
const res = await fetch(url, {
headers: { 'User-Agent': 'facebookexternalhit/1.1' }
});
const html = await res.text();
const get = (prop) => {
const m = html.match(
new RegExp(`<meta[^>]+property=["']${prop}["'][^>]+content=["']([^"']+)["']`, 'i')
) || html.match(
new RegExp(`<meta[^>]+content=["']([^"']+)["'][^>]+property=["']${prop}["']`, 'i')
);
return m ? m[1] : null;
};
const title = get('og:title');
const description = get('og:description');
const image = get('og:image');
const ogUrl = get('og:url');
console.log('og:title:', title || '❌ MISSING');
console.log('og:description:', description || '⚠️ MISSING');
console.log('og:image:', image || '❌ MISSING');
console.log('og:url:', ogUrl || '⚠️ MISSING');
if (image) {
if (!image.startsWith('https://')) {
console.warn('⚠️ og:image is not HTTPS:', image);
}
if (image.startsWith('/')) {
console.error('❌ og:image is a relative URL:', image);
}
}
if (ogUrl && ogUrl !== url) {
console.warn('⚠️ og:url does not match requested URL');
}
}
debugOG('https://yoursite.com/page');
Tools That Do This For You
If you would rather not parse HTML yourself, there are APIs that handle the full extraction pipeline — including redirect following, charset detection, and relative URL resolution.
LinkPeek is a free option:
curl "https://linkpeek-api.linkpeek.workers.dev/v1/preview?url=https://yoursite.com/page&key=YOUR_KEY"
Returns:
{
"title": "Your Page Title",
"description": "Your description",
"image": "https://yoursite.com/og-image.png",
"favicon": "https://yoursite.com/favicon.ico"
}
Useful for sanity-checking what an external crawler actually sees from your page.
Summary Checklist
When a link preview looks wrong, work through this list in order:
- [ ] Tags exist in server-rendered HTML (not just JS-rendered)
- [ ]
og:imageis an absolute HTTPS URL - [ ] Image is accessible without auth and returns the right
Content-Type - [ ] Image meets minimum size requirements (1200×630px recommended)
- [ ] Special characters are HTML-encoded
- [ ] No duplicate
og:titleorog:imagetags - [ ]
og:urlmatches the canonical URL - [ ] Platform cache has been force-refreshed
Nine times out of ten, it is one of the first three items on this list.
Top comments (0)