# CurlShot: everything in one file
> Paste a website address and get a screenshot of the whole page as an image or PDF. Free to try, nothing to install. For developers, one simple screenshot API.
This file holds what CurlShot does (one section per task), its prices, the questions people ask, every page of the docs and every reference article. The short map is at https://curlshot.com/llms.txt and the OpenAPI description at https://curlshot.com/openapi.json.
---
Source: https://curlshot.com/tools/full-page-screenshot
# Take a full-page screenshot of any website
> Take a screenshot of a whole web page, from the top to the very bottom, as one image. Paste the address, nothing to install. Also available as an API.
To take a screenshot of a whole web page, paste its address into CurlShot and press the button. CurlShot opens the page in a real browser, scrolls it from top to bottom so every image loads, and gives you one tall image of the entire page. Nothing to install, and no browser extension.
Do it in the browser, free and without an account: https://curlshot.com/tools/full-page-screenshot

## How to take a full-page screenshot in three steps
1. Copy the address of the page from the bar at the top of your browser and paste it into the box.
2. Keep "Whole page" selected. Choose a computer, phone or tablet view.
3. Press "Take the screenshot", then download the image.
## How tall a full-page screenshot can be
A full-page screenshot follows the page down to its last pixel, but some pages never end: news feeds and shop listings keep adding content as you scroll. So a capture stops at a maximum height and still gives you a valid image.
Four options decide how far the capture goes and what it shows on the way.
| Option | Default | What it does |
| --- | --- | --- |
| full_page | false | true captures from the top to the bottom, not only the first screen. |
| full_page_scroll | true | Scrolls through the page first, so images that load on scroll are in the picture. |
| full_page_max_height | 20,000 px | Cuts the capture off at this height. Up to 30,000 px; your plan can set a lower maximum. |
| hide_selectors | none | Hides sticky headers and floating bars that would otherwise land in odd places down the page. |
- A full-page screenshot counts as one screenshot, however tall it is.
- For a very long page, ask for format=jpeg or format=webp: a tall PNG gets large quickly.
- A PDF always covers the whole page, so full_page is not needed with format=pdf.
## What people use it for
- Keep a record of how a page looked on a certain day
- Send a whole page to a client or a colleague as one file
- Save a long article, a price list or terms before they change
- Review a design from top to bottom without scrolling
## The same thing with the API
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://example.com&full_page=true" \
--output page.png
```
An access key is free: https://curlshot.com/register. Read more:
- [Full-page screenshots](https://curlshot.com/docs/full-page.md)
- [Waiting and timing](https://curlshot.com/docs/waiting.md)
## Questions
### How do I screenshot an entire web page, not only the part I see?
Paste the page address into CurlShot and keep "Whole page" selected. The screenshot covers the page from the top to the bottom, including everything you would have to scroll to see.
### Do images further down the page appear in the screenshot?
Yes. Many pages load images only when you scroll to them. CurlShot scrolls through the page first so those images load, then takes the screenshot.
### Is there a limit to how tall the page can be?
Yes. Very long pages are cut off at a maximum height so the image stays a usable size. The limit is higher on paid plans, and with the API you set it yourself with the full_page_max_height option.
### Is it free?
You can try it on this page without an account. A free account adds a monthly allowance of screenshots and keeps them in one place.
## Related
- [Web page to PDF](https://curlshot.com/tools/website-to-pdf.md): Turn a web page into a PDF document from its address. Real pages, working links and selectable text. Paste the address, nothing to install. Also an API.
- [Mobile screenshot](https://curlshot.com/tools/mobile-screenshot.md): See and screenshot any website as it looks on an iPhone, an Android phone or a tablet, without picking one up. Paste the address. Free to try, also an API.
- [Screenshot without cookie banners](https://curlshot.com/tools/screenshot-without-cookie-banners.md): Take a screenshot of any web page without the cookie banner: GDPR consent pop-ups and cookie notices are hidden before the capture. Free to try, also an API.
## Guides
- [Full-page screenshot on every device and browser](https://curlshot.com/blog/full-page-screenshot-every-device.md): Exact keys and menu names to screenshot a whole web page in Chrome, Firefox, Edge, Safari, iPhone, iPad and Android, checked against each vendor.
- [Why website screenshots look wrong, and the fixes](https://curlshot.com/blog/why-website-screenshots-look-wrong.md): A field guide to 11 ways a website screenshot goes wrong, from blank lazy images to cookie banners and cut-off pages, with the cause and the fix for each.
---
Source: https://curlshot.com/tools/website-to-pdf
# Save any web page as a PDF
> Turn a web page into a PDF document from its address. Real pages, working links and selectable text. Paste the address, nothing to install. Also an API.
To save a web page as a PDF, paste its address into CurlShot, choose PDF and press the button. You get a PDF document with real pages and selectable text that you can print, email or file. It works for articles, invoices, reports and any public page.
Do it in the browser, free and without an account: https://curlshot.com/tools/website-to-pdf

## How to save a web page as a PDF in three steps
1. Paste the address of the page into the box.
2. Choose "PDF" as the result.
3. Press "Take the screenshot", then download the PDF.
## Screen layout or print layout, many pages or one
A web page was not written for paper, so there are two choices to make. The first is which look of the page you want: the one you see in the browser, or the one the site designed for printing. The second is whether the page is cut into sheets of paper or kept as one long sheet.
This page is about pages that are already online. To make a PDF from your own HTML, such as an invoice template, see the HTML to PDF API.
| You want | Add to the request | What you get |
| --- | --- | --- |
| The page as it looks on screen | nothing (media_type=screen is the default) | Menus, colours and sidebars, as in the browser. |
| The site's own printable version | media_type=print | Usually no menus or sidebars, and wider text. Often the cleaner document. |
| A document for printing in the US | pdf_paper_format=letter | US Letter pages. A4 is the default. |
| No page breaks at all | pdf_fit_one_page=true | One page as tall as the content, for reading on a screen. |
| No cookie banner on page one | block_cookie_banners=true | The consent pop-up is hidden before the PDF is made. |
## What people use it for
- File an invoice, a receipt or an order confirmation
- Archive an article or a report as a document
- Print a page without the browser print dialog
- Attach a web page to an email
## The same thing with the API
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://example.com&format=pdf&pdf_paper_format=a4" \
--output page.pdf
```
An access key is free: https://curlshot.com/register. Read more:
- [PDF rendering](https://curlshot.com/docs/pdf.md)
- [Archive pages as PDF](https://curlshot.com/docs/guides/archive-pages-as-pdf.md)
## Questions
### How do I convert a URL to a PDF?
Paste the URL into CurlShot, choose PDF and press the button. Developers send one request: the screenshot address with format=pdf.
### Can I select and copy the text in the PDF?
Yes. The PDF is made by a real browser, the same way as its "Save as PDF", so the text stays text and links keep working.
### Can I choose the paper size?
With the API, yes: paper format, landscape, margins and whether backgrounds are printed are all options. There is also an option to fit the whole page on one long sheet.
### Is it free?
You can try it on this page without an account. A free account adds a monthly allowance of screenshots and keeps them in one place.
## Related
- [Full-page screenshot](https://curlshot.com/tools/full-page-screenshot.md): Take a screenshot of a whole web page, from the top to the very bottom, as one image. Paste the address, nothing to install. Also available as an API.
- [URL to image](https://curlshot.com/tools/url-to-image.md): Convert any URL into an image file. Paste a web address and download a PNG, JPEG or WebP screenshot of the page. Free to try, and one request by API.
- [Screenshot API](https://curlshot.com/tools/screenshot-api.md): A screenshot API for developers. One HTTP request turns a URL, HTML or Markdown into a PNG, JPEG, WebP or PDF. Full page, devices, blocking, cache, MCP.
## Guides
- [Web page to PDF: paper sizes, margins, print CSS](https://curlshot.com/blog/web-page-to-pdf-paper-sizes.md): Paper sizes in millimetres, inches, CSS pixels and points, how margins and page breaks work in a PDF of a web page, and the print CSS that controls them.
---
Source: https://curlshot.com/tools/url-to-image
# Turn any URL into an image
> Convert any URL into an image file. Paste a web address and download a PNG, JPEG or WebP screenshot of the page. Free to try, and one request by API.
To turn a URL into an image, paste the address into CurlShot and press the button. CurlShot loads the page in a real browser and returns a screenshot of it as an image file. On this page you download a JPEG; with the API you choose PNG, JPEG or WebP.
Do it in the browser, free and without an account: https://curlshot.com/tools/url-to-image

## How to turn a URL into an image in three steps
1. Paste the URL into the box.
2. Choose the whole page or just the top, and the screen size.
3. Press "Take the screenshot", then download the image.
## PNG, JPEG or WebP: which format to ask for
The page is drawn the same way whichever format you choose. Only the file is different: how large it is, whether it can be see-through, and how exact the pixels are.
| format | Transparent background | Quality setting | Best for |
| --- | --- | --- | --- |
| png (default) | Yes, with omit_background=true | No: every pixel is kept | Text, interfaces, flat colour, logos |
| jpeg | No | image_quality from 1 to 100, default 80 | Photos and long pages, attachments |
| webp | Yes, with omit_background=true | image_quality from 1 to 100, default 80 | Images shown on your own website |
- image_width and image_height resize the result, up to 8,000 px a side. Give one and the other follows the shape of the page; give both and the image is cropped to fill that box, keeping the top of the page.
- response_type=json returns a short JSON answer with a link to the file instead of the file itself.
- The same request with format=pdf returns a document instead of an image.
## What people use it for
- Put a screenshot of a website into a document or a slide
- Show a page in a chat or a ticket without sending a link
- Make an image of a page for a blog post or a newsletter
- Generate images of pages automatically from your own code
## The same thing with the API
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://example.com&format=webp&image_quality=80" \
--output page.webp
```
An access key is free: https://curlshot.com/register. Read more:
- [The screenshot URL](https://curlshot.com/docs/screenshot-url.md)
- [Options reference](https://curlshot.com/docs/options.md)
## Questions
### How do I convert a URL to a PNG or JPG?
Paste the URL into CurlShot and download the screenshot. With the API, add format=png, format=jpeg or format=webp to the request.
### Which image format should I pick?
PNG is exact and best for pages with text and flat colour. JPEG and WebP make much smaller files and are the better choice for long pages and photos.
### Can I get a smaller image, such as a thumbnail?
Yes. With the API, image_width and image_height resize the result, so you can ask for a 400 pixel wide thumbnail directly.
### Is it free?
You can try it on this page without an account. A free account adds a monthly allowance of screenshots and keeps them in one place.
## Related
- [Full-page screenshot](https://curlshot.com/tools/full-page-screenshot.md): Take a screenshot of a whole web page, from the top to the very bottom, as one image. Paste the address, nothing to install. Also available as an API.
- [Website thumbnail](https://curlshot.com/tools/website-thumbnail.md): Make a thumbnail or preview image of any website from its address. For directories, link lists, portfolios and newsletters. Free to try, one request by API.
- [HTML to image](https://curlshot.com/tools/html-to-image.md): Render your own HTML, CSS or Markdown into an image or a PDF with one API request. For social cards, certificates, receipts and reports.
## Guides
- [PNG, JPEG, WebP or PDF for website screenshots](https://curlshot.com/blog/png-jpeg-webp-pdf-for-screenshots.md): A decision flow, a comparison table and our own file-size measurements for choosing PNG, JPEG, WebP or PDF when you save a screenshot of a web page.
---
Source: https://curlshot.com/tools/mobile-screenshot
# Screenshot a website as a phone shows it
> See and screenshot any website as it looks on an iPhone, an Android phone or a tablet, without picking one up. Paste the address. Free to try, also an API.
To see how a website looks on a phone, paste its address into CurlShot and choose Phone. CurlShot opens the page with a phone-sized screen, the phone's pixel density and a mobile browser identity, so the site serves its mobile layout, and returns a screenshot of it. Tablet and computer views work the same way.
Do it in the browser, free and without an account: https://curlshot.com/tools/mobile-screenshot

## How to screenshot a website as a phone shows it in three steps
1. Paste the address of the website into the box.
2. Choose "Phone" or "Tablet".
3. Press "Take the screenshot", then download the image.
## Every phone you can pick, with its exact screen
Each phone preset sets the screen size, the pixel density, touch support and the browser identity of that phone in one option, viewport_device. The image is larger than the screen because of the density: a 393 × 852 screen at density 3 gives a 1,179 × 2,556 image.
The table shows the first screen. Add full_page=true to capture the phone layout down to the bottom.
| Device | viewport_device | Screen (CSS px) | Density | Image (px) |
| --- | --- | --- | --- | --- |
| iPhone SE | iphone_se | 375 × 667 | 2x | 750 × 1,334 |
| iPhone 12 | iphone_12 | 390 × 844 | 3x | 1,170 × 2,532 |
| iPhone 13 | iphone_13 | 390 × 844 | 3x | 1,170 × 2,532 |
| iPhone 13 mini | iphone_13_mini | 375 × 812 | 3x | 1,125 × 2,436 |
| iPhone 14 | iphone_14 | 390 × 844 | 3x | 1,170 × 2,532 |
| iPhone 14 Plus | iphone_14_plus | 428 × 926 | 3x | 1,284 × 2,778 |
| iPhone 14 Pro | iphone_14_pro | 393 × 852 | 3x | 1,179 × 2,556 |
| iPhone 14 Pro Max | iphone_14_pro_max | 430 × 932 | 3x | 1,290 × 2,796 |
| iPhone 15 | iphone_15 | 393 × 852 | 3x | 1,179 × 2,556 |
| iPhone 15 Plus | iphone_15_plus | 430 × 932 | 3x | 1,290 × 2,796 |
| iPhone 15 Pro | iphone_15_pro | 393 × 852 | 3x | 1,179 × 2,556 |
| iPhone 15 Pro Max | iphone_15_pro_max | 430 × 932 | 3x | 1,290 × 2,796 |
| iPhone 16 | iphone_16 | 393 × 852 | 3x | 1,179 × 2,556 |
| iPhone 16 Plus | iphone_16_plus | 430 × 932 | 3x | 1,290 × 2,796 |
| iPhone 16 Pro | iphone_16_pro | 402 × 874 | 3x | 1,206 × 2,622 |
| iPhone 16 Pro Max | iphone_16_pro_max | 440 × 956 | 3x | 1,320 × 2,868 |
| Pixel 5 | pixel_5 | 393 × 851 | 2.75x | ≈1,081 × ≈2,340 |
| Pixel 7 | pixel_7 | 412 × 915 | 2.625x | ≈1,082 × ≈2,402 |
| Pixel 8 | pixel_8 | 412 × 915 | 2.625x | ≈1,082 × ≈2,402 |
| Pixel 8 Pro | pixel_8_pro | 448 × 998 | 3x | 1,344 × 2,994 |
| Pixel 9 | pixel_9 | 412 × 923 | 2.625x | ≈1,082 × ≈2,423 |
| Pixel 9 Pro | pixel_9_pro | 410 × 914 | 3x | 1,230 × 2,742 |
| Galaxy S23 | galaxy_s23 | 360 × 780 | 3x | 1,080 × 2,340 |
| Galaxy S24 | galaxy_s24 | 360 × 780 | 3x | 1,080 × 2,340 |
| Galaxy S24 Ultra | galaxy_s24_ultra | 384 × 824 | 3x | 1,152 × 2,472 |
| Galaxy A54 | galaxy_a54 | 360 × 800 | 3x | 1,080 × 2,400 |
- Any viewport option you send yourself wins over the preset. device_scale_factor=1 keeps the phone layout in a much lighter file.
- viewport_landscape=true turns the phone on its side.
- No preset fits? Set viewport_width, viewport_height and viewport_mobile=true yourself.
- A preset changes how the page is drawn. It does not draw a phone body around the screenshot.
## What people use it for
- Check your own site on a phone without a phone at hand
- Show a client how their shop looks on mobile
- Compare the phone, tablet and computer layout of a page
- Catch a broken mobile layout after a change
## The same thing with the API
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://example.com&viewport_device=iphone_15_pro&full_page=true" \
--output phone.png
```
An access key is free: https://curlshot.com/register. Read more:
- [Devices](https://curlshot.com/docs/devices.md)
- [Dark mode and emulation](https://curlshot.com/docs/dark-mode-and-emulation.md)
## Questions
### How can I see what my website looks like on a phone?
Paste the address into CurlShot and choose Phone. You get a screenshot of the mobile version of the page, as a phone would show it.
### Which devices can I choose?
On this page: a phone, a tablet and a computer. The API has a list of named devices, including current iPhone, Pixel and iPad models and common laptop and desktop sizes, and you can also set any width and height yourself.
### Is this a real phone?
No. It is a real browser set up like the phone: the same screen size, pixel density, touch support and browser identity. That is what decides which layout a site serves, so the result matches what the phone shows for almost all sites.
### Is it free?
You can try it on this page without an account. A free account adds a monthly allowance of screenshots and keeps them in one place.
## Related
- [Full-page screenshot](https://curlshot.com/tools/full-page-screenshot.md): Take a screenshot of a whole web page, from the top to the very bottom, as one image. Paste the address, nothing to install. Also available as an API.
- [Website thumbnail](https://curlshot.com/tools/website-thumbnail.md): Make a thumbnail or preview image of any website from its address. For directories, link lists, portfolios and newsletters. Free to try, one request by API.
- [Screenshot API](https://curlshot.com/tools/screenshot-api.md): A screenshot API for developers. One HTTP request turns a URL, HTML or Markdown into a PNG, JPEG, WebP or PDF. Full page, devices, blocking, cache, MCP.
## Guides
- [Viewport sizes cheat sheet: phones to desktops](https://curlshot.com/blog/viewport-sizes-cheat-sheet.md): Viewport sizes in CSS pixels, screenshot sizes and device pixel ratios of iPhone, Pixel, Galaxy, iPad and laptop screens, drawn to scale, and the sizes to test.
- [Full-page screenshot on every device and browser](https://curlshot.com/blog/full-page-screenshot-every-device.md): Exact keys and menu names to screenshot a whole web page in Chrome, Firefox, Edge, Safari, iPhone, iPad and Android, checked against each vendor.
---
Source: https://curlshot.com/tools/screenshot-without-cookie-banners
# Screenshot a page without cookie banners or consent pop-ups
> Take a screenshot of any web page without the cookie banner: GDPR consent pop-ups and cookie notices are hidden before the capture. Free to try, also an API.
To screenshot a web page without its cookie banner, paste its address into CurlShot and keep "Hide ads and cookie pop-ups" switched on. CurlShot hides the cookie notice and the GDPR consent pop-up before it takes the screenshot, so the page itself is what you see, not a box asking you to accept.
Do it in the browser, free and without an account: https://curlshot.com/tools/screenshot-without-cookie-banners
## How to screenshot a page without the cookie banner in three steps
1. Paste the address of the page into the box.
2. Keep "Hide ads and cookie pop-ups" switched on.
3. Press "Take the screenshot", then download the image.
## When a banner still shows up, and what to do
block_cookie_banners covers the widely used consent tools. Some banners are home-made, appear late or are part of the page itself. Each of those has a fix that works on that one site.
| What you see | Why | Fix |
| --- | --- | --- |
| The banner appears a moment after the page loads | It is added by a script after the page is ready | Add a short delay, for example delay=2. The banner is hidden again after the wait. |
| A banner the switch does not recognise | A home-made or regional consent tool | hide_selectors with its CSS selector, for example hide_selectors=#consent |
| The capture must show a specific consent choice | The switch presses whichever button it finds | Set the consent cookie yourself with cookies, or press the right button with click. |
| A gap is left where the banner was | The page keeps room for it | Hide its container with hide_selectors, or add your own CSS with styles. |
| A newsletter or app pop-up | It is not a cookie banner | hide_selectors, or click on its close button. |
- To find a selector, open the page in your browser, right-click the banner and choose Inspect. Look for its id or class.
- block_ads, block_trackers and block_chats remove the other usual clutter, each with its own switch.
## What people use it for
- Screenshots for a presentation or a portfolio, without a consent box in the middle
- Clean previews of websites in a directory or a newsletter
- Records of a page where the content is what matters
- Monitoring a page without pop-ups changing the screenshot
## The same thing with the API
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://example.com&block_cookie_banners=true&full_page=true" \
--output clean.png
```
An access key is free: https://curlshot.com/register. Read more:
- [Blocking ads, cookie banners, trackers and chats](https://curlshot.com/docs/blocking.md)
- [Custom CSS, JavaScript and clicks](https://curlshot.com/docs/customize.md)
## Questions
### How do I take a screenshot without the cookie banner?
Use CurlShot with "Hide ads and cookie pop-ups" switched on. With the API, add block_cookie_banners=true to the request.
### Does it work on every website?
It works on most sites, not all. The common consent tools are covered. For a site with an unusual pop-up, the API can hide any element by its selector or click a button before the capture.
### Can it hide other things on the page?
Yes. The other blockers have their own switches, covered on the screenshot without ads page.
### Is it free?
You can try it on this page without an account. A free account adds a monthly allowance of screenshots and keeps them in one place.
## Related
- [Full-page screenshot](https://curlshot.com/tools/full-page-screenshot.md): Take a screenshot of a whole web page, from the top to the very bottom, as one image. Paste the address, nothing to install. Also available as an API.
- [URL to image](https://curlshot.com/tools/url-to-image.md): Convert any URL into an image file. Paste a web address and download a PNG, JPEG or WebP screenshot of the page. Free to try, and one request by API.
- [Screenshot without ads](https://curlshot.com/tools/screenshot-without-ads.md): Take a clean screenshot of any website with the ads blocked: ad networks, trackers and chat bubbles are removed before the capture. Free to try, also an API.
---
Source: https://curlshot.com/tools/website-thumbnail
# Make a thumbnail of any website
> Make a thumbnail or preview image of any website from its address. For directories, link lists, portfolios and newsletters. Free to try, one request by API.
To make a thumbnail of a website, paste its address into CurlShot and choose "Just the top". You get an image of the first screen of the page, which is what a preview needs. With the API you ask for the exact width you want, and repeat requests for the same page can come from the cache at no cost.
Do it in the browser, free and without an account: https://curlshot.com/tools/website-thumbnail
## How to make a thumbnail of a website in three steps
1. Paste the address of the website into the box.
2. Choose "Just the top".
3. Press "Take the screenshot", then download the image.
## Thumbnail sizes, and showing them on your own page
A thumbnail is the first screen of a page, made smaller. The page is drawn at full size in a 1280 × 1024 window, so it shows its desktop layout, and then the image is resized. image_width alone keeps the shape; image_width and image_height together crop to that box from the top.
| Use | Options | Image |
| --- | --- | --- |
| Card in a directory or link list | image_width=400 | 400 × 320 |
| The same card on retina screens | image_width=800 | 800 × 640 |
| A 16:9 tile | image_width=640&image_height=360 | 640 × 360, cropped from the top |
| A phone-shaped preview | viewport_device=iphone_15_pro&image_width=300 | The mobile layout, 300 wide |
| A wide desktop preview | viewport_width=1920&viewport_height=1080&image_width=480 | 480 × 270 |
- format=webp gives the smallest files for use on a website.
- cache=true serves repeat requests for the same thumbnail from storage, without counting them against your allowance. cache_ttl sets how long, up to 30 days.
- To put the screenshot address straight into an img tag, sign it. A signed link cannot be changed, so your access key cannot be reused for other pages.
A signed thumbnail in a web page:
```html
```
## What people use it for
- Preview images next to each site in a directory or a list of links
- Screenshots of client sites in a portfolio
- A screenshot of the linked page in a newsletter
- Previews of user-submitted links in your own product
## The same thing with the API
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://example.com&image_width=400&format=webp&cache=true" \
--output thumb.webp
```
An access key is free: https://curlshot.com/register. Read more:
- [Website previews](https://curlshot.com/docs/guides/website-previews.md)
- [Caching](https://curlshot.com/docs/caching.md)
## Questions
### How do I generate a thumbnail from a URL?
Paste the URL into CurlShot and choose "Just the top". With the API, add image_width to get the thumbnail at the size you need.
### Can I show the thumbnail directly in a web page?
Yes. The screenshot request is a normal web address, so it can be the source of an image. Use a signed link so your access key is not visible in the page.
### Do repeated views cost screenshots?
Not with the cache switched on. A cached screenshot is served again without counting against your allowance.
### Is it free?
You can try it on this page without an account. A free account adds a monthly allowance of screenshots and keeps them in one place.
## Related
- [URL to image](https://curlshot.com/tools/url-to-image.md): Convert any URL into an image file. Paste a web address and download a PNG, JPEG or WebP screenshot of the page. Free to try, and one request by API.
- [Mobile screenshot](https://curlshot.com/tools/mobile-screenshot.md): See and screenshot any website as it looks on an iPhone, an Android phone or a tablet, without picking one up. Paste the address. Free to try, also an API.
- [Screenshot API](https://curlshot.com/tools/screenshot-api.md): A screenshot API for developers. One HTTP request turns a URL, HTML or Markdown into a PNG, JPEG, WebP or PDF. Full page, devices, blocking, cache, MCP.
## Guides
- [PNG, JPEG, WebP or PDF for website screenshots](https://curlshot.com/blog/png-jpeg-webp-pdf-for-screenshots.md): A decision flow, a comparison table and our own file-size measurements for choosing PNG, JPEG, WebP or PDF when you save a screenshot of a web page.
---
Source: https://curlshot.com/tools/screenshot-api
# A screenshot API that is one HTTP request
> A screenshot API for developers. One HTTP request turns a URL, HTML or Markdown into a PNG, JPEG, WebP or PDF. Full page, devices, blocking, cache, MCP.
CurlShot is a website screenshot API. Send one HTTP request with the address of a page and get back a PNG, JPEG, WebP or PDF of it. It renders in a real browser, captures full pages, emulates phones and tablets, hides cookie banners and ads, and works from any language because it is a plain URL. There is a free plan, an OpenAPI description and an MCP server for AI agents.
Do it in the browser, free and without an account: https://curlshot.com/tools/screenshot-api

## How to use the screenshot API in three steps
1. Create a free account and copy your access key.
2. Build the request: the screenshot address, your key, and the URL of the page.
3. Fetch it and save what comes back. Add options as more words in the address.
## Everything one request can do
The API is one endpoint with 69 options, in 13 groups. Every option works the same in a GET query string and in a POST JSON body, and a misspelled option is never silently ignored: the answer names the option you probably meant.
| Group | What it controls | Options | For example |
| --- | --- | --- | --- |
| Source | What to render. Exactly one is required. | 3 | url, html, markdown |
| Output | File format, quality and size of the result. | 6 | format, image_quality, image_width |
| Viewport | The browser window the page is rendered in. | 6 | viewport_width, viewport_height, device_scale_factor |
| Capture | Which part of the page ends up in the image. | 8 | full_page, full_page_scroll, full_page_max_height |
| Waiting | When the page counts as ready. | 4 | wait_until, delay, timeout |
| Customize | Change how the page looks before the capture. | 7 | dark_mode, reduced_motion, media_type |
| Request | What the browser sends to the site. | 5 | user_agent, headers, cookies |
| Blocking | Remove ads, banners and other noise. | 6 | block_ads, block_trackers, block_cookie_banners |
| PDF | Options that apply when format is pdf. | 9 | pdf_paper_format, pdf_landscape, pdf_print_background |
| Video | Options that apply when format is mp4, webm or gif. | 6 | video_duration, video_max_duration, video_fps |
| Cache | Reuse a previous render instead of rendering again. | 3 | cache, cache_ttl, cache_key |
| Async and webhooks | Render in the background. | 3 | async, webhook_url, webhook_sign |
| Authentication | Who is making the request. | 3 | access_key, signature, expires |
## Limits at a glance
The limits of a single request. Your plan sets the monthly allowance, the rate per minute and how many renders run at once.
| What | Limit |
| --- | --- |
| Time for the page to load (timeout) | 1 to 90 seconds, default 30 |
| Extra wait after loading (delay) | Up to 30 seconds |
| Browser window | 100 to 3,840 px wide, 100 to 4,320 px tall |
| Pixel density | 1 to 3 |
| Full-page height | 20,000 px by default, up to 30,000 px |
| HTML or Markdown input | Up to 2 MB |
| Cache lifetime | 60 seconds to 30 days, default 4 hours |
| Scrolling video | 1 to 30 seconds |
| Bulk call | Up to 100 requests, on plans that include bulk |
## What people use it for
- Full-page and first-screen captures, as PNG, JPEG, WebP or PDF
- Device presets for phones, tablets and laptops
- Blocking of ads, cookie banners, trackers and chat widgets
- Response cache, signed links, async renders with webhooks, bulk requests
- HTML and Markdown input, for images made from your own templates
- An MCP server and an OpenAPI description, for AI agents and generated clients
## The same thing with the API
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://example.com&full_page=true&block_cookie_banners=true" \
--output example.png
```
An access key is free: https://curlshot.com/register. Read more:
- [Getting started](https://curlshot.com/docs/getting-started.md)
- [Options reference](https://curlshot.com/docs/options.md)
- [For AI agents](https://curlshot.com/docs/guides/ai-agents.md)
## Questions
### What is a screenshot API?
A service that takes screenshots of web pages for your code. You send the address of a page, it opens the page in a browser on its own servers and returns the image, so you do not run or maintain headless browsers yourself.
### Which languages does it work with?
Any language that can fetch a URL. The docs have complete samples for cURL, Node.js, Python, PHP, Go and Ruby. There is nothing to install.
### How is usage counted?
One successful render is one screenshot, whatever its size. Failed renders and cache hits are not counted. Each plan is a fixed number of screenshots a month for a fixed price.
### Can an AI agent use it?
Yes. CurlShot has an MCP server with a take_screenshot tool, an OpenAPI description and an llms.txt file, so an agent can look at any web page.
## Related
- [Full-page screenshot](https://curlshot.com/tools/full-page-screenshot.md): Take a screenshot of a whole web page, from the top to the very bottom, as one image. Paste the address, nothing to install. Also available as an API.
- [Web page to PDF](https://curlshot.com/tools/website-to-pdf.md): Turn a web page into a PDF document from its address. Real pages, working links and selectable text. Paste the address, nothing to install. Also an API.
- [HTML to image](https://curlshot.com/tools/html-to-image.md): Render your own HTML, CSS or Markdown into an image or a PDF with one API request. For social cards, certificates, receipts and reports.
## Guides
- [Visual regression testing, explained in pictures](https://curlshot.com/blog/visual-regression-testing-guide.md): How screenshot comparison works, why visual tests go flaky and how to fix each cause, the tools, and a set-up checklist with a Playwright example.
---
Source: https://curlshot.com/tools/html-to-image
# Render HTML to an image with one request
> Render your own HTML, CSS or Markdown into an image or a PDF with one API request. For social cards, certificates, receipts and reports.
To turn HTML into an image, send it to CurlShot in a POST request and get back a PNG, JPEG, WebP or PDF. The HTML is rendered by a real browser, so web fonts, flexbox, grid and images work as they do on a web page. Markdown is accepted the same way. It is the simple way to make social sharing cards, certificates, receipts and reports from a template.
Page for people: https://curlshot.com/tools/html-to-image
## How to render HTML to an image in three steps
1. Write the HTML and CSS of the image, as you would for a web page.
2. Send it in a POST request, with the width and height you want.
3. Save the image that comes back, or let your code do it for every item.
## What works in the HTML you send
The HTML is drawn by the same browser that renders web pages, so you design an image the way you build a page. A few things differ, because your HTML arrives as text and has no address of its own.
| Feature | Works? | Note |
| --- | --- | --- |
| Flexbox, grid, gradients, shadows | Yes | Modern CSS renders as in a current browser. |
| Web fonts and images | Yes | Link them with a full https:// address. Relative paths and localhost do not load. |
| Transparent background | Yes | omit_background=true with png or webp, when your HTML sets no background. |
| Exact image size | Yes | viewport_width and viewport_height set the size of the image. |
| Sharper image | Yes | device_scale_factor=2 draws the same design with twice the pixels each way. |
| One element only | Yes | selector crops the image to one element of your HTML. |
| Input size | Up to 2 MB | Send it in a POST body, not in a query string. |
- Escape any text from users or your database before it goes into the HTML.
- Send exactly one source: html, markdown or url.
## What people use it for
- Open Graph and social sharing cards, one per article or product
- Certificates, tickets and badges with a name filled in
- Receipts, invoices and reports as PDF
- Charts and tables as an image for an email
## The same thing with the API
```bash
curl -X POST "https://curlshot.com/api/v1/screenshot" \
-H "X-Access-Key: YOUR_ACCESS_KEY" \
-H "Content-Type: application/json" \
-d '{"html":"
Hello
","viewport_width":1200,"viewport_height":630}' \
--output card.png
```
An access key is free: https://curlshot.com/register. Read more:
- [HTML and Markdown input](https://curlshot.com/docs/html-and-markdown.md)
- [Open Graph images](https://curlshot.com/docs/guides/open-graph-images.md)
## Questions
### How do I convert HTML to an image?
Send the HTML to CurlShot in the html field of a POST request. The answer is the image file. Set viewport_width and viewport_height to the size the image should have.
### Can I use my own fonts and images?
Yes. The HTML is rendered like a web page, so fonts and images referenced by a public address load normally.
### Can I get a PDF instead?
Yes. Add format=pdf. Paper size, margins and orientation are options.
### Does it take Markdown?
Yes. Send a markdown field instead of html and it is rendered as a clean, styled page.
## Related
- [Web page to PDF](https://curlshot.com/tools/website-to-pdf.md): Turn a web page into a PDF document from its address. Real pages, working links and selectable text. Paste the address, nothing to install. Also an API.
- [URL to image](https://curlshot.com/tools/url-to-image.md): Convert any URL into an image file. Paste a web address and download a PNG, JPEG or WebP screenshot of the page. Free to try, and one request by API.
- [Screenshot API](https://curlshot.com/tools/screenshot-api.md): A screenshot API for developers. One HTTP request turns a URL, HTML or Markdown into a PNG, JPEG, WebP or PDF. Full page, devices, blocking, cache, MCP.
## Guides
- [Social preview image sizes: the OG cheat sheet](https://curlshot.com/blog/social-preview-image-sizes.md): Open Graph image sizes for Facebook, LinkedIn, WhatsApp, iMessage, Discord, Slack and Google Discover, drawn to scale, with the tags and the fixes.
---
Source: https://curlshot.com/tools/website-scrolling-video
# Record a scrolling video of any website
> Record a video of a web page scrolling from top to bottom, from its address. MP4, WebM or GIF, computer or phone view. One API request, nothing to install.
To make a video of a website scrolling, give CurlShot the address of the page and ask for an MP4. CurlShot opens the page in a real browser, scrolls it from the top to the bottom at a steady pace and gives you the recording as a video file. A WebM or an animated GIF works the same way, and so does a phone view for a vertical video. Nothing to install, and no screen recorder.
Page for people: https://curlshot.com/tools/website-scrolling-video
## How to record a scrolling video of a website in three steps
1. Create a free account and open the playground in your dashboard.
2. Paste the address of the page and set the format to mp4, webm or gif.
3. Press "Record video", then download the file. Developers send the same thing as one request.
## MP4, WebM or GIF, and how long it can be
Three values of format give a video. The page is recorded scrolling from the top to the bottom; set video_scroll=false to record the first screen standing still instead.
| format | What you get | Good for |
| --- | --- | --- |
| mp4 | An H.264 video that every browser, phone and video editor plays | Almost everything |
| webm | A VP9 video, often a smaller file than MP4 | Web pages |
| gif | An animated image, at most 15 frames per second and 640 px wide unless you set image_width | Emails, chats and READMEs |
- Length: video_duration from 1 to 30 seconds. Left out, it follows the height of the page.
- Smoothness: video_fps from 5 to 30, default 24.
- Window: 1280 × 720 unless you set viewport_height or pick a device. One frame can be at most 1920 × 1080 pixels.
- video_scroll_back=true scrolls back up at the end, so the video loops cleanly.
- Long recordings are a good fit for async=true with a webhook, so your code does not wait on the connection.
## What people use it for
- Show a landing page or a redesign in a post, a pitch or a portfolio
- Add a moving preview of a site to a directory or a template shop
- Send a client a walk through a whole page without a screen recorder
- Put an animated GIF of a page in an email or a README
## The same thing with the API
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://example.com&format=mp4&video_duration=8" \
--output page.mp4
```
An access key is free: https://curlshot.com/register. Read more:
- [Scrolling videos](https://curlshot.com/docs/video.md)
- [Async and webhooks](https://curlshot.com/docs/async-and-webhooks.md)
## Questions
### How do I record a video of a website scrolling?
Send CurlShot the address of the page with format=mp4. The answer is the video file: the page from top to bottom, in a 1280 by 720 window. In the dashboard playground you do the same with a form and a button.
### Can I get a GIF instead of a video?
Yes. Ask for format=gif. A GIF is 640 pixels wide unless you set another width, and it is a much larger file than an MP4 of the same page.
### How long is the video?
As long as the page needs: a taller page gives a longer video, up to 30 seconds. Set video_duration to choose the length yourself, and the scroll speeds up or slows down to fit.
### Can I record the phone version of a site?
Yes. Add a device, for example viewport_device=iphone_15_pro, and you get a tall video of the mobile layout.
### Does a video cost more than a screenshot?
No. A video counts as one screenshot of your monthly allowance. Plans differ in how long a video may be, up to 30 seconds.
## Related
- [Full-page screenshot](https://curlshot.com/tools/full-page-screenshot.md): Take a screenshot of a whole web page, from the top to the very bottom, as one image. Paste the address, nothing to install. Also available as an API.
- [Mobile screenshot](https://curlshot.com/tools/mobile-screenshot.md): See and screenshot any website as it looks on an iPhone, an Android phone or a tablet, without picking one up. Paste the address. Free to try, also an API.
- [Screenshot API](https://curlshot.com/tools/screenshot-api.md): A screenshot API for developers. One HTTP request turns a URL, HTML or Markdown into a PNG, JPEG, WebP or PDF. Full page, devices, blocking, cache, MCP.
---
Source: https://curlshot.com/tools/webpage-to-jpg
# Save a web page as a JPG
> Save any web page as a JPG image. Paste the address, choose the whole page or just the top, and download the file. Free to try, also one request by API.
To save a web page as a JPG, paste its address into CurlShot and press the button. CurlShot opens the page in a real browser and gives you a JPG image of it to download, the whole page or just the first screen. A JPG is small, opens everywhere and can be attached to an email or dropped into a document. With the API you can also ask for PNG or WebP.
Do it in the browser, free and without an account: https://curlshot.com/tools/webpage-to-jpg
## How to save a web page as a JPG in three steps
1. Paste the address of the web page into the box.
2. Choose "Whole page" or "Just the top".
3. Press "Take the screenshot", then download the JPG.
## JPG quality, and what a JPG cannot do
A JPG trades a little sharpness for a much smaller file. With the API, image_quality sets that trade from 1 to 100. The default, 80, suits most pages. These are starting points, not rules: try two values on your own page and compare.
| image_quality | Use it for |
| --- | --- |
| 60 to 70 | Thumbnails and previews, where the image is shown small |
| 80 (default) | Most pages: attachments, documents, chats |
| 90 to 100 | Pages full of small text, and images meant for print |
- A JPG has no transparency. omit_background with format=jpeg is refused with invalid_options; use PNG or WebP for that.
- Choose "Whole page" for everything down to the footer, or "Just the top" for the first screen only. With the API that is full_page=true or nothing.
- A long page as a JPG is usually far smaller than the same page as a PNG, which makes JPG the safer choice for email attachments.
- Want text that stays text? Save the page as a PDF instead.
## What people use it for
- Attach a web page to an email as an image
- Put a page into a slide, a document or a chat
- Keep a small copy of a page that opens on any device
- Share a page with someone who should not need the link
## The same thing with the API
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://example.com&format=jpeg&image_quality=85&full_page=true" \
--output example.jpg
```
An access key is free: https://curlshot.com/register. Read more:
- [Screenshot a URL](https://curlshot.com/docs/screenshot-url.md)
- [Options reference](https://curlshot.com/docs/options.md)
## Questions
### How do I convert a web page to a JPG?
Paste the address of the page into CurlShot and press "Take the screenshot". The download is a JPG image of the page.
### Can I choose the quality of the JPG?
With the API, yes. image_quality takes a number from 1 to 100: a lower number makes a smaller file, a higher one a sharper image.
### JPG, PNG or WebP: which should I use?
JPG is the small, universal choice for pages with photos. PNG keeps text and flat colors perfectly sharp and can have a transparent background. WebP is the smallest of the three and is meant for use on websites.
### Is it free?
You can try it on this page without an account. A free account adds a monthly allowance of screenshots and keeps them in one place.
## Related
- [Full-page screenshot](https://curlshot.com/tools/full-page-screenshot.md): Take a screenshot of a whole web page, from the top to the very bottom, as one image. Paste the address, nothing to install. Also available as an API.
- [Web page to PDF](https://curlshot.com/tools/website-to-pdf.md): Turn a web page into a PDF document from its address. Real pages, working links and selectable text. Paste the address, nothing to install. Also an API.
- [URL to image](https://curlshot.com/tools/url-to-image.md): Convert any URL into an image file. Paste a web address and download a PNG, JPEG or WebP screenshot of the page. Free to try, and one request by API.
## Guides
- [PNG, JPEG, WebP or PDF for website screenshots](https://curlshot.com/blog/png-jpeg-webp-pdf-for-screenshots.md): A decision flow, a comparison table and our own file-size measurements for choosing PNG, JPEG, WebP or PDF when you save a screenshot of a web page.
---
Source: https://curlshot.com/tools/tablet-screenshot
# Screenshot a website as a tablet shows it
> See and screenshot any website as it looks on an iPad or another tablet, without owning one. Paste the address and choose Tablet. Free to try, also an API.
To see how a website looks on a tablet, paste its address into CurlShot and choose Tablet. CurlShot opens the page with a tablet-sized screen, the tablet's pixel density and a tablet browser identity, so the site serves the layout it gives to tablets, and returns a screenshot of it. The API has presets for the iPad, iPad mini, iPad Air, iPad Pro, Galaxy Tab S9 and Pixel Tablet.
Do it in the browser, free and without an account: https://curlshot.com/tools/tablet-screenshot

## How to screenshot a website as a tablet shows it in three steps
1. Paste the address of the website into the box.
2. Choose "Tablet".
3. Press "Take the screenshot", then download the image.
## Every tablet you can pick, upright and on its side
Tablets sit between phones and laptops, and many sites switch layout right there: a menu that collapses, a table that scrolls, two columns that become one. Each tablet preset sets the screen, the pixel density, touch support and the tablet browser identity in one option.
Add viewport_landscape=true to turn the tablet on its side. The screen sizes swap, as in the table.
| Tablet | viewport_device | Portrait (CSS px) | Landscape (CSS px) | Density |
| --- | --- | --- | --- | --- |
| iPad (10th gen) | ipad | 820 × 1180 | 1180 × 820 | 2x |
| iPad mini | ipad_mini | 744 × 1133 | 1133 × 744 | 2x |
| iPad Air | ipad_air | 820 × 1180 | 1180 × 820 | 2x |
| iPad Pro 11" | ipad_pro_11 | 834 × 1194 | 1194 × 834 | 2x |
| iPad Pro 13" | ipad_pro_13 | 1024 × 1366 | 1366 × 1024 | 2x |
| Galaxy Tab S9 | galaxy_tab_s9 | 800 × 1280 | 1280 × 800 | 2x |
| Pixel Tablet | pixel_tablet | 800 × 1280 | 1280 × 800 | 2x |
- The image is the screen size times the density: an iPad at density 2 gives a 1,640 × 2,360 image of its first screen.
- Add full_page=true to capture the tablet layout down to the bottom.
- For a width that no preset has, set viewport_width, viewport_height and viewport_mobile=true yourself.
## What people use it for
- Check the in-between layout that neither a phone nor a computer shows
- Test a menu, a table or a form at tablet width
- Show a client how their site looks on an iPad
- Screenshots for a store listing or a presentation
## The same thing with the API
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://example.com&viewport_device=ipad&full_page=true" \
--output tablet.png
```
An access key is free: https://curlshot.com/register. Read more:
- [Devices](https://curlshot.com/docs/devices.md)
## Questions
### How do I take a screenshot of a website on an iPad without an iPad?
Paste the address into CurlShot and choose Tablet. The page is opened with the screen size and browser identity of a tablet, and you get a screenshot of what it shows.
### Can I get the landscape view?
With the API, yes. Add viewport_landscape=true and the tablet is turned on its side before the screenshot is taken.
### Which tablets are available?
The API has presets for the iPad, iPad mini, iPad Air, iPad Pro 11 and 13 inch, Galaxy Tab S9 and Pixel Tablet, listed with their sizes on this page. You can also set any screen width and height yourself.
### Is it free?
You can try it on this page without an account. A free account adds a monthly allowance of screenshots and keeps them in one place.
## Related
- [Full-page screenshot](https://curlshot.com/tools/full-page-screenshot.md): Take a screenshot of a whole web page, from the top to the very bottom, as one image. Paste the address, nothing to install. Also available as an API.
- [URL to image](https://curlshot.com/tools/url-to-image.md): Convert any URL into an image file. Paste a web address and download a PNG, JPEG or WebP screenshot of the page. Free to try, and one request by API.
- [Mobile screenshot](https://curlshot.com/tools/mobile-screenshot.md): See and screenshot any website as it looks on an iPhone, an Android phone or a tablet, without picking one up. Paste the address. Free to try, also an API.
## Guides
- [Viewport sizes cheat sheet: phones to desktops](https://curlshot.com/blog/viewport-sizes-cheat-sheet.md): Viewport sizes in CSS pixels, screenshot sizes and device pixel ratios of iPhone, Pixel, Galaxy, iPad and laptop screens, drawn to scale, and the sizes to test.
---
Source: https://curlshot.com/tools/dark-mode-screenshot
# Screenshot a website in dark mode
> Screenshot any website in its dark theme. One option asks the page for dark mode before the screenshot is taken. Works with full pages, devices and PDF.
To screenshot a website in dark mode, add dark_mode=true to a CurlShot request. The browser then tells the page that the visitor prefers a dark theme, exactly as a phone or computer set to dark does, and the screenshot shows the dark version. It works on every site that has a dark theme; a site without one looks the same as before.
Page for people: https://curlshot.com/tools/dark-mode-screenshot

## How to take a dark mode screenshot of a website in three steps
1. Create a free account and copy your access key.
2. Add dark_mode=true to the request, next to the address of the page.
3. Fetch it and save the image. Leave the option out to get the light version.
## What dark_mode changes, and when it does not
dark_mode=true tells the page that the visitor prefers a dark theme, the same signal a phone or computer set to dark sends. Whether the page turns dark is up to the site.
| The site | Result | What to do |
| --- | --- | --- |
| Follows the system setting (prefers-color-scheme) | The dark theme | Nothing: this is how most dark themes work. |
| Has its own theme switch only | Stays light | Press the switch with click, or set the theme cookie the site uses with cookies. |
| Has no dark theme | Looks the same as before | Add your own CSS with styles, if you need a dark look anyway. |
- Take the same request twice, with and without dark_mode, for a light and dark pair.
- reduced_motion=true asks the page to stop its animations, so both captures match.
- dark_mode changes the page being captured. It works with full pages, devices, element captures and PDF.
## What people use it for
- Light and dark screenshots of your product, side by side
- Store listings, docs and landing pages that show both themes
- Check that a change did not break the dark theme
- Previews that match the theme of the app they appear in
## The same thing with the API
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://example.com&dark_mode=true" \
--output dark.png
```
An access key is free: https://curlshot.com/register. Read more:
- [Dark mode and emulation](https://curlshot.com/docs/dark-mode-and-emulation.md)
- [Options reference](https://curlshot.com/docs/options.md)
## Questions
### How do I take a screenshot of a website in dark mode?
Send a CurlShot request with dark_mode=true. The page is asked for its dark theme before the screenshot is taken.
### Does it work on every website?
It works on every site that follows the visitor's system setting, which is how most dark themes work. A site with no dark theme, or one that only changes with its own switch, stays light.
### Can I also turn animations off?
Yes. reduced_motion=true asks the page to stop its animations, which gives the same screenshot every time.
### Can I combine it with a phone view or a full page?
Yes. dark_mode works together with every other option: device presets, full_page, element captures and PDF.
## Related
- [Full-page screenshot](https://curlshot.com/tools/full-page-screenshot.md): Take a screenshot of a whole web page, from the top to the very bottom, as one image. Paste the address, nothing to install. Also available as an API.
- [Mobile screenshot](https://curlshot.com/tools/mobile-screenshot.md): See and screenshot any website as it looks on an iPhone, an Android phone or a tablet, without picking one up. Paste the address. Free to try, also an API.
- [Screenshot API](https://curlshot.com/tools/screenshot-api.md): A screenshot API for developers. One HTTP request turns a URL, HTML or Markdown into a PNG, JPEG, WebP or PDF. Full page, devices, blocking, cache, MCP.
---
Source: https://curlshot.com/tools/element-screenshot
# Screenshot one element of a page
> Capture one part of a web page instead of all of it: a chart, a pricing table, a card. Name the element with a CSS selector and get an image of it alone.
To screenshot one element of a web page, add a CSS selector to a CurlShot request, for example selector=h1 or selector=.pricing-table. CurlShot opens the page, finds the first element that matches and returns an image of that element alone, cropped to its edges. To cut out a fixed area instead, give its position and size in pixels.
Page for people: https://curlshot.com/tools/element-screenshot

## How to screenshot one element of a web page in three steps
1. Create a free account and copy your access key.
2. Find the CSS selector of the element: its id, its class or its tag.
3. Add selector to the request and save the image that comes back.
## A CSS selector or a rectangle: which to use
There are two ways to capture part of a page. A selector follows the element wherever it is; a rectangle cuts out the same pixels every time. Use one or the other: sending both is refused.
| Compare | selector | clip_x, clip_y, clip_width, clip_height |
| --- | --- | --- |
| You give | A CSS selector, such as #pricing or .infobox | A position and a size in pixels, from the top left of the page |
| The image is | The first matching element, cropped to its edges | Exactly that rectangle |
| Survives layout changes | Yes, as long as the selector matches | No: a moved element leaves the rectangle |
| Nothing there | selector_not_found (422), not counted against your quota | You get whatever is in that area |
| Formats | png, jpeg, webp | png, jpeg, webp |
- An element that appears late: add wait_for_selector with the same selector.
- A transparent background around a logo or a badge: omit_background=true with png or webp.
- Test the selector first in your browser console with document.querySelector.
- Write # as %23 in a GET request, or send the request as POST.
## What people use it for
- A chart or a dashboard tile as an image for a report or an email
- A pricing table, a testimonial or a product card on its own
- One component of your app for the docs
- Watching one part of a page for changes
## The same thing with the API
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://example.com&selector=p" \
--output element.png
```
An access key is free: https://curlshot.com/register. Read more:
- [Capture one element](https://curlshot.com/docs/element.md)
- [Customize the page](https://curlshot.com/docs/customize.md)
## Questions
### How do I take a screenshot of a specific element?
Add selector to a CurlShot request with the CSS selector of the element. The image contains that element and nothing else.
### What if the element appears late?
Add wait_for_selector with the same selector. The screenshot is taken only after the element is visible.
### Can I capture an area by coordinates?
Yes. clip_x, clip_y, clip_width and clip_height cut out a rectangle of the page, measured in pixels from its top left corner.
### Can I hide things inside or around the element?
Yes. hide_selectors hides any elements you name, and styles adds your own CSS to the page before the screenshot.
## Related
- [Full-page screenshot](https://curlshot.com/tools/full-page-screenshot.md): Take a screenshot of a whole web page, from the top to the very bottom, as one image. Paste the address, nothing to install. Also available as an API.
- [Screenshot API](https://curlshot.com/tools/screenshot-api.md): A screenshot API for developers. One HTTP request turns a URL, HTML or Markdown into a PNG, JPEG, WebP or PDF. Full page, devices, blocking, cache, MCP.
- [HTML to image](https://curlshot.com/tools/html-to-image.md): Render your own HTML, CSS or Markdown into an image or a PDF with one API request. For social cards, certificates, receipts and reports.
---
Source: https://curlshot.com/tools/high-resolution-screenshot
# A high-resolution screenshot of any website
> Take sharp, high-resolution screenshots of any website. One option doubles or triples the pixel density, for print, retina displays and zooming in.
To take a high-resolution screenshot of a website, add device_scale_factor=2 to a CurlShot request. The page is drawn with twice the pixels in each direction, the way a retina display draws it, so text and icons stay sharp when the image is enlarged or printed. The layout of the page does not change, only its sharpness. Use 3 for three times the density.
Page for people: https://curlshot.com/tools/high-resolution-screenshot
## How to take a high-resolution screenshot of a website in three steps
1. Create a free account and copy your access key.
2. Add device_scale_factor=2 to the request, and format=png for the sharpest text.
3. Fetch it and save the image.
## How large the image gets at 1x, 2x and 3x
Pixel density multiplies both sides of the image and keeps the layout. Twice the density means four times the pixels, so file size and render time grow with it.
| device_scale_factor | Image from a 1280 × 1024 window | Pixels compared with 1x | Good for |
| --- | --- | --- | --- |
| 1 (default) | 1,280 × 1,024 | 1x | Thumbnails, previews, monitoring |
| 2 | 2,560 × 2,048 | 4x | Retina displays, slides, landing pages |
| 3 | 3,840 × 3,072 | 9x | Print, posters, zooming into detail |
- Device presets bring their own density: phones are mostly 3x, tablets and MacBooks 2x.
- Your plan can set a lower maximum density for full-page screenshots. A higher value is lowered to the maximum.
- For a video, the frame must stay within 1920 × 1080 pixels, density included.
- Need a large image but not a large file? Capture at 2x and add image_width to resize the result.
## What people use it for
- Screenshots for print, slides and posters
- Product images on a landing page that stay sharp on retina displays
- Images that people zoom into, like long articles and dashboards
- Store listings that ask for large images
## The same thing with the API
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://example.com&device_scale_factor=2&format=png" \
--output sharp.png
```
An access key is free: https://curlshot.com/register. Read more:
- [Devices and screen sizes](https://curlshot.com/docs/devices.md)
- [Options reference](https://curlshot.com/docs/options.md)
## Questions
### How do I take a high-resolution screenshot of a website?
Add device_scale_factor=2 to a CurlShot request. The image has twice the width and height in pixels, with the same layout.
### What is the difference from a wider browser window?
A wider window changes the layout: the page shows its large-screen design. A higher pixel density keeps the layout and draws it with more pixels, so it is sharper.
### Which format is best for sharp text?
PNG keeps every pixel as it was drawn. For smaller files use WebP or JPEG with image_quality set to 90 or more.
### Can I set the exact size of the image?
Yes. viewport_width and viewport_height set the size of the browser window, and image_width resizes the finished image.
## Related
- [Full-page screenshot](https://curlshot.com/tools/full-page-screenshot.md): Take a screenshot of a whole web page, from the top to the very bottom, as one image. Paste the address, nothing to install. Also available as an API.
- [URL to image](https://curlshot.com/tools/url-to-image.md): Convert any URL into an image file. Paste a web address and download a PNG, JPEG or WebP screenshot of the page. Free to try, and one request by API.
- [Screenshot API](https://curlshot.com/tools/screenshot-api.md): A screenshot API for developers. One HTTP request turns a URL, HTML or Markdown into a PNG, JPEG, WebP or PDF. Full page, devices, blocking, cache, MCP.
## Guides
- [Viewport sizes cheat sheet: phones to desktops](https://curlshot.com/blog/viewport-sizes-cheat-sheet.md): Viewport sizes in CSS pixels, screenshot sizes and device pixel ratios of iPhone, Pixel, Galaxy, iPad and laptop screens, drawn to scale, and the sizes to test.
- [PNG, JPEG, WebP or PDF for website screenshots](https://curlshot.com/blog/png-jpeg-webp-pdf-for-screenshots.md): A decision flow, a comparison table and our own file-size measurements for choosing PNG, JPEG, WebP or PDF when you save a screenshot of a web page.
---
Source: https://curlshot.com/tools/screenshot-without-ads
# Screenshot a website without ads
> Take a clean screenshot of any website with the ads blocked: ad networks, trackers and chat bubbles are removed before the capture. Free to try, also an API.
To screenshot a website without ads, paste its address into CurlShot. Before the screenshot is taken, CurlShot blocks requests to ad networks and trackers and removes chat bubbles, so the image shows the page and not what is laid over it. Pages also load faster this way. With the API each kind of blocking is its own switch.
Do it in the browser, free and without an account: https://curlshot.com/tools/screenshot-without-ads
## How to screenshot a website without ads in three steps
1. Paste the address of the website into the box.
2. Press "Take the screenshot". The cleaning happens for you.
3. Download the image of the page without the clutter.
## The six blocking options, and what each removes
Blocking stops requests before they leave the browser: an ad whose script never loads never appears, and the page often renders faster. The page you asked for is never blocked. All of these are off by default.
| Option | Removes | Example |
| --- | --- | --- |
| block_ads | Requests to ad networks | block_ads=true |
| block_trackers | Analytics and tracking scripts | block_trackers=true |
| block_cookie_banners | Cookie consent banners | block_cookie_banners=true |
| block_chats | Live-chat widgets and bubbles | block_chats=true |
| block_resources | Whole kinds of files, such as fonts or video | block_resources=font,media |
| block_requests | Any address that matches your pattern (* is a wildcard) | block_requests=*/ads/* |
- Blocking is best-effort. Ads served from the site's own address look like normal content; hide those with hide_selectors.
- Blocking an ad does not always close the gap it leaves. Hide its container to close it.
- block_resources=script often leaves a blank page, because most sites need their JavaScript.
## What people use it for
- Clean screenshots of articles for a presentation or a report
- Archiving a page as its content, not as its advertising
- Previews and thumbnails with no banner over them
- Faster, steadier screenshots for monitoring
## The same thing with the API
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://example.com&block_ads=true&block_trackers=true&block_chats=true&full_page=true" \
--output clean.png
```
An access key is free: https://curlshot.com/register. Read more:
- [Blocking](https://curlshot.com/docs/blocking.md)
## Questions
### How do I screenshot a page without the ads?
Paste the address into CurlShot. Ad networks are blocked while the page loads, so the ads never appear in the screenshot.
### What is left where the ad was?
Usually an empty space the size of the ad, or nothing at all when the page closes the gap. The content of the page is not changed.
### Can I block something else on the page?
With the API, yes. block_requests blocks any address pattern you give, block_resources blocks whole kinds of files such as fonts or video, and hide_selectors hides any element.
### Is it free?
You can try it on this page without an account. A free account adds a monthly allowance of screenshots and keeps them in one place.
## Related
- [Full-page screenshot](https://curlshot.com/tools/full-page-screenshot.md): Take a screenshot of a whole web page, from the top to the very bottom, as one image. Paste the address, nothing to install. Also available as an API.
- [Web page to PDF](https://curlshot.com/tools/website-to-pdf.md): Turn a web page into a PDF document from its address. Real pages, working links and selectable text. Paste the address, nothing to install. Also an API.
- [Screenshot without cookie banners](https://curlshot.com/tools/screenshot-without-cookie-banners.md): Take a screenshot of any web page without the cookie banner: GDPR consent pop-ups and cookie notices are hidden before the capture. Free to try, also an API.
## Guides
- [Why website screenshots look wrong, and the fixes](https://curlshot.com/blog/why-website-screenshots-look-wrong.md): A field guide to 11 ways a website screenshot goes wrong, from blank lazy images to cookie banners and cut-off pages, with the cause and the fix for each.
---
Source: https://curlshot.com/tools/html-to-pdf
# An HTML to PDF API that is one POST request
> An HTML to PDF API: POST your HTML and CSS, get a PDF back. A4, Letter and 9 other paper sizes, margins, page breaks. Node, Python, PHP, cURL. Free plan.
CurlShot is an HTML to PDF API. Send your HTML in a POST request with format=pdf and the answer is the PDF file. A real browser lays the page out and prints it, so your CSS, web fonts, tables and images come out as they look on screen, with text you can select and search. Paper size, margins, orientation and background printing are options, and page breaks follow your CSS. It works from any language that can send an HTTP request.
Page for people: https://curlshot.com/tools/html-to-pdf

## How to convert HTML to PDF with the API in three steps
1. Write the document as HTML and CSS, as you would a web page.
2. Send it in a POST request with format set to pdf and the paper size you want.
3. Save the PDF that comes back, or make one for every order, user or report.
## One POST request, in your language
Send the HTML in the html field of a JSON body, with format set to pdf. The answer is the PDF file itself. Your access key goes in the X-Access-Key header, so it stays out of logs.
Node.js:
```javascript
const response = await fetch('https://curlshot.com/api/v1/screenshot', {
method: 'POST',
headers: { 'X-Access-Key': process.env.SCREENSHOT_ACCESS_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ html: invoiceHtml, format: 'pdf', pdf_paper_format: 'a4', pdf_margin: '20mm' }),
})
if (!response.ok) throw new Error((await response.json()).error_message)
await writeFile('invoice.pdf', Buffer.from(await response.arrayBuffer()))
```
Python:
```python
response = requests.post(
"https://curlshot.com/api/v1/screenshot",
headers={"X-Access-Key": os.environ["SCREENSHOT_ACCESS_KEY"]},
json={"html": invoice_html, "format": "pdf", "pdf_paper_format": "a4", "pdf_margin": "20mm"},
)
response.raise_for_status()
open("invoice.pdf", "wb").write(response.content)
```
PHP:
```php
$context = stream_context_create(['http' => [
'method' => 'POST',
'header' => "X-Access-Key: " . getenv('SCREENSHOT_ACCESS_KEY') . "\r\nContent-Type: application/json",
'content' => json_encode(['html' => $invoiceHtml, 'format' => 'pdf', 'pdf_paper_format' => 'a4', 'pdf_margin' => '20mm']),
]]);
$pdf = file_get_contents('https://curlshot.com/api/v1/screenshot', false, $context);
if ($pdf === false) {
throw new RuntimeException('Render failed: ' . ($http_response_header[0] ?? 'no response'));
}
file_put_contents('invoice.pdf', $pdf);
```
## Paper sizes
pdf_paper_format takes any of these values. The default is a4; use letter for readers in the United States and Canada. pdf_landscape=true turns the paper on its side, and pdf_fit_one_page=true skips paper sizes and puts the whole document on one tall page.
| Paper | pdf_paper_format | Millimetres | Inches | CSS pixels |
| --- | --- | --- | --- | --- |
| A0 | a0 | 841 × 1189 | 33.1 × 46.8 | 3178 × 4493 |
| A1 | a1 | 594 × 841 | 23.4 × 33.1 | 2246 × 3178 |
| A2 | a2 | 420 × 594 | 16.54 × 23.4 | 1588 × 2246 |
| A3 | a3 | 297 × 420 | 11.7 × 16.54 | 1123 × 1588 |
| A4 | a4 | 210 × 297 | 8.27 × 11.7 | 794 × 1123 |
| A5 | a5 | 148 × 210 | 5.83 × 8.27 | 560 × 794 |
| A6 | a6 | 105 × 148 | 4.13 × 5.83 | 396 × 560 |
| US Letter | letter | 216 × 279 | 8.5 × 11 | 816 × 1056 |
| US Legal | legal | 216 × 356 | 8.5 × 14 | 816 × 1344 |
| Tabloid | tabloid | 279 × 432 | 11 × 17 | 1056 × 1632 |
| Ledger | ledger | 432 × 279 | 17 × 11 | 1632 × 1056 |
## Margins, page breaks and print styles
The PDF is printed by a real browser, so the CSS you already know for printing works.
| You want | How |
| --- | --- |
| A margin on every page | pdf_margin=20mm, or pdf_margin_top, _right, _bottom and _left for one side. Units: mm, cm, in or px. |
| A new page before each section | CSS: section { break-before: page; } |
| A table row or a card never split in two | CSS: tr, .card { break-inside: avoid; } |
| Your @media print rules to apply | media_type=print. The default draws the screen styles. |
| No background colours, to save ink | pdf_print_background=false. Backgrounds print by default. |
| Fonts and logos | Link them with full https:// addresses; relative paths have nothing to resolve against. |
- Without a margin option the content runs to the edge of the paper.
- HTML can be up to 2 MB. For many documents at once, use async=true with a webhook, or the bulk endpoint.
## What people use it for
- Invoices and receipts from an HTML template
- Reports and statements with tables and charts
- Tickets, certificates and contracts with the details filled in
- A printable version of a page of your app
## The same thing with the API
```bash
curl -X POST "https://curlshot.com/api/v1/screenshot" \
-H "X-Access-Key: YOUR_ACCESS_KEY" \
-H "Content-Type: application/json" \
-d '{"html":"Invoice 1042
Total: 120.00
","format":"pdf","pdf_paper_format":"a4","pdf_margin":"20mm"}' \
--output invoice.pdf
```
An access key is free: https://curlshot.com/register. Read more:
- [PDF options](https://curlshot.com/docs/pdf.md)
- [HTML and Markdown input](https://curlshot.com/docs/html-and-markdown.md)
## Questions
### How do I convert HTML to PDF?
Send the HTML to CurlShot in the html field of a POST request and add format=pdf. The answer is the PDF file.
### Do backgrounds and colors print?
Yes. Background colors and images are printed unless you switch them off with pdf_print_background=false, for a document that saves ink.
### Can I control page breaks?
Yes, with normal CSS. Rules such as break-before, break-after and break-inside work as they do when a browser prints.
### Can the whole document be one long page?
Yes. pdf_fit_one_page puts everything on a single tall page with no breaks.
## Related
- [Web page to PDF](https://curlshot.com/tools/website-to-pdf.md): Turn a web page into a PDF document from its address. Real pages, working links and selectable text. Paste the address, nothing to install. Also an API.
- [HTML to image](https://curlshot.com/tools/html-to-image.md): Render your own HTML, CSS or Markdown into an image or a PDF with one API request. For social cards, certificates, receipts and reports.
- [Markdown to PDF](https://curlshot.com/tools/markdown-to-pdf.md): Turn Markdown into a clean, styled PDF or image with one API request. Headings, lists, tables and code are laid out for you. For notes, docs and reports.
## Guides
- [Web page to PDF: paper sizes, margins, print CSS](https://curlshot.com/blog/web-page-to-pdf-paper-sizes.md): Paper sizes in millimetres, inches, CSS pixels and points, how margins and page breaks work in a PDF of a web page, and the print CSS that controls them.
---
Source: https://curlshot.com/tools/markdown-to-pdf
# Turn Markdown into a PDF
> Turn Markdown into a clean, styled PDF or image with one API request. Headings, lists, tables and code are laid out for you. For notes, docs and reports.
To turn Markdown into a PDF, send the text to CurlShot in the markdown field of a POST request with format=pdf. It is rendered as a clean, styled page, with headings, lists, tables, links and code blocks laid out for reading, and comes back as a PDF. Leave format out to get an image of the same page instead.
Page for people: https://curlshot.com/tools/markdown-to-pdf

## How to convert Markdown to PDF in three steps
1. Write the document in Markdown, or take the text your app already has.
2. Send it in a POST request in the markdown field, with format set to pdf.
3. Save the PDF that comes back.
## What the Markdown can contain
The Markdown is turned into a page with a neutral document style: dark text on white, a centred column, styled tables and code blocks. Then it is rendered like any page, as a PDF or an image.
| Markdown | Rendered |
| --- | --- |
| # Headings, **bold**, _italic_, links | Yes |
| Lists and task lists (- [ ] and - [x]) | Yes |
| Tables with \| pipes \| | Yes, styled |
| Fenced code blocks | Yes, in a monospace block |
| Quotes | Yes |
| Images | Yes, from a full https:// address |
- Change the look with styles: your own CSS for fonts, colours and spacing.
- All PDF options apply: paper size, margins, landscape, one long page.
- Leave format out for a PNG of the same document, and set viewport_width for its width.
- Markdown can be up to 2 MB, sent in a POST body.
## What people use it for
- Notes, READMEs and changelogs as a PDF to send
- Reports written by a script or an AI assistant, as a document
- Release notes as an image for a post
- Meeting notes and summaries people can print
## The same thing with the API
```bash
curl -X POST "https://curlshot.com/api/v1/screenshot" \
-H "X-Access-Key: YOUR_ACCESS_KEY" \
-H "Content-Type: application/json" \
-d '{"markdown":"# Weekly report\n\n- Visits: 1,204\n- Signups: 38","format":"pdf"}' \
--output report.pdf
```
An access key is free: https://curlshot.com/register. Read more:
- [HTML and Markdown input](https://curlshot.com/docs/html-and-markdown.md)
- [PDF options](https://curlshot.com/docs/pdf.md)
## Questions
### How do I convert Markdown to PDF?
Send the Markdown to CurlShot in the markdown field of a POST request and add format=pdf. The answer is the PDF file.
### Can I change how it looks?
Yes. The styles option adds your own CSS to the page, so fonts, colors and spacing can match your brand.
### Can I get an image instead of a PDF?
Yes. Leave format out for a PNG, or ask for jpeg or webp. Set viewport_width to choose how wide the page is.
### Are tables and code blocks supported?
Yes. Tables, fenced code blocks, lists, links, quotes and images are all rendered.
## Related
- [Screenshot API](https://curlshot.com/tools/screenshot-api.md): A screenshot API for developers. One HTTP request turns a URL, HTML or Markdown into a PNG, JPEG, WebP or PDF. Full page, devices, blocking, cache, MCP.
- [HTML to image](https://curlshot.com/tools/html-to-image.md): Render your own HTML, CSS or Markdown into an image or a PDF with one API request. For social cards, certificates, receipts and reports.
- [HTML to PDF](https://curlshot.com/tools/html-to-pdf.md): An HTML to PDF API: POST your HTML and CSS, get a PDF back. A4, Letter and 9 other paper sizes, margins, page breaks. Node, Python, PHP, cURL. Free plan.
## Guides
- [Web page to PDF: paper sizes, margins, print CSS](https://curlshot.com/blog/web-page-to-pdf-paper-sizes.md): Paper sizes in millimetres, inches, CSS pixels and points, how margins and page breaks work in a PDF of a web page, and the print CSS that controls them.
---
Source: https://curlshot.com/tools/open-graph-image-generator
# An OG image API for your own HTML templates
> An OG image API: send an HTML template, get a 1200 by 630 PNG share card back. One card per post or product, cached, with a Next.js metadata example.
CurlShot is an OG image API. Write the share card once as HTML and CSS, send it with a window of 1200 by 630 pixels, and the answer is a PNG at exactly that size, the one social networks and chat apps expect. Fill in the title of each article or product and you get one Open Graph image per page, in your own design. With the cache on, the same card is served from storage instead of rendered again.
Page for people: https://curlshot.com/tools/open-graph-image-generator

## How to generate OG images with the API in three steps
1. Design the card as HTML and CSS, with a place for the title.
2. Send it with viewport_width 1200 and viewport_height 630 for each page.
3. Save the image with your other images and point the og:image tag of the page at it.
## From an HTML template to a 1200 × 630 PNG
An OG image is the picture that shows when a link is shared. You design the card once in HTML and CSS, fill in the title of each page, and the API returns the image at exactly the size of the window you set.
| Option | Set it to | Why |
| --- | --- | --- |
| html | Your card template, with the title filled in | One design, one image per page. |
| viewport_width, viewport_height | 1200 and 630 | The image has the size of the window. The default, 1280 × 1024, is the wrong shape for a card. |
| format | png (default), or jpeg for a card with a photo | PNG keeps text sharp. |
| device_scale_factor | 2, if cards look soft on dense screens | The same card at 2400 × 1260. |
| cache, cache_key | true, and a version label such as card-v1 | The same card is served from storage instead of rendered again. |
## Use it from Next.js metadata
Render the card when a post is published or edited, save the file with your other images, and point the metadata at it. Do not point og:image at the API itself: a POST request cannot be a plain link, and files kept by the API are removed after a while.
lib/og.ts: run when a post is published:
```typescript
export async function renderOgCard(title: string): Promise {
const response = await fetch('https://curlshot.com/api/v1/screenshot', {
method: 'POST',
headers: { 'X-Access-Key': process.env.SCREENSHOT_ACCESS_KEY!, 'Content-Type': 'application/json' },
body: JSON.stringify({
html: cardHtml(title), // your template; escape the title
viewport_width: 1200,
viewport_height: 630,
cache: true,
cache_key: 'card-v1',
}),
})
if (!response.ok) throw new Error((await response.json()).error_message)
return Buffer.from(await response.arrayBuffer()) // save as public/og/-.png
}
```
app/blog/[slug]/page.tsx:
```typescript
export async function generateMetadata({ params }: { params: { slug: string } }): Promise {
const post = await getPost(params.slug)
return {
title: post.title,
openGraph: { images: [{ url: post.ogImage, width: 1200, height: 630, alt: post.title }] },
twitter: { card: 'summary_large_image' },
}
}
```
## Caching and updating cards
Two caches matter: the one in the API, and the copy each social network keeps of your image.
- With cache=true, the same HTML returns the stored card for free. A changed title is different HTML, so it gets a new card without any work on your side.
- Cached copies live 4 hours by default; cache_ttl sets up to 30 days.
- Swapped a logo or a font that the HTML only links to? Change cache_key from card-v1 to card-v2 and every card renders fresh.
- Social networks keep their own copy for a long time. Save each new card under a new file name, for example with a short hash of the title, so they fetch it again.
## What people use it for
- A sharing card for every blog post, made when it is published
- Product cards with the name, the price and a photo
- Cards for user profiles, events and job posts
- Images for X, LinkedIn, Facebook, Slack and iMessage previews
## The same thing with the API
```bash
curl -X POST "https://curlshot.com/api/v1/screenshot" \
-H "X-Access-Key: YOUR_ACCESS_KEY" \
-H "Content-Type: application/json" \
-d '{"html":"How we cut our build time in half
","viewport_width":1200,"viewport_height":630}' \
--output og.png
```
An access key is free: https://curlshot.com/register. Read more:
- [Open Graph images](https://curlshot.com/docs/guides/open-graph-images.md)
- [Signed links](https://curlshot.com/docs/signed-links.md)
- [Caching](https://curlshot.com/docs/caching.md)
## Questions
### What size should an Open Graph image be?
1200 by 630 pixels is the size that X, LinkedIn, Facebook and most chat apps show without cropping.
### How do I make one image per page automatically?
Keep one HTML template and fill in the title of each page before you send it to CurlShot. Each request returns the card for that page.
### Can I use a screenshot of the page itself as the image?
Yes. Send the address of the page instead of HTML, with the same window size, and the card is a screenshot of its first screen.
### Is the image rendered again every time someone shares the link?
Not with the cache switched on. The card is rendered once and repeat requests are served from storage, without counting against your allowance.
## Related
- [Website thumbnail](https://curlshot.com/tools/website-thumbnail.md): Make a thumbnail or preview image of any website from its address. For directories, link lists, portfolios and newsletters. Free to try, one request by API.
- [Screenshot API](https://curlshot.com/tools/screenshot-api.md): A screenshot API for developers. One HTTP request turns a URL, HTML or Markdown into a PNG, JPEG, WebP or PDF. Full page, devices, blocking, cache, MCP.
- [HTML to image](https://curlshot.com/tools/html-to-image.md): Render your own HTML, CSS or Markdown into an image or a PDF with one API request. For social cards, certificates, receipts and reports.
## Guides
- [Social preview image sizes: the OG cheat sheet](https://curlshot.com/blog/social-preview-image-sizes.md): Open Graph image sizes for Facebook, LinkedIn, WhatsApp, iMessage, Discord, Slack and Google Discover, drawn to scale, with the tags and the fixes.
---
Source: https://curlshot.com/tools/screenshot-behind-login
# Screenshot a page behind a login
> Screenshot dashboards, admin pages and staging sites that need a login. Send a session cookie or a header with the request and the page opens signed in.
To screenshot a page that needs a login, send the session cookie of a signed-in user with the CurlShot request. The browser sets the cookie before it opens the page, so the site treats it as that user and shows the page instead of the sign-in form. Sites that use a token take it as an HTTP header, and password-protected staging sites take an Authorization value.
Page for people: https://curlshot.com/tools/screenshot-behind-login
## How to screenshot a page behind a login in three steps
1. Sign in to the site as a user made for this, and copy its session cookie.
2. Send the address of the page with the cookie in the cookies field.
3. Save the screenshot of the signed-in page.
## Cookie, header or password: which one to send
How you get past the sign-in depends on how the site remembers a signed-in user. Each way has its own option.
| The site signs you in with | Option | Example value |
| --- | --- | --- |
| A session cookie (most web apps) | cookies | session=YOUR_SESSION_COOKIE; Domain=example.com; Secure |
| A bearer token or an API key header | headers | X-Api-Key: YOUR_TOKEN |
| HTTP basic auth (staging sites) | authorization | Basic dXNlcjpwYXNz |
| A button that must be pressed first | click | #accept-terms |
- Credentials go only to the site you capture. authorization, and headers that carry a credential such as Cookie, Authorization or a name with token or key in it, are sent only to the origin of your url, not to other hosts the page loads files from or redirects to.
- Use POST, so the cookie is in the request body and not in an address that could end up in a log.
- Use an account made for screenshots, with read-only access.
## What people use it for
- Dashboards and reports as an image in a weekly email
- Screenshots of your own app for docs and release notes
- Staging and preview sites behind a password
- Admin pages, for a record of how they looked
## The same thing with the API
```bash
curl -X POST "https://curlshot.com/api/v1/screenshot" \
-H "X-Access-Key: YOUR_ACCESS_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com/dashboard","cookies":["session=YOUR_SESSION_COOKIE; Domain=example.com; Secure"]}' \
--output dashboard.png
```
An access key is free: https://curlshot.com/register. Read more:
- [Screenshot a page behind a login](https://curlshot.com/docs/guides/screenshot-behind-login.md)
- [Customize the page](https://curlshot.com/docs/customize.md)
## Questions
### How do I take a screenshot of a page that requires login?
Send the session cookie of a signed-in user in the cookies field of a CurlShot request. The page then opens as that user.
### What if the site uses a token and not a cookie?
Send it with the headers option, as a named HTTP header. For HTTP basic authentication use the authorization option.
### Which account should I use?
One made for screenshots, with read-only access to the pages you need and nothing else. Send the request with POST so the cookie is in the body and not in a web address.
### Can it click through a sign-in form?
A cookie or a header is the reliable way. The click option presses one element before the screenshot and scripts runs your own JavaScript on the page, for a step such as closing a dialog.
## Related
- [Full-page screenshot](https://curlshot.com/tools/full-page-screenshot.md): Take a screenshot of a whole web page, from the top to the very bottom, as one image. Paste the address, nothing to install. Also available as an API.
- [Screenshot API](https://curlshot.com/tools/screenshot-api.md): A screenshot API for developers. One HTTP request turns a URL, HTML or Markdown into a PNG, JPEG, WebP or PDF. Full page, devices, blocking, cache, MCP.
- [Element screenshot](https://curlshot.com/tools/element-screenshot.md): Capture one part of a web page instead of all of it: a chart, a pricing table, a card. Name the element with a CSS selector and get an image of it alone.
---
Source: https://curlshot.com/tools/bulk-screenshots
# Screenshot a list of URLs at once
> Screenshot a whole list of web pages at once. Start up to 100 screenshots with one API call, then collect the results by webhook or one status request.
To screenshot many web pages at once, send the list to the CurlShot bulk endpoint: up to 100 requests in one call, each with its own options, on plans that include bulk. You get an answer at once with one job per page. The screenshots are made in the background, and you collect them with one status request for the whole batch or receive each one by webhook as it finishes.
Page for people: https://curlshot.com/tools/bulk-screenshots
## How to screenshot a list of URLs at once in three steps
1. Create an account on a plan that includes bulk, and copy your access key.
2. Send the list of addresses in one POST request to the bulk endpoint.
3. Follow the batch with one status request, or receive each result by webhook.
## One call, up to 100 pages
A bulk call is a list of normal requests sent together. Each item has its own options and becomes its own job, so one page can fail while the others succeed. The answer comes at once, with the jobs in the same order as your list.
| To collect the results | Use | Good when |
| --- | --- | --- |
| One status request for the whole batch | The batch_url in the answer | A script that runs, waits and moves on |
| A webhook for every finished job | webhook_url for the call, or one per item | A server that should react as soon as each file is ready |
- Every option of a single request works inside an item, written as JSON: "full_page": true, not "true".
- Each successful render counts as one screenshot. Failed renders are not counted.
- A longer list goes in several calls of up to 100.
Request:
```bash
curl -X POST "https://curlshot.com/api/v1/bulk" \
-H "X-Access-Key: YOUR_ACCESS_KEY" \
-H "Content-Type: application/json" \
-d '{
"webhook_url": "https://your-app.example/hooks/screenshot",
"requests": [
{ "url": "https://example.com" },
{ "url": "https://en.wikipedia.org/wiki/Eiffel_Tower", "full_page": true, "format": "jpeg" },
{ "url": "https://news.ycombinator.com", "viewport_device": "iphone_15_pro" }
]
}'
```
## What people use it for
- Thumbnails for every site in a directory
- A screenshot of every page of a site before and after a redesign
- Nightly captures of a list of competitor or client pages
- PDF copies of a list of articles
## The same thing with the API
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://example.com&async=true&webhook_url=https://example.com/webhooks/screenshot" \
--output job.json
```
An access key is free: https://curlshot.com/register. Read more:
- [Bulk screenshots](https://curlshot.com/docs/bulk.md)
- [Async and webhooks](https://curlshot.com/docs/async-and-webhooks.md)
## Questions
### How do I take screenshots of multiple URLs at once?
Send them to the CurlShot bulk endpoint as one list. Each item is a normal request with its own address and options, and up to 100 fit in one call.
### How do I get the results?
Ask for the status of the batch, which lists every job and a link to each finished file, or give a webhook address and each result is sent to it when it is ready.
### What does the request on this page do?
It starts one screenshot in the background and sends the result to a webhook. A bulk call is a list of requests like it, started together.
### How is a batch counted?
Like the same screenshots made one by one: each successful render is one screenshot. Failed renders are not counted. The pricing page shows which plans include bulk calls.
## Related
- [Web page to PDF](https://curlshot.com/tools/website-to-pdf.md): Turn a web page into a PDF document from its address. Real pages, working links and selectable text. Paste the address, nothing to install. Also an API.
- [Website thumbnail](https://curlshot.com/tools/website-thumbnail.md): Make a thumbnail or preview image of any website from its address. For directories, link lists, portfolios and newsletters. Free to try, one request by API.
- [Screenshot API](https://curlshot.com/tools/screenshot-api.md): A screenshot API for developers. One HTTP request turns a URL, HTML or Markdown into a PNG, JPEG, WebP or PDF. Full page, devices, blocking, cache, MCP.
---
Source: https://curlshot.com/tools/screenshot-tool-for-ai-agents
# Let an AI agent see a web page
> Let an AI agent look at any web page. An MCP server with a take_screenshot tool, an OpenAPI description and llms.txt, or one plain HTTP request.
To let an AI agent see a web page, connect it to the CurlShot MCP server. The agent gets a take_screenshot tool: it passes the address of a page and receives a screenshot of it, which a model that reads images can look at. Agents without MCP use the same thing as one HTTP request, described in an OpenAPI file and in llms.txt.
Page for people: https://curlshot.com/tools/screenshot-tool-for-ai-agents
## How to let an AI agent see a web page in three steps
1. Create a free account and copy your access key.
2. Add the MCP server to your agent, or give it the screenshot request.
3. Ask the agent to look at a page. It takes the screenshot itself.
## Three ways in, for any kind of agent
Pick the one your agent already speaks. All three use the same access key and the same options.
| Way in | Address | Best for |
| --- | --- | --- |
| MCP server | /api/mcp, with the tools take_screenshot and list_devices | Claude, Cursor and other MCP clients |
| OpenAPI description | /openapi.json | Agents and code generators that build a client from a spec |
| Plain HTTP and llms.txt | /llms.txt, and the screenshot request | Any agent that can fetch a URL |
- Create a separate access key for the agent, so you can revoke it without touching your other keys.
- Leave "Require signature" off for that key: calls through MCP are not signed.
MCP client configuration:
```json
{
"mcpServers": {
"screenshots": {
"type": "http",
"url": "https://curlshot.com/api/mcp",
"headers": { "Authorization": "Bearer YOUR_ACCESS_KEY" }
}
}
}
```
## What people use it for
- A coding agent that checks how the page it just changed looks
- Research agents that read pages which need a real browser to load
- Visual checks: is the banner there, did the layout break
- Reports with screenshots, written by an assistant
## The same thing with the API
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://example.com&response_type=json&image_width=1200" \
--output screenshot.json
```
An access key is free: https://curlshot.com/register. Read more:
- [For AI agents](https://curlshot.com/docs/guides/ai-agents.md)
- [Getting started](https://curlshot.com/docs/getting-started.md)
## Questions
### How can an AI agent take a screenshot of a website?
Through the CurlShot MCP server, which gives the agent a take_screenshot tool, or with one HTTP request that returns the image.
### What does the agent get back?
The image itself, or with response_type=json a short JSON answer with a link to the file, which is easier for a tool call to pass on.
### Can the agent read the page as text too?
The service returns images and PDFs. A PDF of a page has text that can be selected and extracted, and a model that reads images can read a screenshot directly.
### How do I keep the cost of an agent under control?
Each plan is a fixed number of screenshots a month, and an access key can be revoked at any time. Repeat requests for the same page can come from the cache at no cost.
## Related
- [Full-page screenshot](https://curlshot.com/tools/full-page-screenshot.md): Take a screenshot of a whole web page, from the top to the very bottom, as one image. Paste the address, nothing to install. Also available as an API.
- [Screenshot API](https://curlshot.com/tools/screenshot-api.md): A screenshot API for developers. One HTTP request turns a URL, HTML or Markdown into a PNG, JPEG, WebP or PDF. Full page, devices, blocking, cache, MCP.
- [HTML to image](https://curlshot.com/tools/html-to-image.md): Render your own HTML, CSS or Markdown into an image or a PDF with one API request. For social cards, certificates, receipts and reports.
## Guides
- [Screenshots for AI agents: let a model see a page](https://curlshot.com/blog/screenshots-for-ai-agents.md): When to give an AI agent a screenshot, HTML, markdown or the accessibility tree, what a screenshot costs in tokens on each vendor, and how to wire it up.
---
Source: https://curlshot.com/pricing
# CurlShot pricing
Each plan is a fixed number of screenshots a month for a fixed price. Nothing is charged on top unless you turn on overage.
| Plan | Price per month | Screenshots per month | Requests per minute | Renders at once |
| --- | --- | --- | --- | --- |
| Free | Free | 100 | 10 | 1 |
| Starter | $19 | 3,000 | 60 | 5 |
| Growth | $79 | 15,000 | 150 | 15 |
| Scale | $249 | 60,000 | 400 | 40 |
Optional overage on paid plans, off by default: Starter $8, Growth $5, Scale $4 per extra 1,000. It is paid from a prepaid balance and stops at a monthly cap the account owner sets; at the cap, requests answer 402.
## What counts
- One successful render is one screenshot, whatever its size: a full-page capture of a long article counts the same as a thumbnail.
- Failed renders are not counted.
- Cache hits are not counted: a screenshot served again from the cache is free.
- The tool on the home page works without an account.
## Refunds
- 14-day money-back guarantee: the first payment of an account is refunded in full on request within 14 days; the plan then ends. Renewals are not refunded. Policy: https://curlshot.com/refunds
## Limits next to the monthly number
- Requests per minute and renders at once, as in the table.
- A maximum height and pixel density for full-page captures, which is lower on the free plan. `GET /usage` reports the values of an account.
Start free, no card: https://curlshot.com/register. Page for people: https://curlshot.com/pricing. Details: https://curlshot.com/docs/usage-and-limits.md
---
Source: https://curlshot.com/
# CurlShot: questions and answers
## What is CurlShot?
CurlShot takes a screenshot of any web page. You give it the address of the page, it opens the page the way a normal browser would, and it hands you the screenshot as an image or a PDF.
## Do I need to install anything?
No. It works right on this page, in any browser, on a computer or a phone. There is nothing to download or set up.
## Is it free?
You can try it on this page without an account. A free account gives you 100 screenshots every month, and you do not need a card to sign up. If you need more, the paid plans have a fixed price each month.
## Can it take a screenshot of the whole page, not only the part I see on my screen?
Yes. Choose "Whole page" and the screenshot runs from the top of the page to the very bottom, including everything you would normally have to scroll to see.
## Can I get a PDF instead of an image?
Yes. Choose "PDF" and the page is laid out on paper-sized pages, ready to print, email or file.
## Can it hide cookie pop-ups and ads?
Yes, on most websites. Cookie pop-ups, ads and chat bubbles are removed before the screenshot is taken, so you get a clean page. It does not catch every one on every site.
## Why did my page not work?
CurlShot can open any page that anyone can visit without a password. Pages behind a login will show the login screen instead, and a few websites turn away visitors that are not people. Check the address for typos and try again.
## What counts as one screenshot?
One screenshot that worked. If a screenshot fails, it does not count. The free plan includes 100 screenshots every month.
## What happens when I use up my screenshots for the month?
It stops until the next month starts, or until you move to a bigger plan. Plans have a fixed monthly price, and nothing is charged on top unless you turn on overage on a paid plan, which stops at a monthly cap you set.
## Is there a screenshot API for developers?
Yes. One HTTP request returns a PNG, JPEG, WebP or PDF of a URL, or of HTML or Markdown you send. The browsers run on our side, so it works from any language and any server. Signed links let you put a screenshot URL straight into a web page without exposing your key.
## Can the API capture pages behind a login or on a private network?
It can capture a page behind a login when you send what the page needs: cookies, extra headers or an Authorization header. Local and private addresses are refused on purpose; for those, send the HTML directly and it is rendered the same way.
## Can AI agents use it?
Yes. There is an MCP server with a take_screenshot tool, an OpenAPI description, an llms.txt map, and a markdown version of every docs page.
## How do I screenshot an entire web page, not only the part I see?
Paste the page address into CurlShot and keep "Whole page" selected. The screenshot covers the page from the top to the bottom, including everything you would have to scroll to see.
## Do images further down the page appear in the screenshot?
Yes. Many pages load images only when you scroll to them. CurlShot scrolls through the page first so those images load, then takes the screenshot.
## Is there a limit to how tall the page can be?
Yes. Very long pages are cut off at a maximum height so the image stays a usable size. The limit is higher on paid plans, and with the API you set it yourself with the full_page_max_height option.
## How do I convert a URL to a PDF?
Paste the URL into CurlShot, choose PDF and press the button. Developers send one request: the screenshot address with format=pdf.
## Can I select and copy the text in the PDF?
Yes. The PDF is made by a real browser, the same way as its "Save as PDF", so the text stays text and links keep working.
## Can I choose the paper size?
With the API, yes: paper format, landscape, margins and whether backgrounds are printed are all options. There is also an option to fit the whole page on one long sheet.
## How do I convert a URL to a PNG or JPG?
Paste the URL into CurlShot and download the screenshot. With the API, add format=png, format=jpeg or format=webp to the request.
## Which image format should I pick?
PNG is exact and best for pages with text and flat colour. JPEG and WebP make much smaller files and are the better choice for long pages and photos.
## Can I get a smaller image, such as a thumbnail?
Yes. With the API, image_width and image_height resize the result, so you can ask for a 400 pixel wide thumbnail directly.
## How can I see what my website looks like on a phone?
Paste the address into CurlShot and choose Phone. You get a screenshot of the mobile version of the page, as a phone would show it.
## Which devices can I choose?
On this page: a phone, a tablet and a computer. The API has a list of named devices, including current iPhone, Pixel and iPad models and common laptop and desktop sizes, and you can also set any width and height yourself.
## Is this a real phone?
No. It is a real browser set up like the phone: the same screen size, pixel density, touch support and browser identity. That is what decides which layout a site serves, so the result matches what the phone shows for almost all sites.
## How do I take a screenshot without the cookie banner?
Use CurlShot with "Hide ads and cookie pop-ups" switched on. With the API, add block_cookie_banners=true to the request.
## Does it work on every website?
It works on most sites, not all. The common consent tools are covered. For a site with an unusual pop-up, the API can hide any element by its selector or click a button before the capture.
## Can it hide other things on the page?
Yes. The other blockers have their own switches, covered on the screenshot without ads page.
## How do I generate a thumbnail from a URL?
Paste the URL into CurlShot and choose "Just the top". With the API, add image_width to get the thumbnail at the size you need.
## Can I show the thumbnail directly in a web page?
Yes. The screenshot request is a normal web address, so it can be the source of an image. Use a signed link so your access key is not visible in the page.
## Do repeated views cost screenshots?
Not with the cache switched on. A cached screenshot is served again without counting against your allowance.
## What is a screenshot API?
A service that takes screenshots of web pages for your code. You send the address of a page, it opens the page in a browser on its own servers and returns the image, so you do not run or maintain headless browsers yourself.
## Which languages does it work with?
Any language that can fetch a URL. The docs have complete samples for cURL, Node.js, Python, PHP, Go and Ruby. There is nothing to install.
## How is usage counted?
One successful render is one screenshot, whatever its size. Failed renders and cache hits are not counted. Each plan is a fixed number of screenshots a month for a fixed price.
## Can an AI agent use it?
Yes. CurlShot has an MCP server with a take_screenshot tool, an OpenAPI description and an llms.txt file, so an agent can look at any web page.
## How do I convert HTML to an image?
Send the HTML to CurlShot in the html field of a POST request. The answer is the image file. Set viewport_width and viewport_height to the size the image should have.
## Can I use my own fonts and images?
Yes. The HTML is rendered like a web page, so fonts and images referenced by a public address load normally.
## Can I get a PDF instead?
Yes. Add format=pdf. Paper size, margins and orientation are options.
## Does it take Markdown?
Yes. Send a markdown field instead of html and it is rendered as a clean, styled page.
## How do I record a video of a website scrolling?
Send CurlShot the address of the page with format=mp4. The answer is the video file: the page from top to bottom, in a 1280 by 720 window. In the dashboard playground you do the same with a form and a button.
## Can I get a GIF instead of a video?
Yes. Ask for format=gif. A GIF is 640 pixels wide unless you set another width, and it is a much larger file than an MP4 of the same page.
## How long is the video?
As long as the page needs: a taller page gives a longer video, up to 30 seconds. Set video_duration to choose the length yourself, and the scroll speeds up or slows down to fit.
## Can I record the phone version of a site?
Yes. Add a device, for example viewport_device=iphone_15_pro, and you get a tall video of the mobile layout.
## Does a video cost more than a screenshot?
No. A video counts as one screenshot of your monthly allowance. Plans differ in how long a video may be, up to 30 seconds.
## How do I convert a web page to a JPG?
Paste the address of the page into CurlShot and press "Take the screenshot". The download is a JPG image of the page.
## Can I choose the quality of the JPG?
With the API, yes. image_quality takes a number from 1 to 100: a lower number makes a smaller file, a higher one a sharper image.
## JPG, PNG or WebP: which should I use?
JPG is the small, universal choice for pages with photos. PNG keeps text and flat colors perfectly sharp and can have a transparent background. WebP is the smallest of the three and is meant for use on websites.
## How do I take a screenshot of a website on an iPad without an iPad?
Paste the address into CurlShot and choose Tablet. The page is opened with the screen size and browser identity of a tablet, and you get a screenshot of what it shows.
## Can I get the landscape view?
With the API, yes. Add viewport_landscape=true and the tablet is turned on its side before the screenshot is taken.
## Which tablets are available?
The API has presets for the iPad, iPad mini, iPad Air, iPad Pro 11 and 13 inch, Galaxy Tab S9 and Pixel Tablet, listed with their sizes on this page. You can also set any screen width and height yourself.
## How do I take a screenshot of a website in dark mode?
Send a CurlShot request with dark_mode=true. The page is asked for its dark theme before the screenshot is taken.
## Can I also turn animations off?
Yes. reduced_motion=true asks the page to stop its animations, which gives the same screenshot every time.
## Can I combine it with a phone view or a full page?
Yes. dark_mode works together with every other option: device presets, full_page, element captures and PDF.
## How do I take a screenshot of a specific element?
Add selector to a CurlShot request with the CSS selector of the element. The image contains that element and nothing else.
## What if the element appears late?
Add wait_for_selector with the same selector. The screenshot is taken only after the element is visible.
## Can I capture an area by coordinates?
Yes. clip_x, clip_y, clip_width and clip_height cut out a rectangle of the page, measured in pixels from its top left corner.
## Can I hide things inside or around the element?
Yes. hide_selectors hides any elements you name, and styles adds your own CSS to the page before the screenshot.
## How do I take a high-resolution screenshot of a website?
Add device_scale_factor=2 to a CurlShot request. The image has twice the width and height in pixels, with the same layout.
## What is the difference from a wider browser window?
A wider window changes the layout: the page shows its large-screen design. A higher pixel density keeps the layout and draws it with more pixels, so it is sharper.
## Which format is best for sharp text?
PNG keeps every pixel as it was drawn. For smaller files use WebP or JPEG with image_quality set to 90 or more.
## Can I set the exact size of the image?
Yes. viewport_width and viewport_height set the size of the browser window, and image_width resizes the finished image.
## How do I screenshot a page without the ads?
Paste the address into CurlShot. Ad networks are blocked while the page loads, so the ads never appear in the screenshot.
## What is left where the ad was?
Usually an empty space the size of the ad, or nothing at all when the page closes the gap. The content of the page is not changed.
## Can I block something else on the page?
With the API, yes. block_requests blocks any address pattern you give, block_resources blocks whole kinds of files such as fonts or video, and hide_selectors hides any element.
## How do I convert HTML to PDF?
Send the HTML to CurlShot in the html field of a POST request and add format=pdf. The answer is the PDF file.
## Do backgrounds and colors print?
Yes. Background colors and images are printed unless you switch them off with pdf_print_background=false, for a document that saves ink.
## Can I control page breaks?
Yes, with normal CSS. Rules such as break-before, break-after and break-inside work as they do when a browser prints.
## Can the whole document be one long page?
Yes. pdf_fit_one_page puts everything on a single tall page with no breaks.
## How do I convert Markdown to PDF?
Send the Markdown to CurlShot in the markdown field of a POST request and add format=pdf. The answer is the PDF file.
## Can I change how it looks?
Yes. The styles option adds your own CSS to the page, so fonts, colors and spacing can match your brand.
## Can I get an image instead of a PDF?
Yes. Leave format out for a PNG, or ask for jpeg or webp. Set viewport_width to choose how wide the page is.
## Are tables and code blocks supported?
Yes. Tables, fenced code blocks, lists, links, quotes and images are all rendered.
## What size should an Open Graph image be?
1200 by 630 pixels is the size that X, LinkedIn, Facebook and most chat apps show without cropping.
## How do I make one image per page automatically?
Keep one HTML template and fill in the title of each page before you send it to CurlShot. Each request returns the card for that page.
## Can I use a screenshot of the page itself as the image?
Yes. Send the address of the page instead of HTML, with the same window size, and the card is a screenshot of its first screen.
## Is the image rendered again every time someone shares the link?
Not with the cache switched on. The card is rendered once and repeat requests are served from storage, without counting against your allowance.
## How do I take a screenshot of a page that requires login?
Send the session cookie of a signed-in user in the cookies field of a CurlShot request. The page then opens as that user.
## What if the site uses a token and not a cookie?
Send it with the headers option, as a named HTTP header. For HTTP basic authentication use the authorization option.
## Which account should I use?
One made for screenshots, with read-only access to the pages you need and nothing else. Send the request with POST so the cookie is in the body and not in a web address.
## Can it click through a sign-in form?
A cookie or a header is the reliable way. The click option presses one element before the screenshot and scripts runs your own JavaScript on the page, for a step such as closing a dialog.
## How do I take screenshots of multiple URLs at once?
Send them to the CurlShot bulk endpoint as one list. Each item is a normal request with its own address and options, and up to 100 fit in one call.
## How do I get the results?
Ask for the status of the batch, which lists every job and a link to each finished file, or give a webhook address and each result is sent to it when it is ready.
## What does the request on this page do?
It starts one screenshot in the background and sends the result to a webhook. A bulk call is a list of requests like it, started together.
## How is a batch counted?
Like the same screenshots made one by one: each successful render is one screenshot. Failed renders are not counted. The pricing page shows which plans include bulk calls.
## How can an AI agent take a screenshot of a website?
Through the CurlShot MCP server, which gives the agent a take_screenshot tool, or with one HTTP request that returns the image.
## What does the agent get back?
The image itself, or with response_type=json a short JSON answer with a link to the file, which is easier for a tool call to pass on.
## Can the agent read the page as text too?
The service returns images and PDFs. A PDF of a page has text that can be selected and extracted, and a model that reads images can read a screenshot directly.
## How do I keep the cost of an agent under control?
Each plan is a fixed number of screenshots a month, and an access key can be revoked at any time. Repeat requests for the same page can come from the cache at no cost.
---
Source: https://curlshot.com/docs/getting-started
# Getting started
Take your first screenshot in about a minute. Send one request with a page address and get an image back.
Paste this into a terminal. Swap `YOUR_ACCESS_KEY` for your own access key.
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://example.com" \
--output example.png
```
You get a file called `example.png`. It looks like this:

That is the whole idea of CurlShot. You send an address, you get back a screenshot of that page.
## Get your access key
An access key is a short code that tells us the request is yours. It is free to get one.
1. [Create an account](https://curlshot.com/register). You do not need a card.
2. Confirm your email address. The key does not work until you do.
3. Open **API keys** in the dashboard and copy the access key.
The free plan comes with a monthly quota of screenshots, so you can try everything in these docs without paying.
> **Tip**
>
> Treat your access key like a password and keep it on your server. To put a screenshot link in a web page, use a [signed link](https://curlshot.com/docs/signed-links.md). [Authentication and API keys](https://curlshot.com/docs/authentication.md) explains why.
## Take the screenshot from your code
The API is a normal web address, so anything that can fetch a URL can use it. Pick your language:
**cURL**
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://example.com" \
--output example.png
```
**Node.js**
```javascript
import { writeFile } from 'node:fs/promises'
const params = new URLSearchParams({
access_key: 'YOUR_ACCESS_KEY',
url: 'https://example.com',
})
const response = await fetch(`https://curlshot.com/api/v1/screenshot?${params}`)
if (!response.ok) throw new Error((await response.json()).error_message)
await writeFile('example.png', Buffer.from(await response.arrayBuffer()))
```
**Python**
```python
import requests
response = requests.get(
"https://curlshot.com/api/v1/screenshot",
params={"access_key": "YOUR_ACCESS_KEY", "url": "https://example.com"},
)
response.raise_for_status()
with open("example.png", "wb") as f:
f.write(response.content)
```
**PHP**
```php
'YOUR_ACCESS_KEY',
'url' => 'https://example.com',
]);
$image = file_get_contents("https://curlshot.com/api/v1/screenshot?$query");
file_put_contents('example.png', $image);
```
**Go**
```go
package main
import (
"io"
"net/http"
"net/url"
"os"
)
func main() {
params := url.Values{}
params.Set("access_key", "YOUR_ACCESS_KEY")
params.Set("url", "https://example.com")
resp, err := http.Get("https://curlshot.com/api/v1/screenshot?" + params.Encode())
if err != nil {
panic(err)
}
defer resp.Body.Close()
file, _ := os.Create("example.png")
defer file.Close()
io.Copy(file, resp.Body)
}
```
**Ruby**
```ruby
require "net/http"
uri = URI("https://curlshot.com/api/v1/screenshot")
uri.query = URI.encode_www_form(access_key: "YOUR_ACCESS_KEY", url: "https://example.com")
File.binwrite("example.png", Net::HTTP.get(uri))
```
Each sample does the same three things: builds the address, fetches it, and saves the bytes to a file.
## Change what you get
Everything else is an option: one more `name=value` pair in the address. Add an option, get a different screenshot.
This request captures the whole page as a JPEG, sized like an iPhone, with any cookie banner removed:
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY\
&url=https://en.wikipedia.org/wiki/Eiffel_Tower\
&viewport_device=iphone_15_pro\
&full_page=true\
&block_cookie_banners=true\
&format=jpeg" \
--output eiffel.jpg
```

Here is what each option did:
| Option | What it changed |
| --- | --- |
| [`viewport_device`](https://curlshot.com/docs/devices.md) | The page was drawn on a phone-sized screen. |
| [`full_page`](https://curlshot.com/docs/full-page.md) | The capture runs to the bottom of the page, not just the first screen. |
| [`block_cookie_banners`](https://curlshot.com/docs/blocking.md) | A consent pop-up, if the page shows one, is hidden before the capture. |
| [`format`](https://curlshot.com/docs/options.md#format) | The file is a JPEG instead of a PNG. |
## When something goes wrong
A failed request never returns a broken image. It returns a short message in JSON, a text format for structured data, that says what happened.
This request leaves `https://` off the page address:
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=example.com"
```
```json
{
"error_code": "invalid_options",
"error_message": "url: must be a full URL starting with http:// or https://",
"documentation_url": "https://curlshot.com/docs/errors#invalid_options",
"errors": [
{
"field": "url",
"message": "must be a full URL starting with http:// or https://"
}
]
}
```
`error_code` is a fixed word your code can check. `error_message` is written for you to read. The `errors` list comes with `invalid_options` only: it names each option that was refused.
Failed requests are not counted against your quota. The [errors page](https://curlshot.com/docs/errors.md) lists every code with its cause and its fix.
> **Common mistakes**
>
> - **The page address is cut off.** If it contains `&` or `?`, it must be encoded. See [The screenshot URL](https://curlshot.com/docs/screenshot-url.md#encode-the-url).
> - **You saved an error as a screenshot.** If the file will not open, look inside it: it probably holds the JSON error. Check the HTTP status before saving.
> - **A misspelled option.** Unknown options are refused, not ignored. The error message suggests the name you probably meant.
> - **The key is in your front-end code.** Anyone can read it there. Use a [signed link](https://curlshot.com/docs/signed-links.md).
## Where to go next
- [Authentication and API keys](https://curlshot.com/docs/authentication.md): the ways to send your key, and how to keep it safe.
- [The screenshot URL](https://curlshot.com/docs/screenshot-url.md): how the address is put together, and when to use POST.
- [Options reference](https://curlshot.com/docs/options.md): every option on one page.
- [Full-page screenshots](https://curlshot.com/docs/full-page.md), [Devices](https://curlshot.com/docs/devices.md) and [PDF rendering](https://curlshot.com/docs/pdf.md): the most common next steps.
- [Code examples](https://curlshot.com/docs/examples/node.md): longer samples for six languages.
---
Source: https://curlshot.com/docs/authentication
# Authentication and API keys
How to send your access key, what the secret key and signatures are for, and how to rotate, revoke and protect your keys.
Send your access key in a header, a named line that travels with the request, and the request is yours.
```bash
curl "https://curlshot.com/api/v1/screenshot?url=https://example.com" \
-H "X-Access-Key: YOUR_ACCESS_KEY" \
--output example.png
```
You get `example.png`, a screenshot of example.com. Without a key you get this instead:
```json
{
"error_code": "access_key_required",
"error_message": "An access key is required. Pass `access_key` or the `X-Access-Key` header.",
"documentation_url": "https://curlshot.com/docs/errors#access_key_required"
}
```
Every request to CurlShot needs an access key. It tells us whose quota, the monthly number of screenshots in your plan, the screenshot counts against.
## Where to find your key
1. [Create an account](https://curlshot.com/register), or [log in](https://curlshot.com/login).
2. Open **API keys** in the dashboard.
3. Copy the access key.
A key works once the email address of your account is confirmed. Until then, requests answer [`email_not_verified`](https://curlshot.com/docs/errors.md#email_not_verified).
You can have more than one key. Give each one a name, such as "production" or "staging", so you can tell them apart later.
## Three ways to send the key
All three do the same thing. Pick the one that fits your code.
| Where | What you send | Good for |
| --- | --- | --- |
| Query string | `access_key=YOUR_ACCESS_KEY` | Quick tests in a terminal. |
| Header | `X-Access-Key: YOUR_ACCESS_KEY` | Server code. The key stays out of the URL. |
| Header | `Authorization: Bearer YOUR_ACCESS_KEY` | HTTP clients and tools that already have a "bearer token" setting. |
If a request carries the key in more than one place, the query string wins.
Here is the header version in each language:
**cURL**
```bash
curl "https://curlshot.com/api/v1/screenshot?url=https://example.com" \
-H "X-Access-Key: YOUR_ACCESS_KEY" \
--output example.png
```
**Node.js**
```javascript
import { writeFile } from 'node:fs/promises'
const params = new URLSearchParams({ url: 'https://example.com' })
const response = await fetch(`https://curlshot.com/api/v1/screenshot?${params}`, {
headers: { 'X-Access-Key': process.env.SCREENSHOT_ACCESS_KEY },
})
if (!response.ok) throw new Error((await response.json()).error_message)
await writeFile('example.png', Buffer.from(await response.arrayBuffer()))
```
**Python**
```python
import os
import requests
response = requests.get(
"https://curlshot.com/api/v1/screenshot",
params={"url": "https://example.com"},
headers={"X-Access-Key": os.environ["SCREENSHOT_ACCESS_KEY"]},
)
response.raise_for_status()
with open("example.png", "wb") as f:
f.write(response.content)
```
**PHP**
```php
'https://example.com']);
$context = stream_context_create([
'http' => ['header' => 'X-Access-Key: ' . getenv('SCREENSHOT_ACCESS_KEY')],
]);
$image = file_get_contents("https://curlshot.com/api/v1/screenshot?$query", false, $context);
file_put_contents('example.png', $image);
```
**Go**
```go
package main
import (
"io"
"net/http"
"net/url"
"os"
)
func main() {
params := url.Values{}
params.Set("url", "https://example.com")
req, _ := http.NewRequest("GET", "https://curlshot.com/api/v1/screenshot?"+params.Encode(), nil)
req.Header.Set("X-Access-Key", os.Getenv("SCREENSHOT_ACCESS_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
file, _ := os.Create("example.png")
defer file.Close()
io.Copy(file, resp.Body)
}
```
**Ruby**
```ruby
require "net/http"
uri = URI("https://curlshot.com/api/v1/screenshot")
uri.query = URI.encode_www_form(url: "https://example.com")
request = Net::HTTP::Get.new(uri)
request["X-Access-Key"] = ENV["SCREENSHOT_ACCESS_KEY"]
response = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https") { |http| http.request(request) }
File.binwrite("example.png", response.body)
```
The samples read the key from an environment variable. That is a setting stored on your server, outside your code, so the key never ends up in your repository.
## Limits belong to the account, not the key
All your keys share one set of limits: the monthly quota, the number of requests per minute, and the number of renders that may run at the same time.
So a second key does not buy more requests per minute. Ten keys on one account have the same per-minute limit as one key.
Extra keys are for organisation and safety: one per app or environment, each one revocable on its own. [Usage and limits](https://curlshot.com/docs/usage-and-limits.md) explains the three limits.
## Access key and secret key
Each key you create is a pair: an access key and a secret key.
The **access key** identifies you. It travels with every request. Treat it like a password, even though it is the "public" half of the pair.
The **secret key** never travels. You use it on your own server to sign things, and we use our copy to check the signature. A signature is a short code computed from the request and the secret, so only someone who holds the secret can produce it.
You need the secret key in two places:
- [Signed links](https://curlshot.com/docs/signed-links.md), when a screenshot URL has to appear in a web page or an email.
- [Webhooks](https://curlshot.com/docs/async-and-webhooks.md), to check that a message really came from us.
If you only call the API from your server, you can ignore the secret key.
## Keep keys off the browser
Anything in a web page can be read by the person looking at it. That includes JavaScript files, HTML attributes and network requests.
So this is not safe in a public page:
```html
```
A visitor can copy the key and spend your quota on their own screenshots.
You have two safe choices:
- Call the API from your server and send the image to the browser yourself.
- Use a [signed link](https://curlshot.com/docs/signed-links.md). The signature covers every parameter, so a visitor cannot change the page being captured.
## What a signature covers
A signed link has one more parameter, `signature`. You compute it on your server from the link's parameters and your secret key. [Signed links](https://curlshot.com/docs/signed-links.md) shows how, with code.
Three rules decide what a signed link can do:
- **Nothing in it can be changed.** Edit, add or remove a parameter and the answer is [`signature_invalid`](https://curlshot.com/docs/errors.md#signature_invalid) with status `403`.
- **It works for one endpoint.** An endpoint is one address of the API, such as `/screenshot` or `/usage`. A signed screenshot link takes that one screenshot. It cannot be reused to read your usage, your jobs or your stored files.
- **It can have an end date.** Add [`expires`](https://curlshot.com/docs/options.md#expires) before you sign.
### expires
The moment a link stops working, as a Unix time in seconds. Unix time counts the seconds since 1 January 1970, so `1798761600` is 1 January 2027, 00:00 UTC.
There is no default. Leave it out and the link has no end date.
The link works until that moment and never after. Because `expires` is part of the signed parameters, nobody can move the date. An expired link answers like this:
```json
{
"error_code": "request_expired",
"error_message": "This request has expired: its `expires` time is in the past. Create a new link with a later `expires`.",
"documentation_url": "https://curlshot.com/docs/errors#request_expired"
}
```
> **Note**
>
> The other endpoints (`/usage`, `/jobs/:id`, `/batches/:id`, `/files/:id` and `/bulk`) can be signed too, each with its own short set of signed parameters. [Signed links](https://curlshot.com/docs/signed-links.md) has the details.
## Accept signed requests only
Each key has a **Require signature** setting in the dashboard. Turn it on, and that key refuses every request that has no valid `signature`.
An unsigned request then fails like this:
```json
{
"error_code": "signature_required",
"error_message": "This access key only accepts signed requests. Add a `signature` parameter.",
"documentation_url": "https://curlshot.com/docs/errors#signature_required"
}
```
This is the right setting for a key that appears in public pages. Even if someone copies the access key from a link, they cannot make new requests with it.
Without the setting, someone could delete the `signature` from your link and send their own parameters with your access key.
> **Tip**
>
> Use two keys. Keep one for your server, with no signature needed. Use a second one with **Require signature** on for links that end up in a browser.
## Rotate a key
Rotating means swapping an old key for a new one. Do it on a schedule, or right away if a key may have leaked.
1. Create a new key in the dashboard.
2. Put the new key in your server settings and deploy.
3. Check that requests work with the new key.
4. Revoke the old key.
Doing it in this order means there is no moment when your app has no working key.
## Revoke a key
Revoking switches a key off for good. Open **API keys**, pick the key and revoke it.
From then on, every request with that key fails with [`access_key_invalid`](https://curlshot.com/docs/errors.md#access_key_invalid) and status `401`. Signed links made with that key stop working too.
> **Common mistakes**
>
> - **The key is in a public repository.** Revoke it and create a new one. Deleting the commit is not enough, because the old version can still be found.
> - **The key is in front-end code.** Move the call to your server, or switch to [signed links](https://curlshot.com/docs/signed-links.md).
> - **You mixed up `Authorization` and `authorization`.** The `Authorization: Bearer` header on your request carries your access key to us. The [`authorization`](https://curlshot.com/docs/options.md#authorization) option is something else: a login for the site being captured. It goes only to the site in `url`, and so do `Cookie`, `Authorization` and API-key style entries in [`headers`](https://curlshot.com/docs/options.md#headers). Other hosts the page loads files from never see them.
> - **You created more keys to get a higher rate limit.** The limits are per account. See [Usage and limits](https://curlshot.com/docs/usage-and-limits.md) for what each plan allows.
> - **You signed with the wrong secret.** The secret must belong to the same access key that is in the request. Otherwise you get [`signature_invalid`](https://curlshot.com/docs/errors.md#signature_invalid).
## Where to go next
- [The screenshot URL](https://curlshot.com/docs/screenshot-url.md): how a request is put together.
- [Signed links](https://curlshot.com/docs/signed-links.md): safe screenshot URLs for public pages.
- [Usage and limits](https://curlshot.com/docs/usage-and-limits.md): check how much of your quota is left.
- [Errors](https://curlshot.com/docs/errors.md): every error code, including the key and signature ones.
---
Source: https://curlshot.com/docs/screenshot-url
# The screenshot URL
How a screenshot request is built, when to use GET or POST, how to encode the page address, and what the response contains.
A screenshot request is one web address. This one captures example.com as a JPEG, 800 pixels wide:
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://example.com&format=jpeg&viewport_width=800" \
--output example.jpg
```
You get `example.jpg`. The response body is the image itself, with the header `Content-Type: image/jpeg`.
## Anatomy of the request
Here is the same address, split into its parts:
```text
https://curlshot.com/api/v1/screenshot the endpoint
?access_key=YOUR_ACCESS_KEY who is asking
&url=https://example.com what to capture
&format=jpeg an option
&viewport_width=800 another option
```
The endpoint is always `https://curlshot.com/api/v1/screenshot`. The address `https://curlshot.com/api/v1/take` is an alias and works the same way.
After the `?` come the options. Each one is `name=value`, and they are joined with `&`. The order does not matter.
You need exactly one source: [`url`](https://curlshot.com/docs/options.md#url), [`html`](https://curlshot.com/docs/options.md#html) or [`markdown`](https://curlshot.com/docs/options.md#markdown). Everything else is optional and has a default. The [Options reference](https://curlshot.com/docs/options.md) lists them all.
### url
Address of the page to capture.
There is no default. Send it, or send [`html` or `markdown`](https://curlshot.com/docs/html-and-markdown.md) in its place.
The address has to follow four rules:
- **It is a full address.** It starts with `http://` or `https://` and is at most 4096 characters long. `example.com` alone returns [`invalid_options`](https://curlshot.com/docs/errors.md#invalid_options).
- **It is public.** `localhost` and private network addresses are refused with [`host_not_allowed`](https://curlshot.com/docs/errors.md#host_not_allowed).
- **It has no username and password in it.** For a page behind a login, use the [`authorization`](https://curlshot.com/docs/options.md#authorization) option.
- **Its port is a web port.** The port is the number after the host name, as in `https://your-app.example:8443`. Most addresses have none and use `80` or `443`.
Ports `80` and `443` always work. So do most ports from `1024` up, such as `3000`, `8080` or `8443`.
Every other port below `1024` is refused. So are the ports of well-known services that are not websites: databases, caches, message queues, remote desktops and the like. Examples are `3306`, `5432`, `6379`, `9200`, `11211` and `27017`. A refused port answers `host_not_allowed`.
## GET or POST
You can send the same options in two ways.
**GET** puts the options in the address, as above. It works anywhere a URL works: a terminal, an `
` tag with a [signed link](https://curlshot.com/docs/signed-links.md), a browser tab.
**POST** puts the options in a JSON body. JSON is a text format for structured data. Set the header `Content-Type: application/json`.
```bash
curl -X POST "https://curlshot.com/api/v1/screenshot" \
-H "X-Access-Key: YOUR_ACCESS_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com",
"format": "jpeg",
"viewport_width": 800
}' \
--output example.jpg
```
The result is the same `example.jpg`.
Use POST when:
- You send [`html`](https://curlshot.com/docs/html-and-markdown.md), `markdown`, [`styles`](https://curlshot.com/docs/customize.md) or `scripts`. These are long and full of characters that are awkward in a URL.
- A value is long, such as a big cookie or a list of headers.
- You want the access key out of the URL. Addresses often end up in server logs.
In JSON you can use real types: `true` instead of `"true"`, `800` instead of `"800"`, and arrays for lists.
A body that is not valid JSON, or is not a JSON object, returns [`invalid_request`](https://curlshot.com/docs/errors.md#invalid_request).
## Encode the URL
The page address you want to capture is itself a URL, and it sits inside another URL. If it contains `&`, `?`, `=`, `#` or a space, the two get mixed up.
Take this page address:
```text
https://news.ycombinator.com/front?day=2024-01-15&p=2
```
Paste it in as it is, and the request breaks:
```text
https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://news.ycombinator.com/front?day=2024-01-15&p=2
```
The `&` ends the `url` value early. We receive `url=https://news.ycombinator.com/front?day=2024-01-15` and a separate option called `p`. There is no option called `p`, so the request fails with [`invalid_options`](https://curlshot.com/docs/errors.md#invalid_options) and the message `p: is not a known option`.
The fix is percent-encoding. Each special character is replaced by `%` and a two-character code, so it can no longer be mistaken for part of the outer address.
```text
https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https%3A%2F%2Fround-lake.dustinice.workers.dev%3A443%2Fhttps%2Fnews.ycombinator.com%2Ffront%3Fday%3D2024-01-15%26p%3D2
```
Now `&` has become `%26` and `?` has become `%3F`. The whole page address arrives as one value.
You do not need to do this by hand. Every language has a function for it:
**cURL**
```bash
# -G sends a GET request; --data-urlencode encodes each value for you.
curl -G "https://curlshot.com/api/v1/screenshot" \
--data-urlencode "access_key=YOUR_ACCESS_KEY" \
--data-urlencode "url=https://news.ycombinator.com/front?day=2024-01-15&p=2" \
--output hn.png
```
**Node.js**
```javascript
// URLSearchParams encodes every value.
const params = new URLSearchParams({
access_key: 'YOUR_ACCESS_KEY',
url: 'https://news.ycombinator.com/front?day=2024-01-15&p=2',
})
const requestUrl = `https://curlshot.com/api/v1/screenshot?${params}`
```
**Python**
```python
from urllib.parse import urlencode
# urlencode encodes every value.
query = urlencode({
"access_key": "YOUR_ACCESS_KEY",
"url": "https://news.ycombinator.com/front?day=2024-01-15&p=2",
})
request_url = f"https://curlshot.com/api/v1/screenshot?{query}"
```
**PHP**
```php
'YOUR_ACCESS_KEY',
'url' => 'https://news.ycombinator.com/front?day=2024-01-15&p=2',
]);
$requestUrl = "https://curlshot.com/api/v1/screenshot?$query";
```
**Go**
```go
package main
import (
"fmt"
"net/url"
)
func main() {
// url.Values encodes every value.
params := url.Values{}
params.Set("access_key", "YOUR_ACCESS_KEY")
params.Set("url", "https://news.ycombinator.com/front?day=2024-01-15&p=2")
fmt.Println("https://curlshot.com/api/v1/screenshot?" + params.Encode())
}
```
**Ruby**
```ruby
require "uri"
# encode_www_form encodes every value.
query = URI.encode_www_form(
access_key: "YOUR_ACCESS_KEY",
url: "https://news.ycombinator.com/front?day=2024-01-15&p=2"
)
request_url = "https://curlshot.com/api/v1/screenshot?#{query}"
```
> **Note**
>
> A plain address such as `https://example.com` has no special characters, so it works without encoding. Encode anyway. It costs nothing and it keeps working when the address changes.
With POST there is nothing to encode. The address goes into the JSON body as an ordinary string.
## Booleans and lists
A boolean is an on or off option, such as [`full_page`](https://curlshot.com/docs/options.md#full_page). In a query string, these all mean on: `true`, `1`, `yes`, `on`. These all mean off: `false`, `0`, `no`, `off`.
Some options take a list: [`hide_selectors`](https://curlshot.com/docs/options.md#hide_selectors), [`block_resources`](https://curlshot.com/docs/options.md#block_resources), [`block_requests`](https://curlshot.com/docs/options.md#block_requests), [`headers`](https://curlshot.com/docs/options.md#headers) and [`cookies`](https://curlshot.com/docs/options.md#cookies). You can write a list in two ways:
```text
block_resources=font,media
block_resources=font&block_resources=media
```
In a POST body, send a JSON array: `"block_resources": ["font", "media"]`.
Any other option may appear only once. An empty value, such as `full_page=`, counts as not set, so the default applies.
## Get JSON instead of the file
By default the response is the file. Add [`response_type=json`](https://curlshot.com/docs/options.md#response_type) to get a description of the file and a link to it.
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://example.com&response_type=json"
```
```json
{
"id": "a187741109b34d6c991bdab9b2c5da03",
"url": "https://curlshot.com/api/v1/files/a187741109b34d6c991bdab9b2c5da03.png?expires=1791155483&token=Zk3vQ8sT1nY6bW2xLr9cHd4JmPq7uAe0GfKoIiNtVyE",
"format": "png",
"width": 1280,
"height": 1024,
"bytes": 48213,
"render_ms": 1240,
"cached": false,
"expires_at": "2026-10-04T23:11:23.563Z"
}
```
This suits code that wants to pass a link along, not the bytes.
The `url` is a link to the stored file. It carries its own token, so it opens without an access key and you can hand it to a browser or another service. It stops working at `expires_at`. Download the file if you need it for longer.
| Field | What it holds |
| --- | --- |
| `id` | The id of this screenshot. |
| `url` | The expiring link to the file. |
| `format` | `png`, `jpeg`, `webp`, `pdf`, `mp4`, `webm` or `gif`. |
| `width`, `height` | Size of the image or the video in pixels. |
| `bytes` | Size of the file. |
| `render_ms` | How long the render took, in milliseconds. |
| `cached` | `true` when a stored copy was served. See [Caching](https://curlshot.com/docs/caching.md). |
| `expires_at` | When the link and the stored file expire. |
## Response headers
Every answer carries `X-Reference-Id`, including errors. Quote it when you [contact us](https://curlshot.com/contact).
A request that gets as far as a render also tells you where your limits stand, whether the answer is a file, JSON or a render error:
| Header | What it tells you |
| --- | --- |
| `X-Quota-Limit` | Screenshots your plan includes in the current period. |
| `X-Quota-Remaining` | Screenshots you have left: what remains of the plan, plus any bonus screenshots. |
| `X-Quota-Reset` | When the period resets, as an ISO date. |
| `X-RateLimit-Limit` | Requests your account may send per minute. |
| `X-RateLimit-Remaining` | Requests left in the current minute. |
| `X-RateLimit-Reset` | When the minute resets, in Unix seconds. |
| `X-Concurrency-Limit` | Renders your account may run at the same time. |
| `X-Concurrency-Remaining` | Free render slots right now. |
A request that is refused before that point, for example with `invalid_options` or a wrong key, has only `X-Reference-Id`.
A successful answer adds these:
| Header | What it tells you |
| --- | --- |
| `X-Cache` | `HIT` if a stored copy was served, `MISS` if the page was rendered. See [Caching](https://curlshot.com/docs/caching.md). |
| `X-Render-Ms` | How long the render took, in milliseconds. |
| `X-Image-Width`, `X-Image-Height` | Size of the image in pixels. Sent when the answer is the image itself. |
A `429` answer also has `Retry-After`: the number of seconds to wait before you try again. [Usage and limits](https://curlshot.com/docs/usage-and-limits.md) explains the three limits.
> **Common mistakes**
>
> - **A misspelled option.** Unknown options are not ignored. `fullpage=true` returns `invalid_options` with a hint: did you mean `full_page`?
> - **The same option twice.** Only list options may repeat. Two `format` values return `invalid_options`.
> - **A username and password in `url`.** An address like `https://user:pass@example.com` returns `invalid_options`. Use the [`authorization`](https://curlshot.com/docs/options.md#authorization) option.
> - **A local address or an unusual port.** Both return `host_not_allowed`. See the [`url`](https://curlshot.com/docs/screenshot-url.md#url) rules above.
> - **Saving an error as an image.** Check the HTTP status before you write the file. Errors are JSON, as shown on the [errors page](https://curlshot.com/docs/errors.md).
## Where to go next
- [Options reference](https://curlshot.com/docs/options.md): every option with its default and limits.
- [Authentication and API keys](https://curlshot.com/docs/authentication.md): the three ways to send your key.
- [HTML and Markdown input](https://curlshot.com/docs/html-and-markdown.md): render your own markup with POST.
- [Signed links](https://curlshot.com/docs/signed-links.md): put a screenshot URL in a public page safely.
---
Source: https://curlshot.com/docs/options
# Options reference
Every option of the screenshot API on one page, with its default, its limits and an example value.
An option is one `name=value` pair added to the request. This request uses three of them:
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://example.com&format=webp&viewport_width=1440&dark_mode=true" \
--output example.webp
```
You get `example.webp`: example.com in a 1440 pixel wide window, as a WebP file, in its dark theme.
Options work the same in a GET query string and in a POST JSON body. [The screenshot URL](https://curlshot.com/docs/screenshot-url.md) explains both, and how to write booleans and lists.
A misspelled option is never silently ignored. You get [`invalid_options`](https://curlshot.com/docs/errors.md#invalid_options) with a hint naming the option you probably meant: `fullpage` gets "did you mean `full_page`?".
## All options at a glance
| Option | Group | What it does | Default |
| --- | --- | --- | --- |
| [`url`](https://curlshot.com/docs/options.md#url) | Source | Address of the page to capture. | |
| [`html`](https://curlshot.com/docs/options.md#html) | Source | HTML to render instead of a URL. | |
| [`markdown`](https://curlshot.com/docs/options.md#markdown) | Source | Markdown to render as a styled page instead of a URL. | |
| [`format`](https://curlshot.com/docs/options.md#format) | Output | File format of the result. mp4, webm and gif record a video of the page. | `png` |
| [`image_quality`](https://curlshot.com/docs/options.md#image_quality) | Output | Compression quality for jpeg and webp. | `80` |
| [`image_width`](https://curlshot.com/docs/options.md#image_width) | Output | Resize the final image to this width. | |
| [`image_height`](https://curlshot.com/docs/options.md#image_height) | Output | Resize the final image to this height. | |
| [`omit_background`](https://curlshot.com/docs/options.md#omit_background) | Output | Keep the page background transparent (png and webp). | `false` |
| [`response_type`](https://curlshot.com/docs/options.md#response_type) | Output | Return the file itself, or JSON with a link to it. | `by_format` |
| [`viewport_width`](https://curlshot.com/docs/options.md#viewport_width) | Viewport | Width of the browser window. | `1280` |
| [`viewport_height`](https://curlshot.com/docs/options.md#viewport_height) | Viewport | Height of the browser window. A video uses 720 unless you set it. | `1024` |
| [`device_scale_factor`](https://curlshot.com/docs/options.md#device_scale_factor) | Viewport | Pixel density; 2 gives a retina image. | `1` |
| [`viewport_device`](https://curlshot.com/docs/options.md#viewport_device) | Viewport | Emulate a phone, tablet or laptop preset. | |
| [`viewport_mobile`](https://curlshot.com/docs/options.md#viewport_mobile) | Viewport | Render the mobile layout (honours the viewport meta tag). | `false` |
| [`viewport_landscape`](https://curlshot.com/docs/options.md#viewport_landscape) | Viewport | Rotate the viewport to landscape. | `false` |
| [`full_page`](https://curlshot.com/docs/options.md#full_page) | Capture | Capture the whole page, not just the first screen. | `false` |
| [`full_page_scroll`](https://curlshot.com/docs/options.md#full_page_scroll) | Capture | Scroll through the page first so lazy-loaded images appear. | `true` |
| [`full_page_max_height`](https://curlshot.com/docs/options.md#full_page_max_height) | Capture | Cut a full-page capture off at this height. | `20000` |
| [`selector`](https://curlshot.com/docs/options.md#selector) | Capture | Capture only the first element matching this CSS selector. | |
| [`clip_x`](https://curlshot.com/docs/options.md#clip_x) | Capture | Left edge of the area to capture. | |
| [`clip_y`](https://curlshot.com/docs/options.md#clip_y) | Capture | Top edge of the area to capture. | |
| [`clip_width`](https://curlshot.com/docs/options.md#clip_width) | Capture | Width of the area to capture. | |
| [`clip_height`](https://curlshot.com/docs/options.md#clip_height) | Capture | Height of the area to capture. | |
| [`wait_until`](https://curlshot.com/docs/options.md#wait_until) | Waiting | Page event that marks the page as loaded. | `load` |
| [`delay`](https://curlshot.com/docs/options.md#delay) | Waiting | Extra time to wait after the page has loaded. | `0` |
| [`timeout`](https://curlshot.com/docs/options.md#timeout) | Waiting | Give up if the page is not ready after this long. | `30` |
| [`wait_for_selector`](https://curlshot.com/docs/options.md#wait_for_selector) | Waiting | Wait until this element is visible before capturing. | |
| [`dark_mode`](https://curlshot.com/docs/options.md#dark_mode) | Customize | Ask the page for its dark theme. | `false` |
| [`reduced_motion`](https://curlshot.com/docs/options.md#reduced_motion) | Customize | Ask the page to turn animations off. | `false` |
| [`media_type`](https://curlshot.com/docs/options.md#media_type) | Customize | CSS media type to render with. | `screen` |
| [`hide_selectors`](https://curlshot.com/docs/options.md#hide_selectors) | Customize | Hide every element matching these CSS selectors. | |
| [`styles`](https://curlshot.com/docs/options.md#styles) | Customize | CSS to add to the page. | |
| [`scripts`](https://curlshot.com/docs/options.md#scripts) | Customize | JavaScript to run on the page before the capture. | |
| [`click`](https://curlshot.com/docs/options.md#click) | Customize | Click the first element matching this selector before the capture. | |
| [`user_agent`](https://curlshot.com/docs/options.md#user_agent) | Request | User-Agent header the browser sends. | |
| [`headers`](https://curlshot.com/docs/options.md#headers) | Request | Extra HTTP headers, as "Name: value". | |
| [`cookies`](https://curlshot.com/docs/options.md#cookies) | Request | Cookies to set, as "name=value; Domain=example.com". | |
| [`authorization`](https://curlshot.com/docs/options.md#authorization) | Request | Authorization header sent to the target site only. | |
| [`time_zone`](https://curlshot.com/docs/options.md#time_zone) | Request | IANA time zone the page sees. | |
| [`block_ads`](https://curlshot.com/docs/options.md#block_ads) | Blocking | Block requests to ad networks. | `false` |
| [`block_trackers`](https://curlshot.com/docs/options.md#block_trackers) | Blocking | Block analytics and tracking scripts. | `false` |
| [`block_cookie_banners`](https://curlshot.com/docs/options.md#block_cookie_banners) | Blocking | Hide cookie consent banners. | `false` |
| [`block_chats`](https://curlshot.com/docs/options.md#block_chats) | Blocking | Block live-chat widgets. | `false` |
| [`block_resources`](https://curlshot.com/docs/options.md#block_resources) | Blocking | Block whole kinds of resources. | |
| [`block_requests`](https://curlshot.com/docs/options.md#block_requests) | Blocking | Block requests whose URL matches these patterns (* is a wildcard). | |
| [`pdf_paper_format`](https://curlshot.com/docs/options.md#pdf_paper_format) | PDF | Paper size of the PDF. | `a4` |
| [`pdf_landscape`](https://curlshot.com/docs/options.md#pdf_landscape) | PDF | Use landscape pages. | `false` |
| [`pdf_print_background`](https://curlshot.com/docs/options.md#pdf_print_background) | PDF | Print background colors and images. | `true` |
| [`pdf_margin`](https://curlshot.com/docs/options.md#pdf_margin) | PDF | Margin on all four sides. | |
| [`pdf_margin_top`](https://curlshot.com/docs/options.md#pdf_margin_top) | PDF | Top margin; overrides pdf_margin. | |
| [`pdf_margin_right`](https://curlshot.com/docs/options.md#pdf_margin_right) | PDF | Right margin; overrides pdf_margin. | |
| [`pdf_margin_bottom`](https://curlshot.com/docs/options.md#pdf_margin_bottom) | PDF | Bottom margin; overrides pdf_margin. | |
| [`pdf_margin_left`](https://curlshot.com/docs/options.md#pdf_margin_left) | PDF | Left margin; overrides pdf_margin. | |
| [`pdf_fit_one_page`](https://curlshot.com/docs/options.md#pdf_fit_one_page) | PDF | Put the whole page on a single tall PDF page. | `false` |
| [`video_duration`](https://curlshot.com/docs/options.md#video_duration) | Video | Length of the video. Left out, it follows the height of the page. | |
| [`video_max_duration`](https://curlshot.com/docs/options.md#video_max_duration) | Video | Longest the video may get when its length follows the page. A taller page then scrolls faster. | `30` |
| [`video_fps`](https://curlshot.com/docs/options.md#video_fps) | Video | Frames per second. A gif takes at most 15. | `24` |
| [`video_scroll`](https://curlshot.com/docs/options.md#video_scroll) | Video | Scroll from the top of the page to the bottom while recording. | `true` |
| [`video_scroll_back`](https://curlshot.com/docs/options.md#video_scroll_back) | Video | Scroll back to the top at the end, so the video loops cleanly. | `false` |
| [`video_scroll_easing`](https://curlshot.com/docs/options.md#video_scroll_easing) | Video | How the scroll moves: a soft start and stop, or one even speed. | `ease_in_out` |
| [`cache`](https://curlshot.com/docs/options.md#cache) | Cache | Serve a stored copy when the same request was made before. | `false` |
| [`cache_ttl`](https://curlshot.com/docs/options.md#cache_ttl) | Cache | How long a cached copy stays valid. | `14400` |
| [`cache_key`](https://curlshot.com/docs/options.md#cache_key) | Cache | Change this value to force a fresh render. | |
| [`async`](https://curlshot.com/docs/options.md#async) | Async and webhooks | Return at once and render in the background. | `false` |
| [`webhook_url`](https://curlshot.com/docs/options.md#webhook_url) | Async and webhooks | Address that receives the result when the render is done. | |
| [`webhook_sign`](https://curlshot.com/docs/options.md#webhook_sign) | Async and webhooks | Sign the webhook body so you can verify it came from us. | `true` |
| [`access_key`](https://curlshot.com/docs/options.md#access_key) | Authentication | Your API access key. | |
| [`signature`](https://curlshot.com/docs/options.md#signature) | Authentication | HMAC-SHA256 signature of the query string, for signed links. | |
| [`expires`](https://curlshot.com/docs/options.md#expires) | Authentication | Unix time in seconds after which the request is refused. Put it in a signed link to give the link a lifetime. | |
## Source
These options say what to render. You always need exactly one of them. Use `url` for a page that is already online. Use `html` or `markdown` when you have the content yourself, such as an invoice or a social card.
A `url` must be a full `http://` or `https://` address on the public internet. [The screenshot URL](https://curlshot.com/docs/screenshot-url.md#url) lists the rules, including which ports are accepted.
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://example.com" --output example.png
```
### url
Address of the page to capture.
There is no default; leave it out and it is not applied.
Type: text.
Example: `url=https://example.com`
### html
HTML to render instead of a URL.
There is no default; leave it out and it is not applied.
Type: text.
Example: `html=%3Ch1%3EHello%3C/h1%3E`
### markdown
Markdown to render as a styled page instead of a URL.
There is no default; leave it out and it is not applied.
Type: text.
Example: `markdown=%23%20Hello`
Read more: [The screenshot URL](https://curlshot.com/docs/screenshot-url.md), [HTML and Markdown input](https://curlshot.com/docs/html-and-markdown.md).
## Output
Reach for these when the file itself needs to change: a smaller JPEG for a thumbnail, a transparent PNG, or a JSON answer with a link in place of the bytes. The page is drawn the same way. Only what you receive is different.
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://example.com&format=jpeg&image_quality=70&image_width=640" --output thumb.jpg
```
### format
File format of the result. mp4, webm and gif record a video of the page.
The default is `png`.
Type: one of a fixed list. Allowed values: `png`, `jpeg`, `webp`, `pdf`, `mp4`, `webm`, `gif`.
Example: `format=png`
### image_quality
Compression quality for jpeg and webp.
The default is `80`.
Type: whole number. From 1 to 100.
Example: `image_quality=80`
### image_width
Resize the final image to this width.
There is no default; leave it out and it is not applied.
Type: whole number. From 1 to 8000 pixels.
Example: `image_width=640`
### image_height
Resize the final image to this height.
There is no default; leave it out and it is not applied.
Type: whole number. From 1 to 8000 pixels.
Example: `image_height=400`
### omit_background
Keep the page background transparent (png and webp).
The default is `false`.
Type: true or false.
Example: `omit_background=true`
### response_type
Return the file itself, or JSON with a link to it.
The default is `by_format`.
Type: one of a fixed list. Allowed values: `by_format`, `json`.
Example: `response_type=json`
Read more: [The screenshot URL](https://curlshot.com/docs/screenshot-url.md).
## Viewport
The viewport is the browser window the page is drawn in. Its size decides which layout a site shows, so this is the group to use when you want the phone version, a wide desktop version, or a sharper image for high-density screens. A device preset sets several of these at once.
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://example.com&viewport_device=iphone_15_pro" --output phone.png
```
### viewport_width
Width of the browser window.
The default is `1280` pixels.
Type: whole number. From 100 to 3840 pixels.
Example: `viewport_width=1280`
### viewport_height
Height of the browser window. A video uses 720 unless you set it.
The default is `1024` pixels.
Type: whole number. From 100 to 4320 pixels.
Example: `viewport_height=1024`
### device_scale_factor
Pixel density; 2 gives a retina image.
The default is `1`.
Type: number. From 1 to 3.
Example: `device_scale_factor=2`
### viewport_device
Emulate a phone, tablet or laptop preset.
There is no default; leave it out and it is not applied.
Type: one of a fixed list. Allowed values: every name on the [Devices](https://curlshot.com/docs/devices.md) page.
Example: `viewport_device=iphone_15_pro`
### viewport_mobile
Render the mobile layout (honours the viewport meta tag).
The default is `false`.
Type: true or false.
Example: `viewport_mobile=true`
### viewport_landscape
Rotate the viewport to landscape.
The default is `false`.
Type: true or false.
Example: `viewport_landscape=true`
Read more: [Devices](https://curlshot.com/docs/devices.md).
## Capture
These decide which part of the page ends up in the screenshot. By default you get the first screen. Use this group to capture the page from top to bottom, one element, or a rectangle you choose.
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://example.com&full_page=true" --output full.png
```
### full_page
Capture the whole page, not just the first screen.
The default is `false`.
Type: true or false.
Example: `full_page=true`
### full_page_scroll
Scroll through the page first so lazy-loaded images appear.
The default is `true`.
Type: true or false.
Example: `full_page_scroll=false`
### full_page_max_height
Cut a full-page capture off at this height.
The default is `20000` pixels.
Type: whole number. From 100 to 30000 pixels.
Example: `full_page_max_height=10000`
### selector
Capture only the first element matching this CSS selector.
There is no default; leave it out and it is not applied.
Type: text.
Example: `selector=%23pricing`
### clip_x
Left edge of the area to capture.
There is no default; leave it out and it is not applied.
Type: whole number. 0 or more pixels.
Example: `clip_x=0`
### clip_y
Top edge of the area to capture.
There is no default; leave it out and it is not applied.
Type: whole number. 0 or more pixels.
Example: `clip_y=0`
### clip_width
Width of the area to capture.
There is no default; leave it out and it is not applied.
Type: whole number. From 1 to 8000 pixels.
Example: `clip_width=600`
### clip_height
Height of the area to capture.
There is no default; leave it out and it is not applied.
Type: whole number. From 1 to 30000 pixels.
Example: `clip_height=400`
Read more: [Full-page screenshots](https://curlshot.com/docs/full-page.md), [Capturing an element](https://curlshot.com/docs/element.md).
## Waiting
Pages do not appear all at once. These options decide the moment the capture is taken. Use them when a screenshot comes back half-loaded, or when a slow page runs out of time.
`delay` and `timeout` are in seconds, not milliseconds: `delay=1` waits one second, and `timeout` can be from 1 to 90.
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://example.com&wait_until=networkidle&delay=1" --output ready.png
```
### wait_until
Page event that marks the page as loaded.
The default is `load`.
Type: one of a fixed list. Allowed values: `load`, `domcontentloaded`, `networkidle`, `commit`.
Example: `wait_until=networkidle`
### delay
Extra time to wait after the page has loaded.
The default is `0` seconds.
Type: number. From 0 to 30 seconds.
Example: `delay=2`
### timeout
Give up if the page is not ready after this long.
The default is `30` seconds.
Type: number. From 1 to 90 seconds.
Example: `timeout=60`
### wait_for_selector
Wait until this element is visible before capturing.
There is no default; leave it out and it is not applied.
Type: text.
Example: `wait_for_selector=.chart-ready`
Read more: [Waiting and timing](https://curlshot.com/docs/waiting.md).
## Customize
Use these to change how the page looks before the capture. You can ask for the dark theme, hide an element that is in the way, add your own CSS, run a bit of JavaScript, or click a button.
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://developer.mozilla.org&dark_mode=true&hide_selectors=.top-banner" --output dark.png
```
### dark_mode
Ask the page for its dark theme.
The default is `false`.
Type: true or false.
Example: `dark_mode=true`
### reduced_motion
Ask the page to turn animations off.
The default is `false`.
Type: true or false.
Example: `reduced_motion=true`
### media_type
CSS media type to render with.
The default is `screen`.
Type: one of a fixed list. Allowed values: `screen`, `print`.
Example: `media_type=print`
### hide_selectors
Hide every element matching these CSS selectors.
There is no default; leave it out and it is not applied.
Type: list of text values.
Example: `hide_selectors=.cookie-bar,%23chat`
### styles
CSS to add to the page.
There is no default; leave it out and it is not applied.
Type: text.
Example: `styles=body%7Bbackground:%23fff%7D`
### scripts
JavaScript to run on the page before the capture.
There is no default; leave it out and it is not applied.
Type: text.
Example: `scripts=document.title%3D'Hi'`
### click
Click the first element matching this selector before the capture.
There is no default; leave it out and it is not applied.
Type: text.
Example: `click=%23accept`
Read more: [Dark mode and emulation](https://curlshot.com/docs/dark-mode-and-emulation.md), [Custom CSS, JavaScript and clicks](https://curlshot.com/docs/customize.md).
## Request
These change what our browser sends to the site. Reach for them when the page needs a login cookie, a special header, a certain time zone, or a different browser name.
Login details stay with the site you capture. `authorization`, and any entry in `headers` that carries a credential (`Cookie`, `Authorization`, or a name containing words like `token` or `key`), is sent only to the origin of your `url`. The origin is its scheme, host and port together. Other hosts the page loads files from, or redirects to, do not receive them.
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://example.com&time_zone=Europe/Berlin&headers=Accept-Language:%20de" --output berlin.png
```
### user_agent
User-Agent header the browser sends.
There is no default; leave it out and it is not applied.
Type: text.
Example: `user_agent=MyBot/1.0`
### headers
Extra HTTP headers, as "Name: value".
There is no default; leave it out and it is not applied.
Type: name and value pairs.
Example: `headers=X-Preview:%201`
### cookies
Cookies to set, as "name=value; Domain=example.com".
There is no default; leave it out and it is not applied.
Type: list of name and value pairs.
Example: `cookies=session%3Dabc123`
### authorization
Authorization header sent to the target site only.
There is no default; leave it out and it is not applied.
Type: text.
Example: `authorization=Basic%20dXNlcjpwYXNz`
### time_zone
IANA time zone the page sees.
There is no default; leave it out and it is not applied.
Type: text.
Example: `time_zone=Europe/Berlin`
Read more: [How to screenshot a page behind a login](https://curlshot.com/docs/guides/screenshot-behind-login.md).
## Blocking
Real pages come with noise: ads, consent pop-ups, chat bubbles. These options remove the common ones so the screenshot shows the content. Blocking is best-effort, so keep `hide_selectors` in mind for anything that slips through.
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://example.com&block_ads=true&block_cookie_banners=true" --output clean.png
```
### block_ads
Block requests to ad networks.
The default is `false`.
Type: true or false.
Example: `block_ads=true`
### block_trackers
Block analytics and tracking scripts.
The default is `false`.
Type: true or false.
Example: `block_trackers=true`
### block_cookie_banners
Hide cookie consent banners.
The default is `false`.
Type: true or false.
Example: `block_cookie_banners=true`
### block_chats
Block live-chat widgets.
The default is `false`.
Type: true or false.
Example: `block_chats=true`
### block_resources
Block whole kinds of resources.
There is no default; leave it out and it is not applied.
Type: list from a fixed list. Allowed values: `document`, `stylesheet`, `image`, `media`, `font`, `script`, `xhr`, `fetch`, `websocket`, `texttrack`, `eventsource`, `manifest`, `other`.
Example: `block_resources=font,media`
### block_requests
Block requests whose URL matches these patterns (* is a wildcard).
There is no default; leave it out and it is not applied.
Type: list of text values.
Example: `block_requests=*.example.com/ads/*`
Read more: [Blocking ads, cookie banners, trackers and chats](https://curlshot.com/docs/blocking.md).
## PDF
These apply only when `format=pdf`. Use them to pick the paper size, turn the page sideways, add margins, or put a whole page on one long sheet. With any other format they have no effect.
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://example.com&format=pdf&pdf_paper_format=letter&pdf_margin=10mm" --output example.pdf
```
### pdf_paper_format
Paper size of the PDF.
The default is `a4`.
Type: one of a fixed list. Allowed values: `a0`, `a1`, `a2`, `a3`, `a4`, `a5`, `a6`, `letter`, `legal`, `tabloid`, `ledger`.
Example: `pdf_paper_format=letter`
### pdf_landscape
Use landscape pages.
The default is `false`.
Type: true or false.
Example: `pdf_landscape=true`
### pdf_print_background
Print background colors and images.
The default is `true`.
Type: true or false.
Example: `pdf_print_background=false`
### pdf_margin
Margin on all four sides.
There is no default; leave it out and it is not applied.
Type: text.
Example: `pdf_margin=10mm`
### pdf_margin_top
Top margin; overrides pdf_margin.
There is no default; leave it out and it is not applied.
Type: text.
Example: `pdf_margin_top=20mm`
### pdf_margin_right
Right margin; overrides pdf_margin.
There is no default; leave it out and it is not applied.
Type: text.
Example: `pdf_margin_right=10mm`
### pdf_margin_bottom
Bottom margin; overrides pdf_margin.
There is no default; leave it out and it is not applied.
Type: text.
Example: `pdf_margin_bottom=20mm`
### pdf_margin_left
Left margin; overrides pdf_margin.
There is no default; leave it out and it is not applied.
Type: text.
Example: `pdf_margin_left=10mm`
### pdf_fit_one_page
Put the whole page on a single tall PDF page.
The default is `false`.
Type: true or false.
Example: `pdf_fit_one_page=true`
Read more: [PDF rendering](https://curlshot.com/docs/pdf.md).
## Video
These apply only when `format` is `mp4`, `webm` or `gif`. The result is then a video of the page scrolling from top to bottom, and these options set how long it is, how smooth it is and how the scroll moves. With any other format they have no effect. The [Scrolling videos](https://curlshot.com/docs/video.md) page shows each one at work.
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://example.com&format=mp4&video_duration=8" --output example.mp4
```
### video_duration
Length of the video. Left out, it follows the height of the page.
There is no default; leave it out and it is not applied.
Type: number. From 1 to 30 seconds.
Example: `video_duration=8`
### video_max_duration
Longest the video may get when its length follows the page. A taller page then scrolls faster.
The default is `30` seconds.
Type: number. From 1 to 30 seconds.
Example: `video_max_duration=15`
### video_fps
Frames per second. A gif takes at most 15.
The default is `24`.
Type: whole number. From 5 to 30.
Example: `video_fps=30`
### video_scroll
Scroll from the top of the page to the bottom while recording.
The default is `true`.
Type: true or false.
Example: `video_scroll=false`
### video_scroll_back
Scroll back to the top at the end, so the video loops cleanly.
The default is `false`.
Type: true or false.
Example: `video_scroll_back=true`
### video_scroll_easing
How the scroll moves: a soft start and stop, or one even speed.
The default is `ease_in_out`.
Type: one of a fixed list. Allowed values: `ease_in_out`, `linear`.
Example: `video_scroll_easing=linear`
Read more: [Scrolling videos](https://curlshot.com/docs/video.md).
## Caching options
Caching stores a result so that the same request can be answered again without a new render. A cached answer is fast and does not use your quota. Turn it on for pages that do not change every minute.
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://example.com&cache=true&cache_ttl=86400" --output example.png
```
### cache
Serve a stored copy when the same request was made before.
The default is `false`.
Type: true or false.
Example: `cache=true`
### cache_ttl
How long a cached copy stays valid.
The default is `14400` seconds.
Type: whole number. From 60 to 2592000 seconds.
Example: `cache_ttl=86400`
### cache_key
Change this value to force a fresh render.
There is no default; leave it out and it is not applied.
Type: text.
Example: `cache_key=v2`
Read more: [Caching](https://curlshot.com/docs/caching.md).
## Async and webhooks
Normally you wait for the screenshot. With these options the request returns at once and the render happens in the background. Use them for slow pages, or when your code should not hold a connection open. A webhook is a request we send to your server when the job ends.
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://example.com&async=true&webhook_url=https://your-app.example/hooks/screenshot"
```
### async
Return at once and render in the background.
The default is `false`.
Type: true or false.
Example: `async=true`
### webhook_url
Address that receives the result when the render is done.
There is no default; leave it out and it is not applied.
Type: text.
Example: `webhook_url=https://example.com/hook`
### webhook_sign
Sign the webhook body so you can verify it came from us.
The default is `true`.
Type: true or false.
Example: `webhook_sign=false`
Read more: [Async and webhooks](https://curlshot.com/docs/async-and-webhooks.md), [Bulk screenshots](https://curlshot.com/docs/bulk.md).
## Authentication
These say who is making the request. Every request needs `access_key`, in the query string or in a header.
`signature` and `expires` are for signed links, which let you put a screenshot URL in a public page safely. `signature` proves the link was not changed. `expires` gives the link an end date: after that moment it answers [`request_expired`](https://curlshot.com/docs/errors.md#request_expired).
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://example.com" --output example.png
```
### access_key
Your API access key.
There is no default; leave it out and it is not applied.
Type: text.
Example: `access_key=YOUR_ACCESS_KEY`
### signature
HMAC-SHA256 signature of the query string, for signed links.
There is no default; leave it out and it is not applied.
Type: text.
Example: `signature=9f86d081...`
### expires
Unix time in seconds after which the request is refused. Put it in a signed link to give the link a lifetime.
There is no default; leave it out and it is not applied.
Type: whole number.
Example: `expires=1767225600`
Read more: [Authentication and API keys](https://curlshot.com/docs/authentication.md), [Signed links](https://curlshot.com/docs/signed-links.md).
## Where to go next
- [The screenshot URL](https://curlshot.com/docs/screenshot-url.md): how to write options in GET and POST requests.
- [Devices](https://curlshot.com/docs/devices.md): the full list of values for `viewport_device`.
- [Errors](https://curlshot.com/docs/errors.md): what `invalid_options` and the other codes mean.
- [Code examples](https://curlshot.com/docs/examples/curl.md): complete scripts that use these options.
---
Source: https://curlshot.com/docs/devices
# Devices
Capture a page as a phone, tablet, laptop or desktop would show it, using one option and a list of ready-made presets.
Add `viewport_device` and the page is drawn as that device would show it.
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://en.wikipedia.org/wiki/Eiffel_Tower&viewport_device=iphone_15_pro" \
--output eiffel-iphone.png
```
You get the mobile version of the article, in a file that is 1179 by 2556 pixels.

## What a device preset sets
A preset is a bundle of settings with a name. One value of [`viewport_device`](https://curlshot.com/docs/options.md#viewport_device) sets all of these:
| Setting | What it means | iPhone 15 Pro |
| --- | --- | --- |
| Width and height | The size of the viewport. The viewport is the browser window the page is drawn in. | 393 x 852 |
| Pixel density | How many image pixels are drawn for each page pixel. | 3 |
| Mobile layout | Whether the page is treated as a phone or tablet page. | yes |
| Touch | Whether the browser reports a touch screen. | yes |
| User agent | The browser name sent to the site. Some sites pick their layout from it. | iPhone Safari |
Presets for phones and tablets turn on the mobile layout. Presets for laptops and desktops do not.
Without a preset, the page is drawn in a 1280 by 1024 window at density 1, as a desktop browser.
## Try a tablet
Change one word and you get a different device.
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://en.wikipedia.org/wiki/Eiffel_Tower&viewport_device=ipad" \
--output eiffel-ipad.png
```

The name is forgiving about spelling. `iphone_15_pro`, `iphone-15-pro` and `iPhone 15 Pro` all pick the same preset.
## Pixel density in one line
Pixel density multiplies the image size: a 393 x 852 viewport at density 3 gives a 1179 x 2556 image, with sharper text and the same layout.
That is why device screenshots are larger than the viewport numbers suggest. The option behind it is [`device_scale_factor`](https://curlshot.com/docs/options.md#device_scale_factor). The default is `1`. The largest value is `3`. For [full-page screenshots](https://curlshot.com/docs/full-page.md#limits-of-your-plan), your plan can set a lower maximum.
## Override part of a preset
Any viewport option you send yourself wins over the preset. The rest of the preset stays.
This keeps the iPhone layout and user agent, but asks for density 1, so the file is a light 393 by 852 pixels:
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://en.wikipedia.org/wiki/Eiffel_Tower&viewport_device=iphone_15_pro&device_scale_factor=1" \
--output eiffel-iphone-small.png
```
You can override these:
- [`viewport_width`](https://curlshot.com/docs/options.md#viewport_width) and [`viewport_height`](https://curlshot.com/docs/options.md#viewport_height), for a taller or shorter first screen.
- [`device_scale_factor`](https://curlshot.com/docs/options.md#device_scale_factor), for a lighter or sharper file.
- [`viewport_mobile`](https://curlshot.com/docs/options.md#viewport_mobile), to turn the mobile layout on or off.
- [`user_agent`](https://curlshot.com/docs/options.md#user_agent), to send your own browser name.
> **Tip**
>
> For a small file that still shows the phone layout, keep the preset and add [`image_width`](https://curlshot.com/docs/options.md#image_width). The page is drawn at full quality and the final image is resized.
## Landscape
Phone and tablet presets are in portrait, which means taller than wide. Add [`viewport_landscape=true`](https://curlshot.com/docs/options.md#viewport_landscape) to turn the device on its side.
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://en.wikipedia.org/wiki/Eiffel_Tower&viewport_device=ipad&viewport_landscape=true" \
--output eiffel-ipad-landscape.png
```
The iPad viewport becomes 1180 by 820 in place of 820 by 1180.
The default is `false`. On a preset that is already wider than tall, such as a laptop, it changes nothing.
## Without a preset
You do not need a preset to get a phone-sized screenshot. Set the numbers yourself:
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://en.wikipedia.org/wiki/Eiffel_Tower&viewport_width=400&viewport_height=800&viewport_mobile=true&device_scale_factor=2" \
--output eiffel-custom.png
```
`viewport_mobile=true` matters here. It makes the browser respect the page's own mobile settings, the way a phone does. Without it, a narrow window is still treated as a desktop browser.
The width can be from 100 to 3840 pixels. The height can be from 100 to 4320 pixels.
> **Common mistakes**
>
> - **An unknown device name.** A name that is not in the [list below](https://curlshot.com/docs/devices.md#all-devices) returns [`invalid_options`](https://curlshot.com/docs/errors.md#invalid_options).
> - **Expecting the device frame.** A preset changes how the page is drawn. It does not draw a phone body around the screenshot.
> - **Expecting a whole page.** A preset sets the first screen. Add [`full_page=true`](https://curlshot.com/docs/full-page.md) to capture down to the bottom.
> - **Huge files from phones.** Density 3 makes nine times as many pixels as density 1. Lower `device_scale_factor` or switch to `format=jpeg` if size matters.
## All devices
### Phones
| `viewport_device` | Device | Viewport | Pixel density | Mobile layout |
| --- | --- | --- | --- | --- |
| `iphone_se` | iPhone SE | 375 x 667 | 2 | yes |
| `iphone_12` | iPhone 12 | 390 x 844 | 3 | yes |
| `iphone_13` | iPhone 13 | 390 x 844 | 3 | yes |
| `iphone_13_mini` | iPhone 13 mini | 375 x 812 | 3 | yes |
| `iphone_14` | iPhone 14 | 390 x 844 | 3 | yes |
| `iphone_14_plus` | iPhone 14 Plus | 428 x 926 | 3 | yes |
| `iphone_14_pro` | iPhone 14 Pro | 393 x 852 | 3 | yes |
| `iphone_14_pro_max` | iPhone 14 Pro Max | 430 x 932 | 3 | yes |
| `iphone_15` | iPhone 15 | 393 x 852 | 3 | yes |
| `iphone_15_plus` | iPhone 15 Plus | 430 x 932 | 3 | yes |
| `iphone_15_pro` | iPhone 15 Pro | 393 x 852 | 3 | yes |
| `iphone_15_pro_max` | iPhone 15 Pro Max | 430 x 932 | 3 | yes |
| `iphone_16` | iPhone 16 | 393 x 852 | 3 | yes |
| `iphone_16_plus` | iPhone 16 Plus | 430 x 932 | 3 | yes |
| `iphone_16_pro` | iPhone 16 Pro | 402 x 874 | 3 | yes |
| `iphone_16_pro_max` | iPhone 16 Pro Max | 440 x 956 | 3 | yes |
| `pixel_5` | Pixel 5 | 393 x 851 | 2.75 | yes |
| `pixel_7` | Pixel 7 | 412 x 915 | 2.625 | yes |
| `pixel_8` | Pixel 8 | 412 x 915 | 2.625 | yes |
| `pixel_8_pro` | Pixel 8 Pro | 448 x 998 | 3 | yes |
| `pixel_9` | Pixel 9 | 412 x 923 | 2.625 | yes |
| `pixel_9_pro` | Pixel 9 Pro | 410 x 914 | 3 | yes |
| `galaxy_s23` | Galaxy S23 | 360 x 780 | 3 | yes |
| `galaxy_s24` | Galaxy S24 | 360 x 780 | 3 | yes |
| `galaxy_s24_ultra` | Galaxy S24 Ultra | 384 x 824 | 3 | yes |
| `galaxy_a54` | Galaxy A54 | 360 x 800 | 3 | yes |
### Tablets
| `viewport_device` | Device | Viewport | Pixel density | Mobile layout |
| --- | --- | --- | --- | --- |
| `ipad` | iPad (10th gen) | 820 x 1180 | 2 | yes |
| `ipad_mini` | iPad mini | 744 x 1133 | 2 | yes |
| `ipad_air` | iPad Air | 820 x 1180 | 2 | yes |
| `ipad_pro_11` | iPad Pro 11" | 834 x 1194 | 2 | yes |
| `ipad_pro_13` | iPad Pro 13" | 1024 x 1366 | 2 | yes |
| `galaxy_tab_s9` | Galaxy Tab S9 | 800 x 1280 | 2 | yes |
| `pixel_tablet` | Pixel Tablet | 800 x 1280 | 2 | yes |
### Laptops
| `viewport_device` | Device | Viewport | Pixel density | Mobile layout |
| --- | --- | --- | --- | --- |
| `macbook_air_13` | MacBook Air 13" | 1440 x 900 | 2 | no |
| `macbook_pro_14` | MacBook Pro 14" | 1512 x 982 | 2 | no |
| `macbook_pro_16` | MacBook Pro 16" | 1728 x 1117 | 2 | no |
| `laptop_hd` | Laptop (1366 x 768) | 1366 x 768 | 1 | no |
| `laptop_hidpi` | Laptop HiDPI (1440 x 900 @2x) | 1440 x 900 | 2 | no |
### Desktops
| `viewport_device` | Device | Viewport | Pixel density | Mobile layout |
| --- | --- | --- | --- | --- |
| `desktop_hd` | Desktop HD (1280 x 720) | 1280 x 720 | 1 | no |
| `desktop_full_hd` | Desktop Full HD (1920 x 1080) | 1920 x 1080 | 1 | no |
| `desktop_qhd` | Desktop QHD (2560 x 1440) | 2560 x 1440 | 1 | no |
| `desktop_4k` | Desktop 4K (3840 x 2160) | 3840 x 2160 | 1 | no |
| `imac_24` | iMac 24" | 2240 x 1260 | 2 | no |
## Get the list as JSON
The same list is available from the API, for a device picker in your own app. This request needs no access key and does not count against your quota.
```bash
curl "https://curlshot.com/api/v1/devices"
```
```json
{
"devices": [
{
"name": "iphone_se",
"label": "iPhone SE",
"category": "phone",
"viewport_width": 375,
"viewport_height": 667,
"device_scale_factor": 2,
"viewport_mobile": true,
"has_touch": true,
"user_agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1"
}
]
}
```
The real answer holds one entry like this for every device in the tables above. `category` is `phone`, `tablet`, `laptop` or `desktop`.
## Where to go next
- [Full-page screenshots](https://curlshot.com/docs/full-page.md): capture the whole page on any device.
- [Dark mode and emulation](https://curlshot.com/docs/dark-mode-and-emulation.md): dark theme, time zone and user agent.
- [Options reference](https://curlshot.com/docs/options.md#viewport_device): every viewport option with its limits.
---
Source: https://curlshot.com/docs/full-page
# Full-page screenshots
Capture a page from top to bottom, load lazy images on the way, and keep very tall pages under control.
Add `full_page=true` and the capture runs to the bottom of the page.
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://en.wikipedia.org/wiki/Eiffel_Tower&full_page=true" \
--output eiffel-full.png
```
You get one tall image with the whole article in it.

Without the option, you get only the first screen. That is the part a visitor sees before scrolling.
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://en.wikipedia.org/wiki/Eiffel_Tower&viewport_height=800" \
--output eiffel-first-screen.png
```

## How it works
The width of the image still comes from the viewport. The viewport is the browser window the page is drawn in. The height is as tall as the page turns out to be.
So [`viewport_width`](https://curlshot.com/docs/options.md#viewport_width) and [`viewport_device`](https://curlshot.com/docs/devices.md) still matter. A full-page capture on a phone preset gives you the long mobile version of the page.
### full_page
Capture the whole page, not only the first screen.
The default is `false`.
## Lazy images
Many sites load images only when you scroll near them. This is called lazy loading. A capture taken without scrolling would show empty boxes further down the page.
To avoid that, a full-page capture first scrolls through the page from top to bottom. It gives the images a moment to arrive, then goes back to the top and takes the screenshot.
### full_page_scroll
Scroll through the page before the capture so lazy-loaded images appear.
The default is `true`.
You rarely need to change it. Turn it off in two cases:
- The page is short and has no lazy images, and you want the fastest render.
- Scrolling changes the page in a way you do not want. Some sites load more and more content as you scroll, or shrink their header.
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://en.wikipedia.org/wiki/Eiffel_Tower&full_page=true&full_page_scroll=false" \
--output eiffel-no-scroll.png
```
> **Note**
>
> The scroll has a time budget. On a very long page with slow images, a few may still be missing. Adding a [`delay`](https://curlshot.com/docs/options.md#delay) does not extend the scroll. A lower `full_page_max_height` does help, because there is less to scroll through.
## Very tall pages
Some pages never end. News feeds and shop listings keep adding content. To keep the image a usable size, a full-page capture stops at a maximum height.
### full_page_max_height
Cut a full-page capture off at this height, in pixels.
The default is `20000`. The smallest value is `100` and the largest is `30000`.
A page shorter than the limit is not stretched. A page taller than the limit is cut off at the limit, and you still get a valid image.
This request keeps only the first 5000 pixels of the article:
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://en.wikipedia.org/wiki/Eiffel_Tower&full_page=true&full_page_max_height=5000" \
--output eiffel-5000.png
```
The height is counted in page pixels. With a pixel density above 1, the file has more pixels than that. A 5000 pixel page at [`device_scale_factor=2`](https://curlshot.com/docs/options.md#device_scale_factor) is 10000 pixels tall in the file.
Very large captures can hit other limits too:
- At a high pixel density, the capture may be cut shorter than `full_page_max_height` to keep the total pixel count within bounds.
- If the finished file is too big, you get [`content_too_large`](https://curlshot.com/docs/errors.md#content_too_large). Use `format=jpeg` or `format=webp`, a lower [`image_quality`](https://curlshot.com/docs/options.md#image_quality), or a smaller `full_page_max_height`.
### Limits of your plan
A full-page screenshot counts as one screenshot against your quota, however tall it is. What a plan limits is the size:
- **Height.** A plan can have a lower maximum height than `30000`. A larger `full_page_max_height` is lowered to the plan's maximum, and the capture is cut off there.
- **Pixel density.** A plan can limit the [`device_scale_factor`](https://curlshot.com/docs/options.md#device_scale_factor) of a full-page capture. A higher value is lowered to the plan's maximum. This also applies to the density a [device preset](https://curlshot.com/docs/devices.md) brings along.
In both cases you still get a valid screenshot, not an error. Screenshots of the first screen and [element captures](https://curlshot.com/docs/element.md) keep the density you asked for.
Your own values are `full_page_max_height` and `full_page_max_scale` in the answer of [`GET /usage`](https://curlshot.com/docs/usage-and-limits.md).
> **Tip**
>
> For tall pages, JPEG or WebP is usually the better choice. A PNG of a 20000 pixel page can be many megabytes.
## Sticky headers and floating bars
A sticky header is a menu bar that stays at the top of the window while you scroll. Cookie bars and chat bubbles float in a similar way.
In a full-page capture these can land in odd places. A bar may cover part of the content, or appear in a spot where it makes no sense.
The fix is to hide the element before the capture with [`hide_selectors`](https://curlshot.com/docs/options.md#hide_selectors). A selector is a short pattern that points at an element, such as `.site-header` for an element with the class `site-header`.
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://en.wikipedia.org/wiki/Eiffel_Tower&full_page=true&hide_selectors=.vector-sticky-header" \
--output eiffel-clean.png
```
To find the right selector, open the page in your browser, right-click the bar and choose **Inspect**. Look for its `class` or `id`.
For consent pop-ups and chat widgets, try [`block_cookie_banners`](https://curlshot.com/docs/blocking.md) and `block_chats` first. They cover the common ones without a selector.
> **Common mistakes**
>
> - **Combining it with an element capture.** When you send [`selector`](https://curlshot.com/docs/element.md) or the `clip_*` options, those decide the area and `full_page` is not used.
> - **A page that looks cut off.** It probably reached `full_page_max_height`. Raise it, up to `30000` or the maximum of [your plan](#limits-of-your-plan).
> - **A full-page phone screenshot that is less sharp than expected.** Your plan limits the pixel density of full-page captures. See [Limits of your plan](#limits-of-your-plan).
> - **Blank areas in the middle.** The content there appears only after an animation or a script. Try [`wait_until=networkidle`](https://curlshot.com/docs/waiting.md) or a short `delay`.
> - **Timeouts on heavy pages.** Long pages take longer. Raise [`timeout`](https://curlshot.com/docs/options.md#timeout), or run the request with [`async=true`](https://curlshot.com/docs/async-and-webhooks.md).
## Where to go next
- [Capturing an element](https://curlshot.com/docs/element.md): when you need one part of the page, not all of it.
- [PDF rendering](https://curlshot.com/docs/pdf.md): a long page as a document with real pages.
- [Waiting and timing](https://curlshot.com/docs/waiting.md): make sure the page is ready before the capture.
- [Blocking ads, cookie banners, trackers and chats](https://curlshot.com/docs/blocking.md): remove the usual floating clutter.
---
Source: https://curlshot.com/docs/element
# Capturing an element
Capture one element with a CSS selector, or a rectangle you choose, with an optional transparent background.
Add `selector` and the image contains only that element.
```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://en.wikipedia.org/wiki/Eiffel_Tower&selector=.infobox" \
--output eiffel-infobox.png
```
You get the fact box from the side of the article and nothing else. The image is exactly as big as the element.

## Pick an element with a selector
A CSS selector is a short pattern that points at an element on a page. It is the same language web designers use to style pages.
| Selector | What it matches |
| --- | --- |
| `.infobox` | An element with the class `infobox`. |
| `#content` | The element with the id `content`. |
| `table` | A `` element. |
| `main article` | An `` inside ``. |
To find one, open the page in your browser, right-click the part you want and choose **Inspect**. Look at the element's `class` or `id`.
### selector
Capture only the first element that matches this CSS selector.
There is no default. Leave it out and the capture is not limited to an element.
If several elements match, the first one on the page is used. The element does not have to be on the first screen. An element further down the page is captured too.
A selector can be up to 1000 characters long.
A few things to know before you rely on it:
- The image is exactly the element's box. There is no padding option. To get space around an element, add it with [`styles`](https://curlshot.com/docs/customize.md), for example `styles=.infobox{padding:16px}`.
- An element taller than the window is captured whole.
- A bar that stays fixed to the top of the window (a sticky header) can land inside the image of a tall element. Hide it with [`hide_selectors`](https://curlshot.com/docs/customize.md).
- The selector does not reach inside an `