Ever noticed how Slack, Discord, and Twitter show rich previews when you paste a link? That feature dramatically increases engagement. Here's how to build it for your own app.
What Makes a Good Link Preview?
A link preview typically includes:
- Title — from the
<title>orog:titlemeta tag - Description — from
og:description - Image — from
og:image, or a screenshot of the page - Favicon — the site's icon
Step 1: Fetch OG Meta Tags
// Node.js — fetch and parse OG tags
async function getOGData(url) {
const response = await fetch(url);
const html = await response.text();
const getTag = (property) => {
const match = html.match(new RegExp(`]*property=["']${property}["'][^>]*content=["']([^"']*)["']`, 'i'));
return match ? match[1] : null;
};
return {
title: getTag('og:title') || html.match(/([^<]*)<\/title>/i)?.[1] || '',
description: getTag('og:description') || '',
image: getTag('og:image') || null,
siteName: getTag('og:site_name') || new URL(url).hostname
};
}
Step 2: Generate Preview Image (When og:image is Missing)
Many websites don't have OG images. Use a screenshot API as a fallback:
async function getPreviewImage(url) {
// First try OG image
const og = await getOGData(url);
if (og.image) return og.image;
// Fallback: screenshot the page
return `https://api.pandan.is/v1/screenshot?url=${encodeURIComponent(url)}&width=1200&height=630&format=jpeg&quality=80`;
}
Step 3: React Component
function LinkPreview({ url }) {
const [data, setData] = useState(null);
useEffect(() => {
fetch(`/api/preview?url=${encodeURIComponent(url)}`)
.then(r => r.json())
.then(setData);
}, [url]);
if (!data) return <div className="preview-loading">Loading...</div>;
return (
<a href={url} className="link-preview" target="_blank" rel="noopener">
<img src={data.image} alt="" />
<div className="preview-content">
<h3>{data.title}</h3>
<p>{data.description}</p>
<span className="preview-domain">{data.siteName}</span>
</div>
</a>
);
}
Step 4: Generate OG Images for YOUR Pages
Don't just consume previews — generate them. Use the Pandan OG Image API to create beautiful social images for your own content:
// In your page's <head>
<meta property="og:image" content="https://og.pandan.is/v1/og?title=My+Blog+Post&subtitle=A+guide+for+developers&theme=dark" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
Performance Tips
- Cache aggressively — Preview data rarely changes. Cache for 24-48 hours.
- Generate asynchronously — Don't block message rendering on preview generation.
- Use lazy loading — Only fetch previews when they scroll into view.
- Set image dimensions — Prevent layout shift by specifying width/height.
Complete Backend (Express.js)
app.get('/api/preview', async (req, res) => {
const { url } = req.query;
if (!url) return res.status(400).json({ error: 'URL required' });
// Check cache first (Redis, in-memory, etc.)
const cached = cache.get(url);
if (cached) return res.json(cached);
const og = await getOGData(url);
const data = {
...og,
image: og.image || `https://api.pandan.is/v1/screenshot?url=${encodeURIComponent(url)}&width=1200&height=630&format=jpeg&quality=80`
};
cache.set(url, data, 86400); // Cache 24h
res.json(data);
});
Related Pandan Tools
- Screenshot API — Capture any website (100 free/month)
- OG Image API — Generate social preview images
- QR Code API — Generate QR codes for your links
- Link Shortener — Shorten URLs with click tracking