Collect visual annotations
The annotated browser is a self-contained iframe that combines a live browser
and an annotation overlay into one embeddable view. Your users point at a live
page and leave feedback; your app receives each submission via postMessage —
no WebSocket or webhook plumbing on your side.
It’s the annotated-browser surface of @coframe/editor-embed,
so you drive it with the same EmbedController / <EditorEmbed> API.
How it works
Section titled “How it works”- Your app mounts the iframe (surface
annotated-browser) with a capability token and navigates it to a target URL. - Inside the iframe, Coframe Agent provisions the live browser, injects the annotation overlay on every page navigation, and watches for submissions.
- When a user submits an annotation, the iframe re-emits it to your app as an
annotation-submittedevent overpostMessage.
Quick start (vanilla JS)
Section titled “Quick start (vanilla JS)”onAnnotationSubmitted is a convenience helper that subscribes to just the
annotation events:
import { EmbedController, onAnnotationSubmitted } from "@coframe/editor-embed";
const controller = new EmbedController({ editorBaseUrl: "https://editor.example.com", sessionId: "my-session", surface: "annotated-browser", token: "capability-token",});
const iframe = document.getElementById("embed") as HTMLIFrameElement;iframe.src = controller.buildIframeSrc();controller.attach(iframe);
const unsubscribe = onAnnotationSubmitted(controller, (submission) => { console.log("Annotated:", submission.url, submission.annotations);});
controller.navigate("https://example.com/landing");
// Laterunsubscribe();controller.dispose();Quick start (React)
Section titled “Quick start (React)”import { EditorEmbed } from "@coframe/editor-embed/react";
function AnnotatedBrowser({ sessionId, token }: { sessionId: string; token: string;}) { return ( <EditorEmbed editorBaseUrl="https://editor.example.com" sessionId={sessionId} token={token} surface="annotated-browser" style={{ width: "100%", height: 600 }} onEvent={(event) => { if (event.type === "annotation-submitted") { // Build a prompt or task from the submission console.log(event.submission.annotations); } }} /> );}The annotation-submitted payload
Section titled “The annotation-submitted payload”interface AnnotationSubmissionPayload { id: string; url: string; createdAt: string; annotations: unknown[]; source: string; authorLabel?: string;}See Embed the editor for the full
list of commands you can send (navigate, setReadonly, dispose, …) and
events you can receive.
Live demo
Section titled “Live demo”The demo mounts the annotated browser and exercises the full pipeline. The
“Simulate annotation” button submits an annotation, which flows back to the
parent as an annotation-submitted event: