← Til baka

How to Add Link Previews to Your App (Like Slack, Discord, and Twitter)

· 5 mín lestrartími · Developer Tools

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:

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
  };
}</code></pre>

<h2>Step 2: Generate Preview Image (When og:image is Missing)</h2>
<p>Many websites don't have OG images. Use a screenshot API as a fallback:</p>
<pre><code>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`;
}</code></pre>

<h2>Step 3: React Component</h2>
<pre><code>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>
  );
}</code></pre>

<h2>Step 4: Generate OG Images for YOUR Pages</h2>
<p>Don't just consume previews — generate them. Use the Pandan OG Image API to create beautiful social images for your own content:</p>
<pre><code>// 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" /></code></pre>
<p><a href="https://og.pandan.is">Try Pandan OG Image API →</a></p>

<h2>Performance Tips</h2>
<ul>
<li><strong>Cache aggressively</strong> — Preview data rarely changes. Cache for 24-48 hours.</li>
<li><strong>Generate asynchronously</strong> — Don't block message rendering on preview generation.</li>
<li><strong>Use lazy loading</strong> — Only fetch previews when they scroll into view.</li>
<li><strong>Set image dimensions</strong> — Prevent layout shift by specifying width/height.</li>
</ul>

<h2>Complete Backend (Express.js)</h2>
<pre><code>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);
});</code></pre>

<h2>Related Pandan Tools</h2>
<ul>
<li><a href="https://api.pandan.is">Screenshot API</a> — Capture any website (100 free/month)</li>
<li><a href="https://og.pandan.is">OG Image API</a> — Generate social preview images</li>
<li><a href="https://qr.pandan.is">QR Code API</a> — Generate QR codes for your links</li>
<li><a href="https://s.pandan.is">Link Shortener</a> — Shorten URLs with click tracking</li>
</ul>
    </main>
    <footer class="container">
      <div class="cta-box">
        <h3>🐼 Skoðaðu verkfærin okkar</h3>
        <p>Pandan býður upp á fjölbreytt verkfæri fyrir einstaklinga og fyrirtæki.</p>
        <div class="cta-links">
          
          <a href="https://index.pandan.is" target="_blank">Sjá öll verkfæri →</a>
        </div>
      </div>
      <div style="background:#0d0d1a;padding:30px 20px;text-align:center;margin-top:24px;border-radius:12px">
        <h3 style="color:#7b2ff7;margin-bottom:8px;font-size:1.1rem">📧 Fáðu fréttir af nýjum verkfærum</h3>
        <p style="color:#888;margin-bottom:12px;font-size:.85rem">Ný verkfæri, uppfærslur og ráð. Engin ruslpóstur.</p>
        <div data-pandan-email data-pandan-source="blog.pandan.is" data-pandan-cta="Skráðu þig"></div>
      </div>
      <script src="https://mail.pandan.is/widget.js"></script>
    </footer>
  
</body>
</html>