GET /v1/screenshot
GET /v1/screenshot is the screenshot API as a URL. Put the options in the query string and the response is the image itself, so the link works anywhere a browser or crawler loads an image: <img src>, og:image, Markdown, a spreadsheet. It accepts the common options under flat names. For everything else, use POST /v1/screenshot. Both are part of the API documentation.
GET https://api.renderscreenshot.com/v1/screenshot?url=...&preset=og_card
Authentication
| Method | How | Use it for |
|---|---|---|
| Bearer header | Authorization: Bearer rs_live_... |
Server-side calls. The key stays out of URLs and logs. |
| Query parameter | api_key=rs_live_... |
Quick tests in a terminal or browser. Never in public HTML. |
| Signed URL | key_id, expires, signature |
Any URL that the public will see. |
Query parameters
Each name maps to a field of the POST body. The parameters overview gives the full POST list.
| Parameter | Maps to | Type | Default and limits |
|---|---|---|---|
url |
url |
string | Required unless html is set. http or https only. |
html |
html |
string | Raw HTML to render. Prefer POST for long documents. |
preset |
preset |
string | For example og_card, twitter_card, full_page. See presets. |
device |
viewport.device |
string | A device ID from GET /v1/devices |
width |
viewport.width |
integer | 1280. 1 to 7680. |
height |
viewport.height |
integer | 800. 1 to 4320. |
scale |
viewport.scale |
number | 1. 1 to 3. |
full_page |
capture.mode = full_page |
boolean | Only the word true turns it on |
format |
output.format |
string | png (default), jpeg, webp, pdf |
quality |
output.quality |
integer | 80. 1 to 100, JPEG and WebP only. |
delay |
wait.delay |
integer (ms) | 0. Capped at 10000. |
timeout |
wait.timeout |
integer (s) | 30. Maximum 60. |
click |
page.click |
string | CSS selector clicked before capture |
hide |
page.hide |
string | Comma-separated selectors. They keep their space. |
remove |
page.remove |
string | Comma-separated selectors. The layout closes up. |
block_ads |
block.ads |
boolean | false |
block_cookies |
block.cookie_banners |
boolean | false |
dark_mode |
browser.dark_mode |
boolean | Page default. true or false forces a scheme. |
user_agent |
browser.user_agent |
string | Browser default |
locale |
browser.locale |
string | en-US. BCP 47. |
timezone |
browser.timezone |
string | IANA name, for example Europe/Paris |
cache_ttl |
cache.ttl |
integer (s) | 86400. 3600 to 2592000. |
cache_available |
cache.available |
boolean | false. Reuse an identical earlier render for 0 credits. |
cache_refresh |
cache.refresh |
boolean | false. Force a fresh render. |
pdf_paper |
pdf.paper |
string | letter. a0 to a6, letter, legal, tabloid. |
pdf_landscape |
pdf.landscape |
boolean | false |
pdf_print_background |
pdf.print_background |
boolean | true |
pdf_scale |
pdf.scale |
number | 1.0. 0.1 to 2.0. |
pdf_margin, pdf_margin_top, pdf_margin_right, pdf_margin_bottom, pdf_margin_left |
pdf.margin* |
string | CSS units, for example 1cm |
pdf_width, pdf_height |
pdf.width, pdf.height |
string | CSS units. Override pdf_paper. |
pdf_fit_one_page, pdf_prefer_css_page_size |
pdf.* |
boolean | false |
pdf_page_ranges |
pdf.page_ranges |
string | For example 1-5, 8 |
pdf_header, pdf_footer |
pdf.header, pdf.footer |
string | HTML templates |
Waiting for a selector, injected scripts and styles, cookies, headers, target authentication, element capture and resizing have no GET name. Send those with POST.
Build the URL with an encoder
The target URL is itself a URL, so it must be encoded as a value. Let a library do it. All three builders below print the same query string. Tested on 2026-10-15 with Node 22.18, Python 3.14 and Ruby 4.0. We parsed each result with the same query parser the API uses and got the full target URL back.
Node.js
const params = new URLSearchParams({ url: 'https://example.com/search?q=dark mode&page=2#results', preset: 'og_card', format: 'webp', block_cookies: 'true', api_key: process.env.RS_API_KEY, // server-side only; use a signed URL in public HTML }); console.log(`https://api.renderscreenshot.com/v1/screenshot?${params}`);
Python
import os from urllib.parse import urlencode params = { 'url': 'https://example.com/search?q=dark mode&page=2#results', 'preset': 'og_card', 'format': 'webp', 'block_cookies': 'true', 'api_key': os.environ['RS_API_KEY'], # server-side only; use a signed URL in public HTML } print('https://api.renderscreenshot.com/v1/screenshot?' + urlencode(params))
Ruby
require 'uri' params = { url: 'https://example.com/search?q=dark mode&page=2#results', preset: 'og_card', format: 'webp', block_cookies: 'true', api_key: ENV.fetch('RS_API_KEY') # server-side only; use a signed URL in public HTML } puts "https://api.renderscreenshot.com/v1/screenshot?#{URI.encode_www_form(params)}"
curl
curl --get https://api.renderscreenshot.com/v1/screenshot \ -H "Authorization: Bearer $RS_API_KEY" \ --data-urlencode 'url=https://example.com/search?q=dark mode&page=2#results' \ -d preset=og_card -d format=webp \ --output screenshot.webp
Encoding pitfalls
We parsed the unencoded version of the URL above the same way. The API saw the target https://example.com/search?q=dark mode, with no page=2, and no preset or api_key at all. These are the mistakes behind that result and a few quieter ones:
&in the target splits it. Unencoded,&page=2becomes a parameter of the API call, not of your page.#ends the query string. Browsers never send the fragment, so everything after#is lost, including any API parameters you put after the target.+means a space. A literal plus in the target, as in?tags=a+b, must be sent as%2B.- Booleans are words. Only
trueturns an option on.block_ads=1orblock_ads=yesis ignored without an error. - Commas split
hideandremove. A selector such as:is(.a, .b)is cut in two. Use POST with an array. - Unknown formats are rejected. A
formatvalue outsidepng,jpeg,webpandpdfreturns HTTP 400 withinvalid_format. &in HTML attributes. Inside an<img src>orcontent=""attribute, write&as&. Browsers and crawlers decode it back. Template engines that escape output do this for you.- Never edit a signed URL. Adding
&format=webpafter signing breaks the signature. Add every parameter before you sign.
The signed variant
A signed GET URL has the same parameters plus key_id (your rs_pub_ public key ID) and expires, sorted alphabetically, then signature: the HMAC-SHA256 of everything before it, keyed with your rs_secret_ key. Signed URLs authenticate only this endpoint (GET, or HEAD, with no body); they do not work for POST /v1/screenshot or any other endpoint.
https://api.renderscreenshot.com/v1/screenshot?expires=1792644628&key_id=rs_pub_...&preset=og_card&url=https%3A%2F%2Fexample.com%2Fblog%2Fhello-world&signature=5c0f...
<meta property="og:image" content="https://api.renderscreenshot.com/v1/screenshot?expires=1792644628&key_id=rs_pub_...&preset=og_card&url=https%3A%2F%2Fexample.com%2Fblog%2Fhello-world&signature=5c0f...">
Signing code in six languages is on the signed URLs page.
Response
By default the body is the image or PDF, with Content-Type set to match. Send Accept: application/json to get JSON with the CDN URL instead. The headers carry X-Credits-Remaining, X-Cache-URL and X-Request-Id. See response headers and caching.
Errors
In an <img> tag a failed request shows as a broken image, and the browser hides the reason. Open the same URL with curl to read it:
curl -i "https://api.renderscreenshot.com/v1/screenshot?url=example.com&api_key=$RS_API_KEY"
{ "error": { "type": "validation_error", "code": "invalid_url", "message": "The URL 'example.com' is not a valid HTTP(S) URL", "param": "url", "retryable": false, "docs": "https://renderscreenshot.com/docs/errors/invalid-url" }, "request_id": "7a2e4c10-93b5-4d6f-8e1a-0b9c3d5f7e21" }
| Status | Typical cause on GET | Fix |
|---|---|---|
400 invalid_url |
The scheme is missing, or the target was not encoded | Send https://... and encode the value |
400 invalid_cache_ttl |
cache_ttl below 3600 or above 2592000 |
Use a value inside the range |
401 missing_credentials |
No api_key, a revoked key, or a signed URL with an unknown key_id |
Check the key. See API keys. |
401 invalid_signature |
The signed URL was changed after signing | Re-sign with every parameter included |
422 screenshot_failed |
The page did not render. The cause is in message. |
See error codes |
Examples
Full page, ads and cookie banners blocked, WebP:
https://api.renderscreenshot.com/v1/screenshot?url=https%3A%2F%2Fexample.com&full_page=true&block_ads=true&block_cookies=true&format=webp&api_key=rs_live_...
A4 PDF with backgrounds and 1 cm margins:
https://api.renderscreenshot.com/v1/screenshot?url=https%3A%2F%2Fexample.com&format=pdf&pdf_paper=a4&pdf_print_background=true&pdf_margin=1cm&api_key=rs_live_...
Dark mode in French, reuse a render from the last 24 hours if there is one:
https://api.renderscreenshot.com/v1/screenshot?url=https%3A%2F%2Fexample.com&dark_mode=true&locale=fr-FR&cache_available=true&api_key=rs_live_...
Last verified 2026-10-15 against the API's query parameter mapping.