Skip to main content
Glance Browser Testing Glance is Morph’s vision model, trained specifically to test code changes. Give it a diff and a URL—it figures out what to test and returns video, screenshots, errors, and network logs.

What You Get Back

OutputDescription
VideoMP4/WebM recording of the entire test session
Animated WebPEmbeddable in GitHub PRs, Slack, Notion, and more
ScreenshotsPer-step snapshots for debugging
ErrorsConsole errors, exceptions, and failed assertions
Network logsAll HTTP requests/responses during the test
Embed test recordings directly into your PRs, or use the SDK to integrate into your product—post results to your users’ PRs, Slack, Linear, or anywhere else.

Quick Start

import { MorphClient } from '@morphllm/morphsdk';

const morph = new MorphClient({ apiKey: "YOUR_API_KEY" });

const result = await morph.browser.execute({
  url: "https://preview-abc.vercel.app",
  diff: prDiff,  // Glance uses the diff to decide what to test
  task: "Test the changes in this PR",
  recordVideo: true
});

// What you get back
console.log(result.success);      // Agent's pass/fail assessment
console.log(result.result);       // What it found

if (result.recordingId) {
  const recording = await morph.browser.getRecording(result.recordingId);
  console.log(recording.videoUrl);    // Full video
  console.log(recording.networkUrl);  // Network logs
  console.log(recording.consoleUrl);  // Console/errors

  // Get embeddable WebP for PRs, Slack, etc.
  const { webpUrl } = await recording.getWebp({ maxSizeMb: 5 });
  console.log(`![Test Recording](${webpUrl})`);  // Markdown-ready
}

Integration Options


Harness API

Use this when you want to run your own browser and use Glance as the “brain” for step-by-step decisions.

Endpoints

  • Create session: POST /harness/sessions
  • Next step: POST /harness/sessions/{session_id}/step

Flow

  1. Create a session with url, diff, instructions, and your tools
  2. Take a screenshot in your browser
  3. Send the screenshot to /step, get back tool_calls
  4. Execute the tool calls, take a new screenshot, repeat
// 1. Create session
const session = await fetch("https://browser.morphllm.com/harness/sessions", {
  method: "POST",
  headers: { Authorization: `Bearer ${API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    url: "https://myapp.com",
    diff: prDiff,
    instructions: "Test the login flow",
    tools: [{ name: "click", description: "Click at coordinates", parameters: { /* ... */ } }]
  })
}).then(r => r.json());

// 2. Step loop
let done = false;
while (!done) {
  const screenshot = await page.screenshot({ encoding: "base64" });

  const step = await fetch(`https://browser.morphllm.com/harness/sessions/${session.session_id}/step`, {
    method: "POST",
    headers: { Authorization: `Bearer ${API_KEY}`, "Content-Type": "application/json" },
    body: JSON.stringify({ screenshot, context: { current_url: page.url() } })
  }).then(r => r.json());

  // Execute tool_calls in your browser
  for (const call of step.tool_calls) {
    if (call.name === "click") await page.mouse.click(call.args.x, call.args.y);
    if (call.name === "type_text") await page.keyboard.type(call.args.text);
  }

  done = step.is_done;
}

Step Response

{
  "step_index": 3,
  "tool_calls": [{ "name": "click", "args": { "x": 942, "y": 20 } }],
  "is_done": false,
  "done_reason": null
}
Send client_step_id with each step for idempotency—retries won’t create duplicate steps.