Discord and Slack Link Preview Image Fallback Guide
Fix slack link preview image failures and Discord embed images with deterministic og:image fallback URLs that unfurl reliably in both platforms.
When a URL is posted in Slack or Discord, the platform fetches the page's Open Graph meta tags and renders a link preview card. The slack link preview image comes from og:image. When that tag is missing or returns an error, the preview shows the page title and description with no image — a notably less engaging card.
Internal tools, documentation portals, and developer blogs are the most common sources of shared links in engineering Slack channels. These sites rarely have per-page OG images. A URL-based fallback strategy makes every shared link from these properties look intentional.
How unfurling works
Slack and Discord scraping behavior for link previews
Slack's Link Unfurling runs when a user posts a URL in a channel or DM. Slack's servers fetch the URL (not the user's browser), parse the HTML, extract og:title, og:description, og:image, and og:image:width/height, then render the unfurled card. The fetch runs server-to-server and does not send user credentials.
Discord's embed system works similarly. Discord's scraper fetches the URL from Discord's servers and renders an embed using OG tags. Discord also reads Twitter Card meta tags (twitter:image, twitter:card) as a fallback when OG tags are absent. Providing both OG and Twitter Card tags maximizes compatibility.
Both platforms cache the unfurled preview. Slack's cache duration is not publicly documented but approximately 30 minutes to a few hours for frequently shared URLs. Discord's cache is similar. Neither platform has a user-accessible cache clear button; the developer console in the respective API can force a re-fetch.
Private URLs
Handling link previews for authenticated internal tools
Slack and Discord fetch URLs from their own servers without authentication. If the URL requires a login to access, the scraper receives a redirect to the login page and reads the login page's OG tags instead of the target page's tags. The preview shows the generic login page image, not the document image.
There is no way to pass session cookies to the platform's scraper. The only reliable solution for authenticated content is to serve the OG meta tags in a public pre-render layer that does not require authentication. Some frameworks support this via a public metadata endpoint that returns the OG tags for a given document ID without serving the document content.
For internal tools where you control the embedding, Discord and Slack both support rich message embeds via their APIs. You can send a message with a pre-constructed embed object that includes the image URL directly, bypassing the unfurl scraper entirely.
Internal tools
Generating og:image for internal documentation and runbooks
Internal documentation portals (Notion-exported pages, Confluence, custom wikis) are shared constantly in Slack. They almost never have per-page OG images. A site-wide layout that generates a fallback.pics thumbnail from the page title and section name covers every page without per-page work.
For Notion, you cannot inject custom OG tags into exported pages. The workaround is to publish Notion content through a proxy (Feather, super.so, Potion) that adds a custom head and lets you configure OG image generation per page or based on the page title.
// Express middleware — inject og:image for every page
app.use((req, res, next) => {
res.locals.generateOgImage = (title, section = 'Docs') =>
`https://fallback.pics/api/v1/thumbnail/1200x630.png` +
`?text=${encodeURIComponent(title)}` +
`&label=${encodeURIComponent(section)}` +
`&theme=purple&style=soft`;
next();
});
// In your EJS/Handlebars template
// <meta property="og:image" content="<%= generateOgImage(pageTitle, section) %>" /> Testing
Debugging unfurl previews without spamming your Slack channel
Slack provides an API endpoint for testing unfurls: chat.unfurl in the Slack API. You can call it with a URL to see the resolved unfurl data without posting to a channel. The simpler approach is to create a private Slack channel used exclusively for testing link previews and post URLs there.
Discord's embed tester is available at discohook.org — a community tool that lets you construct and preview Discord embeds including link unfurls. For your own URL, the easiest test is to create a server and post the URL in a private channel.
Key takeaways
What to standardize before shipping
- Slack and Discord fetch og:image from their own servers without user credentials — authenticated pages cannot provide previews.
- Include og:image:width and og:image:height in your meta tags so Slack and Discord display the card immediately.
- Discord also reads Twitter Card tags; providing both sets maximizes compatibility.
- For internal tools behind authentication, serve OG tags in a public metadata layer or use the platform's rich message API.
- Test with a private Slack channel or discohook.org without polluting shared channels.
Production fallback layer
Use fallback.pics anywhere an image URL is accepted.
Start with one deterministic URL and standardize fallback behavior across your design system.