Framejet

The screenshot API, explained

How server-side page capture actually works, why the results are so often unusable, and what to do about it.

What a screenshot API is

A screenshot API is an HTTP endpoint that runs a real browser on a server, points it at a URL you give it, and hands back the rendered page as an image. You send a URL, you get a PNG.

The reason to buy one rather than build one is not the screenshot. It is everything around it: keeping a headless Chrome binary alive, giving it enough memory to render a heavy page, stopping one slow target from blocking every other request, and doing that on hardware you are not paying for while it sits idle. The capture is a few lines. The operations are the product.

This is the failure that sends most people looking for a second provider, so it is worth being precise about the cause.

A headless browser is a first-time visitor. It has no cookies, no local storage and no consent record. Every consent platform is built to interrupt exactly that visitor, so a naive capture of a European news site returns a dark overlay and an Accept button, with the content you wanted greyed out behind it. Sticky headers eat the top of the frame and a live-chat bubble sits in the bottom-right corner of every single image.

Cropping does not fix it: the overlay is in the middle of the page and the content behind it is dimmed and often scroll-locked. Clicking Accept is worse — you are recording consent on behalf of someone who never gave it, once per capture.

The workable answer is to remove the overlay from the DOM before the capture, and to unstick whatever is fixed to the viewport. That is what Framejet calls clean mode, and it runs by default rather than behind a flag you have to remember. You turn it off with clean=false when you want the page exactly as a visitor would meet it.

Making the call

The response body is the image itself, not a JSON envelope with a link you have to fetch afterwards. That means you can pipe it straight to a file, or hand the URL to an <img> tag.

curl -o shot.png "https://framejet.dev/v1/take?key=YOUR_KEY&url=https://example.com&full_page=true"

Full reference, including every parameter and error code, is on the docs page.

The parameters that actually matter

ParameterWhy you would reach for it
full_pageCapture the whole scroll height instead of one viewport. Height is then decided by the content, so height is ignored.
widthThe viewport width the page believes it is rendering into, 320–3840. This is how you get a mobile-layout capture: set a narrow width, not a small image.
dprDevice pixel ratio, 1–3. Set 2 for a retina-resolution image at the same layout width.
delayExtra wait after load, up to 10 seconds. The escape hatch for pages that animate in or fetch their content after first paint.
cacheSet false when you are monitoring a page for change and a cached answer would defeat the point.

Screenshots for AI agents and vision models

This is newer than the rest of the category and worth separating out. When a vision model reads a page capture, an overlay is not a cosmetic problem — it is the model's answer. A consent wall covering the article means the model describes the consent wall.

Framejet exposes the same capture engine as a remote Model Context Protocol server at https://framejet.dev/mcp. An agent authenticates with the same API key as a bearer token, calls one screenshot tool, and gets the image inline. It draws from the same monthly quota as your REST calls, so there is no second account to manage. Setup is on the docs page.

What it costs to run, and how that reaches your bill

A capture is a browser launch, a page load and an image encode. The page load is the part that varies wildly — a static page is a few hundred milliseconds, a heavy application can be several seconds. Two billing details follow from that, and they are worth checking on any provider you evaluate:

  • Repeats. The same URL with the same parameters is the same image. Framejet serves it from cache and does not meter it.
  • Failures. A timeout produced no image, so Framejet spends no credit on it. You pay for pixels you actually received.

Neither of these is unique to Framejet, and you should confirm both with whoever you buy from — the sourced comparisons are at vs ScreenshotOne, vs Urlbox and vs ApiFlash.

When a capture fails

Four things account for nearly every failure, and knowing which one you hit saves an afternoon:

What you seeWhat happened
target_timeoutThe page never finished loading. Often a third-party script that never resolves — try a shorter target or a delay.
blocked_targetThe URL resolves to a private or internal address. Refused on purpose: a capture service that fetches internal addresses is a way into your network.
bad_urlNot an http or https URL, or not a URL at all.
A blank or half-rendered imageThe page painted after the capture. This is what delay exists for.

Questions

What is a screenshot API?
A screenshot API is an HTTP endpoint that renders a web page in a real browser on a server and returns the result as an image. You send a URL, it sends back a PNG or JPEG. It exists so you do not have to run and scale headless Chrome yourself, which is the expensive and fragile part.
Why do screenshots come back with a cookie banner over them?
Because a consent wall is part of the page the browser loaded. Anything that automates a real browser sees what a first-time visitor sees, and a first-time visitor gets the banner. Framejet removes cookie and consent overlays, sticky headers and live-chat bubbles before the capture, and that behaviour is on by default rather than behind a flag.
How do I take a screenshot of a website with an API call?
Send a GET request to /v1/take with your key and the target URL, and write the response body to a file. With curl that is a single line, and the response is the image bytes themselves, not a JSON wrapper with a link to fetch afterwards.
Can I capture the whole page, not just the visible part?
Yes. Pass full_page=true and the capture covers the entire scroll height instead of one viewport. When full_page is set the height parameter is ignored, because the page's own content decides the height.
Can an AI agent take screenshots?
Yes. Framejet is also a remote Model Context Protocol server at /mcp, so an agent such as Claude or Cursor can call a screenshot tool directly. It authenticates with the same API key as a bearer token and draws from the same monthly quota as your REST calls, so there is no second account and no second integration.
Do failed screenshots cost me anything?
No. If a capture times out, the target is unreachable, or something breaks on our side, no credit is spent. You are only metered for captures that return an image.
Are repeated screenshots of the same URL charged twice?
No. A repeat capture of the same URL and the same parameters is served from cache and does not count against your quota. Pass cache=false when you specifically want a fresh capture, and that one is metered.
Is there a free screenshot API?
Framejet gives you 200 screenshots a month for free, with no credit card and no expiry. That is enough to build a feature and ship it before deciding whether to pay.
What image formats are supported?
PNG by default and JPEG on request, at a device pixel ratio between 1 and 3 so you can produce retina-resolution captures. Viewport width can be set between 320 and 3840 pixels.
Can I screenshot a page behind a login?
No. Framejet captures publicly reachable pages only. Requests to private, internal or link-local addresses are refused, which is a deliberate safety limit rather than a missing feature.
200 screenshots a month, free. No credit card, and a failed capture never spends one. Get a key and paste the curl line above.