HTML frames (render at times)

$0.02 per callUSDC via x402POST /api/html-frames

Render a self-contained HTML document in headless Chromium with all network access refused, call its window.renderAt(t) for each requested time in seconds, and return a PNG still per time (base64) plus one contact-sheet PNG of every still in a grid. Send POST /api/html-frames with the required fields html and times and pay $0.02 per call over x402 or MPP (there is no free tier). It returns a JSON object with width, height, frameCount, frames, contactSheet and 2 more.

For previews of canvas, SVG or CSS animations an agent wrote itself. The document must carry everything inline: every request it makes (fetch, images, fonts, frames, sockets, navigations) is refused and counted; data: and blob: URLs it builds itself work. A script error while loading, a missing renderAt or a renderAt that throws answers 400. Limits: html up to 512 KB, 1 to 12 times, width up to 1280 and height up to 720 (default 640x360), 5 s per renderAt and 25 s for loading and every renderAt together, 8 MB of PNG output in all. Deterministic code, no model. Body: {"html":"<!doctype html>…","times":[0,0.5,1],"width":640?,"height":360?}.

Category: Web & documentsTags: browser html render frames animation png canvas contact-sheet

Try in playground →

Parameters

NameTypeRequiredDescription
htmlstringyesA self-contained HTML document (max 512 KB) that defines window.renderAt(t); it may return a promise Also accepted as content, body, markup, text, source.
timesarray of numberyes1 to 12 times in seconds (0 to 3600), one still each
widthintegernoViewport width in px, 16 to 1280 (default 640)
heightintegernoViewport height in px, 16 to 720 (default 360)

Example request

curl -i -X POST https://agent402.tools/api/html-frames \
  -H "Content-Type: application/json" \
  -d '{"html":"<!doctype html><html><body style=\"margin:0\"><canvas id=\"c\" width=\"320\" height=\"180\"></canvas><script>const x=document.getElementById('\''c'\'').getContext('\''2d'\'');window.renderAt=function(t){x.fillStyle='\''#10243e'\'';x.fillRect(0,0,320,180);x.fillStyle='\''#4cc38a'\'';x.fillRect(20+t*100,70,40,40);};</script></body></html>","times":[0,1,2],"width":320,"height":180}'

Without payment this returns HTTP 402 Payment Required with the exact price for html-frames; any x402 v2 or MPP client pays it and retries.

Example response

{
  "width": 320,
  "height": 180,
  "frameCount": 3,
  "frames": [
    {
      "t": 0,
      "bytes": 645,
      "pngBase64": "iVBORw0KGgo…"
    },
    {
      "t": 1,
      "bytes": 645,
      "pngBase64": "iVBORw0KGgo…"
    },
    {
      "t": 2,
      "bytes": 644,
      "pngBase64": "iVBORw0KGgo…"
    }
  ],
  "contactSheet": {
    "columns": 2,
    "rows": 2,
    "width": 664,
    "height": 420,
    "bytes": 3282,
    "pngBase64": "iVBORw0KGgo…"
  },
  "totalBytes": 5216,
  "network": {
    "blockedRequests": 0,
    "policy": "all network access refused; only inline script and style, and data: or blob: URLs the document builds itself"
  }
}
FieldTypeAlways presentIn the example
widthnumberyes320
heightnumberyes180
frameCountnumberyes3
framesarray of objectsyes3 items in the example
contactSheetobjectyes6 fields: columns, rows, width, height, bytes, pngBase64
totalBytesnumberyes5216
networkobjectyes2 fields: blockedRequests, policy

From an MCP client

catalog.call {
  "slug": "html-frames",
  "params": {
    "html": "<!doctype html><html><body style=\"margin:0\"><canvas id=\"c\" width=\"320\" height=\"180\"></canvas><script>const x=document.getElementById('c').getContext('2d');window.renderAt=function(t){x.fillStyle='#10243e';x.fillRect(0,0,320,180);x.fillStyle='#4cc38a';x.fillRect(20+t*100,70,40,40);};</script></body></html>",
    "times": [
      0,
      1,
      2
    ],
    "width": 320,
    "height": 180
  }
}

The hosted connector at https://agent402.tools/mcp needs a payment for html-frames; the stdio package pays it from a wallet or from an AGENT402_CREDITS_KEY issued earlier. Local install: npx -y agent402-mcp.

Errors and behavior

Paid call (JavaScript agent)

import { wrapFetchWithPayment } from "@x402/fetch";
import { x402Client } from "@x402/core/client";
import { registerExactEvmScheme } from "@x402/evm/exact/client";
import { privateKeyToAccount } from "viem/accounts";

const client = new x402Client();
client.setSpendControls?.({ maxAmountPerPayment: "$0.02" }); // refuse any quote above this tool's price
registerExactEvmScheme(client, { signer: privateKeyToAccount(KEY) });
const payFetch = wrapFetchWithPayment(fetch, client);

const res = await payFetch("https://agent402.tools/api/html-frames", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    "html": "<!doctype html><html><body style=\"margin:0\"><canvas id=\"c\" width=\"320\" height=\"180\"></canvas><script>const x=document.getElementById('c').getContext('2d');window.renderAt=function(t){x.fillStyle='#10243e';x.fillRect(0,0,320,180);x.fillStyle='#4cc38a';x.fillRect(20+t*100,70,40,40);};</script></body></html>",
    "times": [
      0,
      1,
      2
    ],
    "width": 320,
    "height": 180
  }),
});

Related tools

Screenshot

$0.004 · GET /api/screenshot

Screenshot any public URL in headless Chromium.

HTML links

FREE w/ compute · or $0.001 · POST /api/html-links

Enumerate every <a href> in an HTML string with its anchor text and rel attribute.

HTML meta (from string)

FREE w/ compute · or $0.001 · POST /api/html-meta

Extract <title>, <meta description>, OpenGraph/Twitter cards, canonical URL, and JSON-LD blocks from an HTML string.

HTML select

FREE w/ compute · or $0.001 · POST /api/html-select

Run a CSS selector against an HTML string and return the matches (text, attrs, and optionally outerHTML for each).

HTML strip to text

FREE w/ compute · or $0.001 · POST /api/html-strip

Strip all HTML tags and return plain text.

HTML table to JSON/CSV

FREE w/ compute · or $0.001 · POST /api/html-table

Extract a <table> from an HTML string as JSON rows (header-keyed) or CSV.