The referral chain in Hengchun B&B businesses runs through LINE. A satisfied guest sends a link to their group chat — “這家不錯,看看。” A friend sees the preview card, clicks through, and asks about availability. OTA commissions are significantly higher than most operators realize, which is why every direct inquiry is worth protecting. I’ve been building direct-booking infrastructure for operators in this area — ads, landing pages, booking flows, tracking. Every piece of that system is wasted if the share itself doesn’t render.
The site I was debugging was a static Astro build deployed to Firebase Hosting. The og:image tag was in the HTML, the image loaded fine at its URL, the Content-Type header was correct, Cloudflare had been purged, and Facebook’s Sharing Debugger was showing the correct preview image. LINE was still showing a blank card.
The problem wasn’t any of the things I’d verified. There are six independent failure modes — seven if you count one that only surfaces under load — and they all produce the same output: blank card, no error, no diagnostic signal. The correct intervention is different for each. Running them in the wrong order means spending an hour re-confirming things that are already working.
The first tool you reach for shows you the wrong picture
The instinct is to open devtools and check the <head>. Don’t. What Chrome’s Elements panel shows you is what JavaScript rendered — not what LINE’s crawler received. LINE’s scraper doesn’t execute JavaScript. A client-side framework that injects og:image after hydration makes the tag invisible to the crawler even though it looks correct in the browser. This sends you in entirely the wrong direction, because the tag appears to be there.
The only reliable baseline is impersonating the scraper directly:
curl -A "facebookexternalhit/1.1" https://yoursite.com/some-page | grep og:image
If the tag isn’t in the output, stop. Fix the rendering layer first — SSR not outputting the tag server-side, a template bug, JavaScript injection running post-load instead of at render time. Everything downstream assumes the tag is already present in raw HTML.
Six failure modes, one blank card
Relative image URL. og:image requires an absolute URL. Scrapers have no base URL context — /images/og-cover.jpg resolves to nothing. Silent failure, no indication it happened, no error anywhere.
Image below 200×200. Facebook and LINE silently discard images below this size threshold without notifying you. If og:image points to an existing page thumbnail, the scraper fetches it and drops it. The practical target is 1200×630 — fills the preview card without letterboxing.
Wrong Content-Type. Run curl -I against the image URL and check the Content-Type header. application/octet-stream instead of image/jpeg or image/png causes some scrapers to ignore the file entirely. S3 buckets and CDNs without explicit MIME type configuration are the usual source.
Missing image dimension hints. When og:image:width, og:image:height, and og:image:type are absent, LINE’s crawler has to fetch and decode the image to determine its dimensions before it can validate and display it. Under time pressure — or when the CDN is slow — it times out and silently drops the image. Providing these three properties lets the crawler skip the fetch-and-decode step. This is distinct from the 200×200 minimum: your image can be the right size and still be dropped if the crawler can’t confirm that quickly enough.
Bot protection blocking the crawler. Cloudflare Under Attack mode, WAF rules, and rate limiting treat scrapers and attackers identically. Test with the scraper User-Agent explicitly:
curl -A "facebookexternalhit/1.1" https://yoursite.com/
If the response contains a Cloudflare challenge page, every preview card from that domain is blank until known scraper User-Agents are allowlisted in the firewall rules.
LINE’s 72-hour platform cache. This is what the three hours were actually about.
LINE maintains its own OG cache with a 72-hour TTL. It has no connection to your server, your CDN, or any cache you control. Purging Cloudflare does nothing. Redeploying does nothing. Facebook’s Sharing Debugger can show the correct image while LINE simultaneously shows blank — because LINE’s crawler hasn’t revisited the page since before you updated og:image, and it won’t until the TTL expires or you force a refresh.
The fix is the LINE Page Cache Refresh Tool in the developer console: paste the URL, trigger a forced recrawl, and the card updates within minutes.
Facebook’s Sharing Debugger is the diagnostic pivot
The Debugger shows what a scraper actually sees: parsed og: tags, detected image dimensions, image reachability, and specific error strings that never appear on the blank card itself. It’s the tool that separates client-side problems from platform-side caching problems. Run it after step 3, not before.
curlwith scraper UA — og: tags present in raw HTML output?- og:image value — absolute URL? Loads directly in a browser tab?
curl -Ithe image URL — Content-Type header, HTTP status- Facebook Sharing Debugger — parsed tags, dimensions, reachability, explicit errors
- Debugger shows correct image but LINE still blank → LINE Page Cache Refresh Tool
- Debugger can’t reach the page at all → bot protection allowlist
- Debugger shows the old image → CDN cache purge, then repeat step 4
Steps 1–4 take about ten minutes total. Steps 5–7 take about five minutes each. The three-hour session happened because step 7 came before step 4. Purging the CDN didn’t help, so I cycled back through steps 1–3 looking for something I’d missed, and only reached the Debugger after that second pass.
What got baked into production
The debugging session produced the SEO component that now ships across every Astro site I maintain for this group of clients. Every page emits og:image:width, og:image:height, and og:image:type alongside the image URL. All image paths run through an absolutize function at build time: absolute URLs pass through unchanged, root-relative paths are prefixed with the site domain. Neither the template author nor a future content editor has to think about this — the component enforces it.
The LINE cache problem has no automated solution. It requires a manual trigger each time a page is first shared and again after any OG image change. That’s a workflow constraint the operator needs to know about before launch, not a week into wondering why share previews aren’t working.
For an operator whose primary acquisition channel runs through LINE group chats, a blank preview card doesn’t degrade performance — the referral simply doesn’t happen. The inquiry that never arrived is invisible. She sees the bookings that came through. She has no view into the share links that stopped at a blank card.