Ctrl/ K search results Enter open Esc close

// Theme

Pick a palette. Ctrl/⌘ K is reserved for search.
GitHub

Building an OpenGraph preview canvas for GitHub Copilot

Social preview bugs have a uniquely annoying feedback loop:

  1. Change a few <meta> tags.
  2. Deploy the site.
  3. Paste the public URL into one or more platform-specific validators.
  4. Discover that the image is cropped, the description is stale, or a required tag is missing.
  5. Repeat.

That felt backwards. I wanted to inspect the page where I was already working, compare every important social card at once, understand the metadata behind them, and fix problems before deploying anything.

So I built an open-source OpenGraph Preview canvas for the GitHub Copilot app. It works with public URLs and localhost, and it turns a passive preview into an agent-driven workflow.

See it in action

Play

The video walks through the end-to-end flow in about six minutes: browse a page inside the canvas, inspect its social cards, review the raw metadata, and turn a diagnostic into a ready-to-run Copilot task.

One canvas, four working modes

The canvas has four tabs, but they all operate on the same URL and shared state. Navigating in Browse refreshes Previews, Raw metadata, and Diagnostics automatically.

The walkthrough uses aspire.dev as one consistent target, so each view shows a different layer of evidence for the same page.

Browse the live page

The default tab is a real, interactive page view. The address bar accepts a full URL, a bare domain, or a local address such as localhost:4321.

This is not a static screenshot. The page is fetched through the extension’s loopback server and rendered in a sandboxed frame. Internal navigation updates the address bar and reruns the metadata pipeline. Reload and open-in-browser controls are available beside the main Preview button, while the “I’m feeling lucky” control offers a quick sample site.

The practical value is continuity: I can browse to the exact route I care about without leaving the canvas or copying URLs between tools.

Compare nine social renderings

The Previews tab renders the same metadata as:

  • OpenGraph / Facebook
  • X
  • Bluesky
  • Mastodon
  • LinkedIn
  • Reddit
  • Slack
  • Microsoft Teams
  • Discord

The larger list layout preserves detail, while the compact grid makes cross-platform differences obvious at a glance.

Inspect the raw evidence

Pretty cards are useful, but debugging requires evidence. Raw metadata is grouped into OpenGraph, Twitter / X, other metadata, and icons or links. Values get useful formatting, every row has a copy action, and the entire payload can be copied as JSON.

Aspire pages also emit git-commit-id and git-source-url. Hovering the source URL fetches the corresponding GitHub file and displays a scrollable, syntax-highlighted hovercard without leaving the canvas.

That connection from rendered page to source file is small but powerful. It removes the “which file generated this page?” step from the debugging loop.

Diagnose, explain, and act

The OpenGraph diagnostics check required, recommended, and optional metadata, including structured image properties:

  • og:title, og:type, og:url, and og:description
  • og:image and whether its URL is absolute
  • og:image:alt, width, height, MIME type, and secure URL
  • og:site_name, og:locale, and twitter:card
  • Description length

I pointed the canvas at aspire.dev for this walkthrough. Instead of manufacturing a failure, the diagnostics confirmed that the site passes every displayed check: the core OpenGraph fields, site name and locale, X card metadata, absolute and secure image URLs, image alt text, declared dimensions, MIME type, and description length.

A clean report is useful evidence too: it confirms the metadata is complete before a platform crawler ever sees the page. The failure path is just as important, but it should not invent problems on a healthy site.

Expanding the missing og:image:alt check explains why it matters, shows the exact tag shape, links to the OpenGraph structured-properties reference, and produces a copyable AI fix prompt grounded in the local page.

The fixture deliberately has no repository link, so the canvas does not guess - it leaves the prompt ready to copy manually. The repo-backed aspire.dev example below shows how the same remediation pattern can continue directly into Copilot or a GitHub issue.

Agent readiness is part of web readiness

OpenGraph metadata answers, “How will a person see this link?” The experimental Agent readiness section asks, “How will an agent discover, read, and act on this site?”

It runs 15 read-only checks across five groups:

GroupChecks
Discoverabilityrobots.txt, XML sitemap, and response Link headers
Content for agentsllms.txt and Markdown content negotiation
Bot access controlAI crawler rules and Content Signals
Agent and protocol discoveryMCP, A2A, Agent Skills, AI plugin, and DNS-AID
Auth for agentsOAuth protected-resource metadata, authorization-server metadata, and API Catalog

On aspire.dev, the audit detects the sitemap, llms.txt, Markdown negotiation, and Content Signals.

Expanding the missing AI crawler rules produces a focused prompt, detects microsoft/aspire.dev, and exposes the Copilot and issue actions.

The remediation card includes two next actions:

  • Open in Copilot starts a coding session for microsoft/aspire.dev with the generated prompt already supplied.
  • Create issue files the recommendation in the repository and hands it to the Copilot coding agent.

Repository detection scores GitHub links in the fetched HTML. An “Edit this page” link is a strong signal; blob, tree, raw, and commit links are also considered. If the source cannot be identified confidently, the canvas does not guess - it leaves the prompt ready to copy manually.

Emerging standards are deliberately reported as informational rather than hard failures. That distinction matters: an absent experimental endpoint should not make a healthy site look broken.

The agent can drive the canvas too

The UI is only half of the collaboration model. The extension exposes one tool and two canvas actions:

CapabilityPurpose
open_og_previewOpen or focus the canvas, optionally loading a URL immediately
preview_urlDrive an open canvas to a URL and return the resolved preview fields
get_metadataFetch and parse a URL headlessly, returning raw tags and diagnostics

That means I can ask Copilot:

Open the OG preview for localhost:4321/posts/opengraph-preview-canvas

The human-visible canvas opens, while the agent can inspect the same structured result. Server-Sent Events keep agent-driven navigation synchronized with the open panel.

How the extension works

The implementation is dependency-free JavaScript with no build step. Each canvas instance gets a small HTTP server bound to 127.0.0.1 on a random port.

Preview localhost:4321 open_og_preview(url) canvas.open Start 127.0.0.1 server Renderer URL Open side panel GET /api/fetch?u=... Fetch HTML HTML + headers Parse metadata + diagnostics Structured JSON SSE updates for agent navigation Human Copilot Canvas runtime OG extension Canvas renderer Target page

The key pieces are:

  • extension.mjs wires the canvas, actions, loopback routes, browsing proxy, and session handoffs.
  • http-fetch.mjs handles redirects, timeouts, response limits, and network safety.
  • parse-og.mjs resolves tags, URLs, social fields, repository clues, and diagnostics.
  • agent-readiness.mjs probes the emerging agent-facing standards.
  • The ui directory contains the renderer, platform cards, interactions, theme support, and loading states.

Server-side fetching solves two important problems. It avoids browser CORS restrictions, and it makes localhost reachable from the extension process. The interactive Browse tab uses a script-rewriting proxy so styles, modules, fonts, and internal navigation continue working inside an opaque-origin sandbox.

Safety and accessibility are part of the design

Fetching arbitrary URLs from an agent-driven canvas requires deliberate guardrails:

  1. Oversized responses are rejected immediately, and stream completion is guarded against double settlement.
  2. Relative canonical, image, and metadata URLs are resolved against the fetched page URL before they reach the UI.
  3. The four tabs expose selection state and panel relationships, use roving focus, and support keyboard navigation.
  4. Every destination and redirect hop is validated. Private, link-local, CGNAT, and cloud-metadata ranges are blocked, while loopback remains available for the core local-preview scenario. Private networks require an explicit OG_ALLOW_PRIVATE_NETWORK=1 opt-in.

That last tradeoff is especially important. “Supports localhost” should not mean “silently turns the agent into a network scanner.”

Why this changes the feedback loop

BeforeWith the canvas
Deploy before validatingPreview localhost before deployment
Open separate platform validatorsCompare nine renderings together
Inspect <head> manuallyReview grouped, copyable metadata
Translate a warning into workGenerate a grounded fix prompt
Find the owning repositoryDetect it from the page
Copy context into another toolOpen a Copilot session or create an issue
Audit social metadata separatelyInclude agent readiness in the same workflow

The real value is not the card renderer by itself. It is the shortened distance between seeing a problem, understanding it, and starting the correct fix in the correct repository.

Try it yourself

Start by installing the GitHub Copilot app.

The extension is open source in the Aspire docs repository. It is self-contained, uses the documented GitHub Copilot app theme tokens, and has no package installation or compilation step.

Read the official canvas extension documentation, copy or adapt the extension for your own workflow, and then ask Copilot to open a public or local URL.

Better social cards are the immediate payoff. The more interesting outcome is a reusable pattern: give humans and agents the same visible artifact, the same structured evidence, and an explicit path from diagnosis to action.

Table of Contents

More Posts

Comments