Screenshot Markdown
Captures Markdown files, laid out by your own HTML page, as a PNG, JPEG or WebP image.
Capture the page
Upload an index.html that places each Markdown file with {{ toHTML "<name>" }}, the Markdown files and the page's assets, as on the Markdown conversion:
curl \
--request POST http://localhost:3000/forms/chromium/screenshot/markdown \
--form files=@index.html \
--form files=@notes.md \
--form files=@style.css \
-o notes.png
Pick the format
curl \
--request POST http://localhost:3000/forms/chromium/screenshot/markdown \
--form files=@index.html \
--form files=@notes.md \
--form files=@style.css \
--form format=jpeg \
--form quality=80 \
-o notes.jpeg
format takes png, the default, jpeg or webp. quality applies to JPEG.
Size the window
width and height set the browser window, in CSS pixels. clip keeps that window only, instead of the whole page:
curl \
--request POST http://localhost:3000/forms/chromium/screenshot/markdown \
--form files=@index.html \
--form files=@notes.md \
--form files=@style.css \
--form width=1280 \
--form height=720 \
--form clip=true \
-o notes.png
Without them, the image is 800 pixels wide and as tall as the page.
Capture one element
curl \
--request POST http://localhost:3000/forms/chromium/screenshot/markdown \
--form files=@index.html \
--form files=@notes.md \
--form files=@style.css \
--form selector=h1 \
-o notes.png
The image takes the bounds of the first element the CSS selector matches. No visible match answers 400.
Sharpen it
deviceScaleFactor sets the image pixels per CSS pixel. At 2, an 800 by 600 window gives a 1600 by 1200 image:
curl \
--request POST http://localhost:3000/forms/chromium/screenshot/markdown \
--form files=@index.html \
--form files=@notes.md \
--form files=@style.css \
--form deviceScaleFactor=2 \
--form clip=true \
-o notes.png
Drop the background
omitBackground leaves the white default background out, so a PNG stays transparent where the page paints nothing:
curl \
--request POST http://localhost:3000/forms/chromium/screenshot/markdown \
--form files=@index.html \
--form files=@notes.md \
--form files=@style.css \
--form omitBackground=true \
-o notes.png
Screenshots take no stages: a request with it answers 400. To render a PDF's pages as images, see the render stage.
Wait for the page
Scripts run, unless the operator turned them off with --chromium-disable-javascript. Chromium captures the page as soon as it loads, though. A page that draws later with JavaScript, such as a chart or a table filled from an API, needs a wait. The examples upload this page, whose chart draws a second after it loads, to the HTML route; the fields work the same on every Chromium route:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Sales report</title>
</head>
<body>
<h1>Sales report</h1>
<div id="chart">Loading…</div>
<script>
// Stands in for a chart that draws once its data arrives.
setTimeout(() => {
const chart = document.getElementById("chart");
chart.textContent = "Revenue: 42,000 EUR";
chart.className = "ready";
window.chartReady = true;
window.status = "ready";
}, 1000);
</script>
</body>
</html>
Without a wait, the result reads "Loading…":
curl \
--request POST http://localhost:3000/forms/chromium/screenshot/html \
--form files=@index.html \
-o report.png
Each wait below gets "Revenue: 42,000 EUR" instead.
Wait for an element
Chromium waits until an element matching the CSS selector is visible:
curl \
--request POST http://localhost:3000/forms/chromium/screenshot/html \
--form files=@index.html \
--form waitForSelector=#chart.ready \
-o report.png
Mark the page ready from your own code, and wait for the mark. It's the most precise signal.
Wait for an expression
Chromium evaluates the JavaScript expression until it returns true:
curl \
--request POST http://localhost:3000/forms/chromium/screenshot/html \
--form files=@index.html \
--form 'waitForExpression=window.chartReady === true' \
-o report.png
An expression that throws, such as one that reads a property of undefined, answers 400.
Wait for the window status
Chromium waits until window.status equals the value:
curl \
--request POST http://localhost:3000/forms/chromium/screenshot/html \
--form files=@index.html \
--form waitForWindowStatus=ready \
-o report.png
Wait a fixed delay
curl \
--request POST http://localhost:3000/forms/chromium/screenshot/html \
--form files=@index.html \
--form waitDelay=2s \
-o report.png
A delay is the last resort. Too short, the chart is missing. Too long, every request pays for it.
Wait for the network
skipNetworkIdleEvent=false waits until the page stops making requests, for pages that fetch their content once they load:
curl \
--request POST http://localhost:3000/forms/chromium/screenshot/url \
--form url=https://example.com \
--form skipNetworkIdleEvent=false \
-o example.png
Order and limits
Chromium waits for the page to load, then for waitForWindowStatus, waitForExpression, waitForSelector and waitDelay, in that order. Every wait counts against --api-timeout, 30 seconds by default. A wait that never ends answers 503 Service Unavailable then, and names itself:
The selector '#never' (waitForSelector) did not become visible within the time limit. Increase it with --api-timeout (API_TIMEOUT), or check the selector.
waitDelay must be shorter than --api-timeout. A longer one answers 400 right away, and names the flag:
Invalid form data: form field 'waitDelay' is invalid (got '60s', must be shorter than the API timeout of 30s: raise --api-timeout (API_TIMEOUT) or lower the delay)