Chrome Extension Open Graph Preview (2026)
Open Graph protocol metadata controls how links appear when shared on social media platforms. A Chrome extension that previews Open Graph tags helps developers and content creators verify their social sharing cards before publishing. This guide walks through building a functional Open Graph preview extension with practical code examples.
Understanding Open Graph Meta Tags
Open Graph tags live in the <head> section of HTML documents. The essential tags include og:title, og:description, og:image, and og:url. Twitter and other platforms extend these with their own namespace, but the core Open Graph structure remains consistent across platforms.
When you share a link on Facebook, LinkedIn, or Twitter, these platforms fetch the Open Graph metadata to generate preview cards. Without proper tags, you get plain text links that perform poorly in engagement metrics. A preview extension lets you catch these issues before sharing.
Extension Architecture
Chrome extensions consist of several components working together. For an Open Graph preview extension, you need a popup interface for displaying results and a content script or background script for fetching page metadata.
The manifest file defines permissions and components:
{
"manifest_version": 3,
"name": "Open Graph Preview",
"version": "1.0",
"description": "Preview Open Graph meta tags for any webpage",
"permissions": ["activeTab", "scripting"],
"action": {
"default_popup": "popup.html"
}
}
The popup serves as the main interface where users see extracted metadata when they click the extension icon.
Extracting Open Graph Tags
The core functionality involves parsing HTML to find Open Graph meta tags. You can accomplish this through a content script that runs on the active tab or by using the Chrome DevTools Protocol in a background script.
Here is a practical implementation using the chrome.scripting.executeScript API:
// background.js
async function getOpenGraphTags() {
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
const results = await chrome.scripting.executeScript({
target: { tabId: tab.id },
function: () => {
const tags = {
title: '',
description: '',
image: '',
url: '',
siteName: ''
};
// Helper function to extract meta tag content
const getMetaContent = (property) => {
const el = document.querySelector(`meta[property="${property}"]`)
|| document.querySelector(`meta[name="${property}"]`);
return el ? el.getAttribute('content') : '';
};
tags.title = getMetaContent('og:title') || getMetaContent('twitter:title');
tags.description = getMetaContent('og:description') || getMetaContent('description');
tags.image = getMetaContent('og:image') || getMetaContent('twitter:image');
tags.url = getMetaContent('og:url');
tags.siteName = getMetaContent('og:site_name');
return tags;
}
});
return results[0].result;
}
This function runs directly in the context of the current page, giving it access to the full DOM including dynamically loaded meta tags.
Building the Popup Interface
The popup needs to display the extracted metadata in a visual format that resembles the actual social card. Create an HTML file with CSS styling:
<!-- popup.html -->
<!DOCTYPE html>
<html>
<head>
<style>
body { width: 320px; font-family: -apple-system, system-ui, sans-serif; }
.preview-card { border: 1px solid #e0e0e0; border-radius: 8px; overflow: hidden; }
.preview-image { width: 100%; height: 160px; object-fit: cover; background: #f0f0f0; }
.preview-content { padding: 12px; }
.preview-title { font-weight: 600; margin-bottom: 4px; font-size: 14px; }
.preview-description { color: #666; font-size: 12px; line-height: 1.4; }
.preview-site { color: #999; font-size: 11px; text-transform: uppercase; }
.field { margin-bottom: 8px; }
.field-label { font-size: 11px; color: #666; }
.field-value { font-size: 12px; word-break: break-all; }
</style>
</head>
<body>
<div id="preview-container"></div>
<script src="popup.js"></script>
</body>
</html>
The popup JavaScript handles initializing the interface and populating it with data:
// popup.js
document.addEventListener('DOMContentLoaded', async () => {
const container = document.getElementById('preview-container');
// Request metadata from background script
const tags = await chrome.runtime.sendMessage({ action: 'getOGTags' });
if (!tags.title && !tags.description && !tags.image) {
container.innerHTML = '<p style="padding: 16px;">No Open Graph tags found</p>';
return;
}
// Build preview card
const card = document.createElement('div');
card.className = 'preview-card';
if (tags.image) {
const img = document.createElement('img');
img.src = tags.image;
img.className = 'preview-image';
img.onerror = () => img.style.display = 'none';
card.appendChild(img);
}
const content = document.createElement('div');
content.className = 'preview-content';
if (tags.siteName) {
const siteName = document.createElement('div');
siteName.className = 'preview-site';
siteName.textContent = tags.siteName;
content.appendChild(siteName);
}
if (tags.title) {
const title = document.createElement('div');
title.className = 'preview-title';
title.textContent = tags.title;
content.appendChild(title);
}
if (tags.description) {
const desc = document.createElement('div');
desc.className = 'preview-description';
desc.textContent = tags.description;
content.appendChild(desc);
}
card.appendChild(content);
container.appendChild(card);
});
Handling Dynamic Content
Single-page applications and dynamically loaded content present challenges because meta tags may update after the initial page load. You can address this by using a MutationObserver in your content script to detect changes to the <head> element.
// content-script.js - observe meta tag changes
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'childList') {
// Re-extract and send updated tags
const updatedTags = extractOpenGraphTags();
chrome.runtime.sendMessage({
action: 'tagsUpdated',
tags: updatedTags
});
}
});
});
observer.observe(document.head, {
childList: true,
subtree: true,
attributes: true,
attributeFilter: ['content']
});
The background script listens for these updates and refreshes the popup when reopened.
Debugging Common Issues
Several problems frequently arise when building Open Graph preview extensions. Image URLs are often relative paths rather than absolute URLs. Resolve this by combining the page URL with the image path:
function resolveUrl(relativeUrl, baseUrl) {
try {
return new URL(relativeUrl, baseUrl).href;
} catch {
return relativeUrl;
}
}
const absoluteImage = resolveUrl(tags.image, window.location.origin);
Another issue involves Facebook and other platforms requiring image dimensions. Include width and height attributes in your preview when available:
const ogImage = document.querySelector('meta[property="og:image"]');
const imageUrl = ogImage?.getAttribute('content');
const imageWidth = ogImage?.getAttribute('width');
const imageHeight = ogImage?.getAttribute('height');
Testing Your Extension
Load your extension in Chrome by navigating to chrome://extensions/, enabling Developer mode, and selecting the directory containing your extension files. Open a webpage with Open Graph tags and click the extension icon to verify the preview displays correctly.
Test with popular sites like GitHub, Medium, and news websites that implement Open Graph correctly. Also test with pages that lack Open Graph tags to confirm graceful fallback behavior.
Building an Open Graph preview extension gives you a practical tool for verifying social metadata while learning Chrome extension development fundamentals. The same techniques apply to more complex extensions that analyze SEO, validate structured data, or extract other page metadata.
Try it: Paste your error into our Error Diagnostic for an instant fix.
Related Reading
- Chrome Extension Markdown Editor: Build Your Own Browser-Based Writing Tool
- Responsive Viewer Alternative Chrome Extension 2026
- Web Developer Toolbar Alternative Chrome Extension in 2026
- Chrome Extension Markdown Preview: Complete Developer Guide
- Chrome Extension Google Serp P — Honest Review 2026
Built by theluckystrike. More at zovo.one