You might have seen this "[link preview](https://mgx.me/35)" thing on my website - I implemented it using PHP. But I thought I'd share another approach that's even easier to set up.

This guide will show you how to implement a popover link preview system on your blog in minutes, without a complex backend or heavy plugins, by leveraging Cloudflare Workers (free tier) and a small piece of JavaScript.
The popover preview system has two parts:
1. **A Cloudflare Worker** that fetches and parses web pages
2. **A frontend script** that handles hover events and shows popover previews
### The Back-end (Cloudflare Worker)
```javascript
export default {
async fetch(request) {
const { searchParams } = new URL(request.url);
const targetUrl = searchParams.get("url");
const origin = request.headers.get("Origin");
const allowedOrigin = "https://yourdomain.com";
// Good enough to prevent casual hotlinking.
// Build CORS headers only if Origin matches
const corsHeaders = {
"Content-Type": "application/json",
"Access-Control-Allow-Methods": "GET, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type",
...(origin === allowedOrigin ? { "Access-Control-Allow-Origin": allowedOrigin } : {}),
};
// Handle preflight OPTIONS requests
if (request.method === "OPTIONS") {
return new Response(null, { headers: corsHeaders });
}
if (!targetUrl) {
return new Response(JSON.stringify({ error: "No URL provided" }), {
status: 400,
headers: corsHeaders,
});
}
// Validate URL
let url;
try {
url = new URL(targetUrl);
} catch (e) {
return new Response(JSON.stringify({ error: "Invalid URL" }), {
status: 400,
headers: corsHeaders,
});
}
let html;
try {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 10000);
const resp = await fetch(url.toString(), {
redirect: "follow",
signal: controller.signal,
headers: {
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 " +
"(KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Accept":
"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.9",
"Connection": "keep-alive",
},
});
clearTimeout(timeout);
html = await resp.text();
} catch (e) {
return new Response(
JSON.stringify({ error: "Failed to fetch the URL (timeout or blocked)" }),
{ status: 500, headers: corsHeaders }
);
}
const getMeta = (pattern) => {
const match = html.match(pattern);
return match ? match[1] : null;
};
let title =
getMeta(/
(.*?)<\/title>/i) ||
getMeta(/]+property=["']og:title["'][^>]+content=["'](.*?)["']/i) ||
getMeta(/]+name=["']twitter:title["'][^>]+content=["'](.*?)["']/i);
let description =
getMeta(/]+name=["']description["'][^>]+content=["'](.*?)["']/i) ||
getMeta(/]+property=["']og:description["'][^>]+content=["'](.*?)["']/i) ||
getMeta(/]+name=["']twitter:description["'][^>]+content=["'](.*?)["']/i);
let ogImage =
getMeta(/]+property=["']og:image["'][^>]+content=["'](.*?)["']/i) ||
getMeta(/]+name=["']twitter:image["'][^>]+content=["'](.*?)["']/i) ||
getMeta(/]+name=["']thumbnail["'][^>]+content=["'](.*?)["']/i);
if (ogImage && !/^https?:\/\//i.test(ogImage)) {
ogImage = `${url.protocol}//${url.host}${ogImage}`;
}
if (!title) {
const h1 = html.match(/]*>(.*?)<\/h1>/i);
title = h1 ? h1[1].replace(/<[^>]+>/g, ") : null;
}
if (!description) {
const p = html.match(/
]*>(.*?)<\/p>/i);
description = p ? p[1].replace(/<[^>]+>/g, ") : null;
}
if (!title && !description && !ogImage) {
return new Response(JSON.stringify({ error: "No previewable content found" }), {
status: 204,
headers: corsHeaders,
});
}
return new Response(
JSON.stringify({ url: targetUrl, title, description, ogImage }),
{ headers: corsHeaders }
);
},
};
```
### The Front-end JS & Popover HTML
```javascript
```
```html
```
## How To Set It Up
### Step 1: Create a Cloudflare Worker
1. Sign up for Cloudflare (if you don't have an account) at [cloudflare.com](https://cloudflare.com)
2. Go to **Workers & Pages** in your Cloudflare dashboard
3. Click **"Create a Worker"**
4. Delete the default code and paste the worker code from [`worker.js`](https://github.com/verfasor/popover-preview-with-cloudflare-workers/blob/main/worker.js)
- Inside the code, you’ll see:
```javascript
const allowedOrigin = "https://yourdomain.com";
```
- Update `https://yourdomain.com` to your own domain.
5. Click **"Save and Deploy"**
6. Copy your worker URL (it will look like `https://your-worker.your-subdomain.workers.dev`)
### Step 2: Add the Frontend Script + HTML snippet
1. Open your website's header or footer template
2. Add the JavaScript code and HTML snippet from [`client.html`](https://github.com/verfasor/popover-preview-with-cloudflare-workers/blob/main/client.html) to your page
3. Update the worker URL in the JavaScript:
```javascript
const res = await fetch(
"https://your-worker.your-subdomain.workers.dev/?url=" + encodeURIComponent(url)
);
```
4. Add the preview box HTML to your page:
```html
```
### Step 3: Test It
1. Save your changes and refresh your page
2. Hover over any link - you should see a popover preview appear
3. The front-end script is designed to be easily customizable. So make it your own.
Have fun.
Note: The frontend JS for this guide has only been tested for compatibility with bearblog.dev. Users on platforms like WordPress, Ghost, or static sites may need to adjust the containerSelector variable in the script.