Claude Skills Guide

Open Graph Protocol meta tags shape how your content appears when shared on social media platforms. For developers and power users, understanding how these tags work across different sites becomes essential for debugging, content auditing, and building tools that consume structured metadata. A custom chrome extension that previews open graph data directly in your browser provides immediate insight into any page’s social metadata without leaving the browser.

Understanding Open Graph Metadata

The Open Graph Protocol, originally developed by Facebook, establishes a standard for how web pages represent themselves in social graphs. When you share a link on Twitter, LinkedIn, or Facebook, the platform extracts title, description, image, and other properties from special meta tags in the page’s HTML. These tags follow a predictable pattern using the og: prefix.

The core Open Graph properties include og:title, og:description, og:image, og:url, and og:type. Beyond these fundamentals, platforms like Twitter, LinkedIn, and Slack recognize additional meta tags such as twitter:card, twitter:image, and platform-specific variants. A well-built open graph preview extension should handle both standard Open Graph tags and platform-specific Twitter card metadata.

Building this extension requires understanding Chrome’s extension architecture, particularly how content scripts interact with page DOM and how the extension popup displays captured data.

Project Structure and Manifest Configuration

Create a new directory for your extension and set up the manifest file. Chrome extensions using Manifest V3 represent the current standard, offering improved security and performance characteristics.

// manifest.json
{
  "manifest_version": 3,
  "name": "Open Graph Preview",
  "version": "1.0",
  "description": "Preview Open Graph and Twitter Card metadata for any webpage",
  "permissions": ["activeTab", "scripting"],
  "action": {
    "default_popup": "popup.html",
    "default_icon": {
      "16": "icons/icon16.png",
      "48": "icons/icon48.png",
      "128": "icons/icon128.png"
    }
  },
  "icons": {
    "16": "icons/icon16.png",
    "48": "icons/icon48.png",
    "128": "icons/icon128.png"
  }
}

The manifest declares permissions for accessing the active tab and executing scripts. The popup action defines the HTML page that appears when clicking the extension icon.

Extracting Meta Tags with Content Scripts

Content scripts run in the context of web pages, allowing direct access to the DOM. This capability makes them ideal for extracting Open Graph metadata from page head elements.

// content.js
function extractMetaTags() {
  const ogTags = {};
  const metaSelectors = [
    { key: 'title', selectors: ['meta[property="og:title"]', 'meta[name="twitter:title"]', 'title'] },
    { key: 'description', selectors: ['meta[property="og:description"]', 'meta[name="twitter:description"]', 'meta[name="description"]'] },
    { key: 'image', selectors: ['meta[property="og:image"]', 'meta[name="twitter:image"]'] },
    { key: 'url', selectors: ['meta[property="og:url"]'] },
    { key: 'type', selectors: ['meta[property="og:type"]'] },
    { key: 'siteName', selectors: ['meta[property="og:site_name"]'] }
  ];

  metaSelectors.forEach(({ key, selectors }) => {
    for (const selector of selectors) {
      const element = document.querySelector(selector);
      if (element) {
        const content = element.getAttribute('content') || element.textContent;
        if (content) {
          ogTags[key] = content.trim();
          break;
        }
      }
    }
  });

  // Handle image URLs that might be relative
  if (ogTags.image && !ogTags.image.startsWith('http')) {
    const baseUrl = window.location.origin;
    ogTags.image = ogTags.image.startsWith('/') 
      ? baseUrl + ogTags.image 
      : baseUrl + '/' + ogTags.image;
  }

  return ogTags;
}

// Execute immediately since we need data right when the page loads
const metadata = extractMetaTags();
window.postMessage({ type: 'OG_PREVIEW_DATA', payload: metadata }, '*');

The extraction function handles several important scenarios. It attempts multiple selectors for each property, falling back to Twitter card tags and eventually to standard meta description tags. It also normalizes relative image URLs to absolute URLs using the page’s origin, which prevents broken image previews.

Building the Popup Interface

The popup HTML and JavaScript provide the user interface for viewing extracted metadata. When the user clicks the extension icon, the popup script requests metadata from the active tab.

<!-- popup.html -->
<!DOCTYPE html>
<html>
<head>
  <style>
    body { width: 400px; padding: 16px; font-family: -apple-system, BlinkMacSystemFont, sans-serif; }
    .preview-card { border: 1px solid #e0e0e0; border-radius: 8px; overflow: hidden; }
    .preview-image { width: 100%; height: 200px; object-fit: cover; background: #f5f5f5; }
    .preview-content { padding: 12px; }
    .preview-title { font-size: 16px; font-weight: 600; margin-bottom: 4px; }
    .preview-description { font-size: 14px; color: #666; }
    .preview-url { font-size: 12px; color: #999; margin-top: 8px; }
    .tag-section { margin-top: 16px; }
    .tag-row { display: flex; justify-content: space-between; font-size: 12px; padding: 4px 0; border-bottom: 1px solid #eee; }
    .tag-label { color: #666; }
    .tag-value { color: #333; font-weight: 500; max-width: 200px; overflow: hidden; text-overflow: ellipsis; }
  </style>
</head>
<body>
  <h3>Open Graph Preview</h3>
  <div id="preview-container"></div>
  <div class="tag-section" id="tags-container"></div>
  <script src="popup.js"></script>
</body>
</html>
// popup.js
document.addEventListener('DOMContentLoaded', async () => {
  const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
  
  chrome.tabs.sendMessage(tab.id, { type: 'GET_OG_DATA' }, (response) => {
    if (response && response.metadata) {
      renderPreview(response.metadata);
    } else {
      document.getElementById('preview-container').innerHTML = 
        '<p>No Open Graph metadata found on this page.</p>';
    }
  });
});

function renderPreview(metadata) {
  const container = document.getElementById('preview-container');
  const tagsContainer = document.getElementById('tags-container');
  
  // Build preview card
  let html = '<div class="preview-card">';
  if (metadata.image) {
    html += `<img class="preview-image" src="${escapeHtml(metadata.image)}" alt="Preview">`;
  }
  html += '<div class="preview-content">';
  if (metadata.title) {
    html += `<div class="preview-title">${escapeHtml(metadata.title)}</div>`;
  }
  if (metadata.description) {
    html += `<div class="preview-description">${escapeHtml(metadata.description)}</div>`;
  }
  if (metadata.url) {
    html += `<div class="preview-url">${escapeHtml(metadata.url)}</div>`;
  }
  html += '</div></div>';
  container.innerHTML = html;
  
  // Build detailed tags section
  let tagsHtml = '<h4>Raw Metadata</h4>';
  for (const [key, value] of Object.entries(metadata)) {
    tagsHtml += `<div class="tag-row">
      <span class="tag-label">${escapeHtml(key)}:</span>
      <span class="tag-value" title="${escapeHtml(value)}">${escapeHtml(value)}</span>
    </div>`;
  }
  tagsContainer.innerHTML = tagsHtml;
}

function escapeHtml(text) {
  const div = document.createElement('div');
  div.textContent = text;
  return div.innerHTML;
}

The popup renders both a visual preview card mimicking social media appearance and a detailed breakdown of all extracted metadata. The escapeHtml function prevents XSS vulnerabilities when displaying user-controlled content.

Handling Dynamic Content

Single-page applications and dynamically loaded content present challenges since meta tags might not exist in the initial HTML. For these cases, consider using a background script with a MutationObserver to detect changes.

// background.js
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.type === 'GET_OG_DATA') {
    chrome.tabs.sendMessage(sender.tab.id, { type: 'FETCH_OG_DATA' }, (response) => {
      sendResponse(response);
    });
    return true; // Keep channel open for async response
  }
});

This background script acts as a bridge, enabling communication between the popup and content scripts even in more complex scenarios.

Practical Applications

A functional Open Graph preview extension serves multiple purposes beyond simple metadata viewing. Content marketers use it to verify social sharing appearance before publishing. Developers debug missing or incorrectly formatted meta tags. SEO specialists audit competitor metadata strategies. Security researchers identify potential meta tag manipulation.

The extension architecture demonstrated here provides a foundation that you can extend with additional features such as editing meta tags for testing, exporting metadata as JSON, or comparing Open Graph implementation across multiple pages.

Building your own Open Graph preview tool gives you complete control over how you view and interact with social metadata. The transparency of seeing exactly what metadata any page publishes—and understanding how different platforms interpret that data—builds deeper knowledge of how the social web actually works.

Built by theluckystrike — More at zovo.one