Building an OpenGraph preview canvas for GitHub Copilot
Social preview bugs have a uniquely annoying feedback loop:
- Change a few
<meta>tags. - Deploy the site.
- Paste the public URL into one or more platform-specific validators.
- Discover that the image is cropped, the description is stale, or a required tag is missing.
- 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
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
- 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, andog:descriptionog:imageand whether its URL is absoluteog:image:alt, width, height, MIME type, and secure URLog:site_name,og:locale, andtwitter: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:
| Group | Checks |
|---|---|
| Discoverability | robots.txt, XML sitemap, and response Link headers |
| Content for agents | llms.txt and Markdown content negotiation |
| Bot access control | AI crawler rules and Content Signals |
| Agent and protocol discovery | MCP, A2A, Agent Skills, AI plugin, and DNS-AID |
| Auth for agents | OAuth 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.devwith 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:
| Capability | Purpose |
|---|---|
open_og_preview | Open or focus the canvas, optionally loading a URL immediately |
preview_url | Drive an open canvas to a URL and return the resolved preview fields |
get_metadata | Fetch 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-canvasThe 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.
The key pieces are:
extension.mjswires the canvas, actions, loopback routes, browsing proxy, and session handoffs.http-fetch.mjshandles redirects, timeouts, response limits, and network safety.parse-og.mjsresolves tags, URLs, social fields, repository clues, and diagnostics.agent-readiness.mjsprobes the emerging agent-facing standards.- The
uidirectory 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:
- Oversized responses are rejected immediately, and stream completion is guarded against double settlement.
- Relative canonical, image, and metadata URLs are resolved against the fetched page URL before they reach the UI.
- The four tabs expose selection state and panel relationships, use roving focus, and support keyboard navigation.
- 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=1opt-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
| Before | With the canvas |
|---|---|
| Deploy before validating | Preview localhost before deployment |
| Open separate platform validators | Compare nine renderings together |
Inspect <head> manually | Review grouped, copyable metadata |
| Translate a warning into work | Generate a grounded fix prompt |
| Find the owning repository | Detect it from the page |
| Copy context into another tool | Open a Copilot session or create an issue |
| Audit social metadata separately | Include 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.