Skip to content

A URL to PDF API for your own code

CurlShot is a URL to PDF API. Send the address of a web page with format=pdf and the answer is a PDF of that page, printed by a real browser: text you can select and search, links that work, and your choice of paper size, margins and orientation. It works from any language that can make an HTTP request, and long jobs can run in the background and report to a webhook.

Request
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://example.com&format=pdf&pdf_paper_format=letter&pdf_margin=15mm&block_cookie_banners=true" \
  --output page.pdf

How to convert a URL to PDF with an API in three steps

  1. 1

    Create a free account and copy your access key.

  2. 2

    Send the page address with format=pdf, and the paper size and margins you want.

  3. 3

    Store the PDF that comes back, or let a webhook tell you when it is ready.

PDF options for a URL, with their defaults

Every PDF option is a parameter of the same request. Leave them all out and you get A4 pages, no margin, backgrounds printed and the screen styles of the page. A PDF always covers the whole page, so full_page is not needed.

Show the table (7 rows)
OptionDefaultWhat it changes
pdf_paper_formata4Paper size: a0, a1, a2, a3, a4, a5, a6, letter, legal, tabloid, ledger
pdf_landscapefalsetrue turns the paper on its side, for wide tables and dashboards
pdf_marginnoneOne margin for all four sides: 10mm, 1cm, 0.5in or 20px
pdf_margin_top, pdf_margin_right, pdf_margin_bottom, pdf_margin_leftnoneOne side each; wins over pdf_margin
pdf_print_backgroundtruefalse drops background colours and images, for a printer
pdf_fit_one_pagefalsetrue puts the whole page on one sheet as tall as the content
media_typescreenprint uses the stylesheet the site wrote for paper
  • selector, clip and the image options have no effect on a PDF; selector and clip are refused with format=pdf.
  • With pdf_fit_one_page the width of the sheet follows viewport_width, so a 1280 px window gives a 1280 px wide page.
  • With response_type=json, width and height describe one page of the PDF, in pixels at 96 per inch.

A clean PDF of a page you do not control

Your own pages print the way you designed them. Other people's pages arrive with a consent pop-up, a sticky header that repeats at the top of every sheet, and content that loads late. Each has an option.

Show the table (7 rows)
What goes wrongOption that fixes it
A cookie banner over the first pageblock_cookie_banners=true
Ads and a chat bubble on every sheetblock_ads=true, block_chats=true
A sticky header repeated down the documenthide_selectors with its CSS selector, or media_type=print
Charts or prices missing, because they load after the pagewait_until=networkidle, or wait_for_selector with the element you need
Images further down left blankNothing: the page is scrolled before printing so they load (full_page_scroll)
The menu and sidebar take half the first pagemedia_type=print, or hide them with hide_selectors
The text breaks inside a table rowpdf_fit_one_page=true for a single long sheet

Many PDFs, or PDFs that take a while

A long page can take several seconds to load and print. Rather than hold a request open, add async=true: the API answers at once with a job, renders in the background, and posts the result to your webhook_url when it is done. The webhook body carries a link to the PDF, signed so your server can check it came from the API.

For a list of pages, a bulk call takes up to 100 at once, each with its own options, on plans that include bulk.

  • The webhook arrives once the job is done or has failed. Download the PDF when it arrives: the link in it expires.
  • Checking a job's status is free and does not use your quota.
Node.js: start a PDF job with a webhook
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({
    url: 'https://example.com/report',
    format: 'pdf',
    pdf_paper_format: 'a4',
    pdf_margin: '15mm',
    async: true,
    webhook_url: 'https://your-app.example/hooks/pdf',
  }),
})
const job = await response.json()
if (!response.ok) throw new Error(job.error_code + ': ' + job.error_message)
console.log('Started', job.job_id)
Python: the same PDF, waited for in the request
import os

import requests

response = requests.get(
    "https://curlshot.com/api/v1/screenshot",
    headers={"X-Access-Key": os.environ["SCREENSHOT_ACCESS_KEY"]},
    params={"url": "https://example.com/report", "format": "pdf", "pdf_paper_format": "a4", "pdf_margin": "15mm"},
    timeout=120,
)
response.raise_for_status()
with open("report.pdf", "wb") as f:
    f.write(response.content)

A "Download as PDF" link on your own site

To let visitors download a PDF of a page, do not put your access key in the page. Make a signed link on your server instead: the request address plus a signature made with your secret key. Nobody can change the page or the options in it, and an expires parameter can give the link a lifetime.

Add cache=true so that a hundred clicks on the same link make one PDF, not a hundred. Cache hits are not counted against your allowance.

  • Signing takes a few lines in any language; the docs have the code for six.
A signed PDF link in a page
<a href="https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&cache=true&format=pdf&media_type=print&url=https%3A%2F%2Fexample.com%2Finvoice%2F1042&signature=SIGNATURE">
  Download as PDF
</a>
The first page of a PDF made from the Wikipedia article about the Eiffel Tower
Page one of a URL turned into an A4 PDF by the API. The text stays selectable.

What people use it for

  • Archive pages of your own app or of a site you track, as dated documents
  • Attach the current state of a dashboard or report to an email
  • Offer a "Download as PDF" link on pages your users can already see
  • Keep records of terms, prices or listings at a moment in time

For developers: one request

The same thing from your own code. It is a plain HTTP request, so it works from any language. Create a free account to get an access key.

Questions people ask

How do I convert a URL to PDF with an API?

Send a GET request to the CurlShot screenshot endpoint with your access key, the page address in url, and format=pdf. The body of the answer is the PDF file, with Content-Type application/pdf.

Is the text in the PDF real text?

Yes. The PDF is printed by the browser, not built from a screenshot, so the text can be selected, searched and copied, links stay clickable, and the file stays small compared with an image of the same page.

Does a long page cost more than a short one?

No. One successful render counts as one, whether the PDF has one page or forty. Failed renders are not counted, and a repeat served from the cache is free.

Can it make a PDF of a page that needs a login?

Yes, when you pass what the page needs: a session cookie with cookies, extra headers with headers, or an Authorization header with authorization, which is sent to the target site only. Pages on a private network are refused; send their HTML instead.

How is this different from the web page to PDF tool?

It is the same engine. The tool is a page where a person pastes an address and downloads one PDF. The API is for code: the same result from a request, with every PDF option, background jobs, webhooks and bulk calls.

Take as many screenshots as you need

A free account gives you 100 screenshots every month and keeps them in one place. No card needed.