GuidesCLI

How to Screenshot a Website from the Command Line

Jun 13, 2026 · 4 min read · ScreenshotInk

Sometimes you just need a PNG of a webpage from a script. A CI job that attaches a render of the deploy preview to every build. A cron task that snapshots a status dashboard every morning. A monitoring check that grabs the marketing homepage so you can eyeball it later. None of that should require installing Chromium, wiring up Puppeteer, or babysitting a headless browser on a build agent.

The whole thing is one HTTP request. You hand a URL to the API, it drives a real browser on its side, and you get an image back. Below are the patterns I reach for, from a single curl line to small Node and Python snippets you can drop into a script.

One cURL call

The endpoint is https://screenshotink.com/v1/capture. Pass it a URL and a format, authenticate with a bearer token, and you get JSON back with a link to the rendered image:

curl "https://screenshotink.com/v1/capture" \
  -H "Authorization: Bearer sk_live_…" \
  -d url="https://github.com" -d format=png

The response looks like this:

{ "image_url": "https://screenshotink.com/i/9f2a…png" }

That image_url is a hosted copy of the capture. You can open it, embed it, or download it. For a one-off check this is all you need.

Save the image straight to disk

Most of the time you don't want the JSON — you want a file on disk. Pipe the response through jq to pull out image_url, then hand that to a second curl to download the bytes:

curl -s "https://screenshotink.com/v1/capture" \
  -H "Authorization: Bearer sk_live_…" \
  -d url="https://github.com" -d format=png \
| jq -r '.image_url' \
| xargs curl -s -o github.png

echo "saved github.png"

-s keeps curl quiet, jq -r prints the raw URL without quotes, and xargs feeds it to the download call. Swap github.png for whatever filename your script needs — a timestamp, a build number, a commit SHA.

A reusable shell function

If you do this often, wrap it in a shell function and drop it in your .bashrc or .zshrc. Pass a URL, get a file named after the host:

shot() {
  local url="$1"
  local name="${2:-$(echo "$url" | sed -E 's#https?://##; s#/.*##').png}"
  curl -s "https://screenshotink.com/v1/capture" \
    -H "Authorization: Bearer $SCREENSHOTINK_KEY" \
    -d url="$url" -d format=png \
  | jq -r '.image_url' \
  | xargs curl -s -o "$name"
  echo "saved $name"
}

Put your token in SCREENSHOTINK_KEY once (export SCREENSHOTINK_KEY=sk_live_…) and then it's just:

shot https://github.com
shot https://news.ycombinator.com hn.png

In a script (Node / Python)

Inside a real program you'll usually skip the shell entirely. Here's the same call in Node, writing the file with fetch (built in since Node 18):

const res = await fetch("https://screenshotink.com/v1/capture", {
  method: "POST",
  headers: {
    "Authorization": "Bearer sk_live_…",
    "Content-Type": "application/x-www-form-urlencoded",
  },
  body: new URLSearchParams({ url: "https://github.com", format: "png" }),
});

const { image_url } = await res.json();
const img = await fetch(image_url);
await Bun.write?.("github.png", img) ??
  require("fs").writeFileSync("github.png", Buffer.from(await img.arrayBuffer()));

And in Python with requests:

import requests

res = requests.post(
    "https://screenshotink.com/v1/capture",
    headers={"Authorization": "Bearer sk_live_…"},
    data={"url": "https://github.com", "format": "png"},
)
image_url = res.json()["image_url"]

img = requests.get(image_url)
with open("github.png", "wb") as f:
    f.write(img.content)

Both follow the same two-step shape as the shell version: post the capture request, read image_url from the JSON, fetch the bytes.

Useful options

The request takes a handful of parameters that cover the cases you'll actually hit:

A few things happen on their own so you don't have to script around them: lazy-loaded images are scrolled into view before the shot is taken, and common cookie-consent banners are dismissed automatically so they don't sit on top of your capture. Rendering runs on EU-hosted infrastructure. The free tier is 100 captures a month with no card required, which is plenty for a personal cron job or a small CI pipeline.

That's the whole surface. One endpoint, a token, a URL — everything else is just choosing where to write the file.

Prefer a UI? website screenshot tool.

Capture it with the API

Everything here runs on the ScreenshotInk API — 100 free captures a month, no card.

More guides

The Best Screenshot APIs in 2026, Compared

An honest comparison of the top screenshot APIs in 2026 — ScreenshotInk, ScreenshotOne, ApiFlash, Urlbox and more — on pricing, formats, tooling and AI-agent support.