Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Chromium Control Canvas
A GitHub Copilot canvas that drives a real headful Chromium window via Playwright.
The host app's built-in browser canvas is WebKit (WKWebView); this gives you actual
Chromium, controllable both from the panel UI and by the agent.
The canvas panel is a control strip (URL bar, back/forward/reload, screenshot). A separate Chromium window does the real rendering, because you can't embed Chromium inside a WebKit iframe.
Files
extension.mjs— the extension: canvas declaration, Playwright launch, a loopback HTTP server for the panel, and the agent actions.index.html— the control strip UI the panel renders.package.json— declares theplaywrightdependency and"type": "module".copilot-extension.json— name/version metadata.
Prerequisites
- Node.js 18 or newer (Playwright 1.60 requires
node >=18; older versions hit a cryptic engine error). The extension runs as a Node child process. - The app's canvas / UI-extensions experiment enabled. Without it, the extension loads but the canvas never appears in the panel. Enable it in the app's Settings → Experiments. (This may not be available to all accounts.)
Install
Drop this folder at ~/.copilot/extensions/chromium-control-canvas/ (user scope) or in a repo's
.github/extensions/chromium-control-canvas/ (project scope), then install dependencies and the
Chromium binary from inside that folder:
cd ~/.copilot/extensions/chromium-control-canvas
npm install # playwright is declared in package.json
npx playwright install chromium # downloads the browser, a few hundred MB
Reload extensions in the app, then open the chromium-control-canvas canvas.
Note: copying the extension files only places the source. It does not run the commands above or enable the experiment, so those steps are still required on first setup.
Attach to your own Chrome
By default the canvas launches the bundled Chromium with a persistent profile. To drive
a Chrome you already have running instead, start it with a debug port and pass cdpUrl
when opening the canvas:
google-chrome --remote-debugging-port=9222 # then open the canvas with cdpUrl: http://localhost:9222
In this mode the extension connects over CDP and never launches or kills your browser; closing the canvas just disconnects.
Agent actions
navigate { url }— go to a URL or search query (blocklist-guarded).back/forward/reload— history navigation.current_url— current URL and page title.snapshot— structured list of visible interactive elements, each with a stable ref.click { ref | selector }— click an element by snapshot ref or CSS selector.type { ref | selector, text, submit? }— fill an input; optionally press Enter.screenshot { fullPage? }— save a PNG toartifacts/and return its path and size.
Notes
- A persistent profile is stored in
profile/so logins survive restarts. Do not commit or shareprofile/— it contains real session cookies. - Raw
evaluate(arbitrary in-page JS) is intentionally omitted. navigateis checked against a blocklist, and a request interceptor also blocks navigations to blocked hosts that happen via in-page redirects. The shippedBLOCKLISTentries are illustrative examples, not real coverage — edit the list inextension.mjsto fit your environment.- The loopback control server requires a per-launch token (templated into the panel), so other pages in your browser can't drive it.
- Typed text (e.g. passwords) is redacted in
audit.log, and password field values are excluded from snapshots. - Generated at runtime and not part of the source:
node_modules/,profile/,artifacts/,audit.log.