Generate PDFs and images
without the browser stack

Convert HTML, URLs, or dynamic templates into PDFs and images with our REST API or 8 open source SDKs, without managing headless browsers, server fleets, or render queues.

Free account, no credit card

The pieces a document endpoint needs

One REST API

Post HTML, a template ID, or a URL and request a PDF or image. Any language that can make an HTTP request can use the API.

Browser-based rendering

Render modern HTML and CSS in Chromium, including Grid, Flexbox, web fonts, and pages that need JavaScript before capture.

Public SDKs

Use an SDK for .NET, F#, Go, Java, JavaScript, PHP, Python, and Ruby, or inspect its public source before adding it to your application.

Async delivery

Return a job ID quickly, do the render outside the request cycle, and send the completed result or failure to a webhook.

Reusable templates

Keep layout in a saved Nunjucks template. Supply JSON data at render time for loops, conditions, filters, and reusable partials.

Managed assets

Upload fonts, images, and stylesheets once, then reference their stable URLs from templates without operating a separate asset host.

From API key to finished file

1

Create a project key

Get an API key from the dashboard and keep it on the server. Rate-limit responses include a retry-after header for controlled backoff.

2

Describe the render

Post raw HTML, a URL, or a template ID with JSON data. Choose the output format, page geometry, and the options the page needs.

3

Handle the result

Read the file from a synchronous response, or use a job ID and webhook for work that should finish outside the request cycle.

Start with the request your application already knows how to make

Choose raw HTML, a saved template, or a URL, then switch the example to your language. The 8 public SDKs cover .NET, F#, Go, Java, JavaScript, PHP, Python, and Ruby; the REST contract underneath them is available to every other stack.

Language
What goes in
import { CloudLayer } from '@cloudlayer/sdk';

const client = new CloudLayer(process.env.CLOUDLAYER_KEY);
// Returns the finished PDF on this request.
const result = await client.pdf.create({
  templateId: 'inv-2026-standard',
  data: {
    customer: 'Rivera Dental',
    total: '1840.00'
  },
});

The request is the integration. A synchronous call returns the file in the response. An asynchronous call returns a job ID, releases your connection, and reports the result to a webhook. You do not need a browser process or render queue in your own service. The same inputs and output controls carry across both modes, so moving a slow workflow to async does not require a second document definition.

Give the browser enough context to render the right page

A URL capture is rarely just a URL. The result may depend on viewport, session state, scripts, or region. The render API provides dedicated controls for viewport sizing, custom scripts, proxies, and session headers so each request can precisely describe the state it expects to capture. Keeping these options alongside the URL in code ensures every capture is reliable and reproducible.

Control the render inputs

Keep document layout in a reviewed template and specify its assets, page geometry, and render options. Engine-version pinning is not offered, so regression-test layouts that must remain exact.

Recreate the client context

Set headers, cookies, platform, timezone, and coordinates when a public page varies by session or client context. The browser receives those values before it loads the page.

Skip unnecessary resources

Block media, styles, sockets, or fonts when the capture does not need them. Fewer network requests can shorten the page load and remove content that would delay capture.

Prepare the page before capture

Add CSS or JavaScript before capture to hide an overlay, set a display mode, or put the page into a known state. Flexible script execution options let you run custom JavaScript or inject CSS before capturing.

Choose the captured area

Capture a full page, a fixed viewport, a clip rectangle, or one element selected with CSS. Scroll and section controls cover pages that load more content as they move.

Route public pages by proxy

Provide an authenticated proxy address or choose an eligible proxy region when a public page responds differently by geography. This does not connect the renderer to a private network.

Make failure part of the integration contract

A render can fail because the input is invalid, a page does not load, or a worker reaches its limit. Structured errors, durable job state, and signed webhooks give your application a defined response instead of leaving an open connection or a missing file. Decide which failures are safe to retry, which should reach a dead-letter path, and which require a caller to correct the source data.

sync file async job id webhook
  1. Retry only failures that may recover. Configure the conditions, attempt count, delay, and any option changes for a retry. That lets a temporary page-load error retry without turning every invalid request into extra work.
  2. Receive a terminal event. Webhooks report failure as well as success, and job state remains available from the Jobs API. Your worker can reconcile a missed callback instead of treating silence as completion.
  3. Verify webhook signatures. Check the signature before accepting a completion event. The callback endpoint can reject messages that were not produced for the render workflow.
  4. Separate projects and credentials. Scope keys to a project so staging and production do not share the same credential or document namespace. Revoke one environment without interrupting the other.

Self-hosting starts with a browser and ends with an operating service

A Puppeteer script can produce the first file quickly. Production use adds browser images, fonts, isolation, queues, retries, observability, and capacity planning around that script. The important comparison is the complete runtime path, including how it behaves during a traffic spike or a destination-page timeout.

Package the browser runtime

Chromium and its system libraries become part of the application image. That image must be built, patched, deployed, and kept compatible with the code that starts each browser.

Install every required font

A minimal container may not include the families or scripts your document uses. Missing fonts change line breaks and pagination, so the font set needs to be explicit and tested.

Own browser process cleanup

Every success, timeout, and exception path must close its pages and processes. A leaked browser consumes memory until the worker slows down or restarts with jobs still waiting.

Control concurrency and backpressure

Launching one browser per request does not provide a safe capacity limit. A production service needs a queue, bounded workers, retries, and a place for work that cannot complete.

Test browser upgrades

Browser and dependency updates can affect layout or timing. Keep representative documents in a visual regression suite so a release does not quietly change a critical output.

Support each output path

PDF, PNG, JPEG, and WebP have different controls and consumers. Each new format or size adds validation, storage behavior, and tests to the service you operate.

If the renderer itself is your product, owning this stack may be the right choice. If documents support another product, compare the API with the engineering and operations work above. Plans start at $9 a month for 1,000 renders and run to 100,000.

Do not render the same input twice unless you mean to

Repeated social previews, product cards, and document downloads may ask for identical output. Custom cache settings define how requests are keyed, how long results remain fresh, and when your application can bypass or clear them.

Reuse identical requests

A matching request signature can return a cached result instead of starting another browser job. This is useful when several consumers request the same generated asset.

Set a useful lifetime

Give changing data a short cache lifetime and stable assets a longer one. The request controls the lifetime rather than forcing every document into one retention window.

Refresh when the source changes

Force a new render or invalidate the existing entry when source data changes before its cache lifetime ends. Your application decides when the old result is no longer valid.

Choose no retained result

Use secure or zero-retention behavior when a generated document should not remain stored. Sensitive header and proxy credential values are redacted from logs.

Build the unhappy path before customers find it

Error responses use structured JSON with a code, message, and request ID. Log the request ID beside your own job record so the failed render can be traced without reproducing it first.

SDK retry behavior and retry-after headers help callers back off when capacity is limited. Your plan sets the monthly allowance and simultaneous render count; accepted async work can wait in the queue instead of holding the original connection open.

Typed clients describe request options, response shapes, and errors in supported languages. Add an idempotency key when a caller may repeat the same request, so a network retry does not create an unintended second document.

Traceable errors

Read a stable code in your application, show the useful message, and retain the request ID for diagnosis.

Explicit backoff

Use the retry-after value on a 429 response instead of guessing when the next request should run.

Typed contracts

Use request, response, and error types supplied by the client library instead of recreating the API shape.

Safe request replay

Attach an idempotency key when transport failures may cause your application to send the same render again.

Two common integration shapes

Node.js: return a PDF from an HTTP handler

Call the REST API with fetch() and send the HTML plus PDF options as JSON. Read the response as bytes, then return it to the caller or put it in object storage without writing a temporary file on the application server.

Keep page size, margins, print backgrounds, and header or footer templates in the same request. Record the request ID and response metadata beside the application event that caused the render.

Python: create a document from a saved template

Initialize the client with a server-side API key, then pass a template ID and its JSON data. The template controls the layout while the request supplies the customer, line items, or other values that change for each document.

Use asynchronous jobs when the workflow creates many files or should not block a web request. Store each job ID, verify the webhook, and move the completed file to its destination when the terminal event arrives.

8
Official SDKs
Available on GitHub
36
Payment gateways
Accept payments on forms
6
E-signature providers
Triggered from submissions

Questions about the developer API

Which languages have an official SDK?

8: .NET, F#, Go, Java, JavaScript, PHP, Python, and Ruby. Each SDK is public in the cloudlayer.io GitHub organization. If your language is not listed, you can call the same REST API with any HTTP client.

How many documents can I render at once?

Concurrency depends on your plan: 2 simultaneous renders on Starter, 8 on Business, and 25 on Enterprise. For larger batches, async requests return a job ID and send each result to your webhook when it is ready.

Do I choose the browser engine version?

No. Engine-version pinning is not a request option. For repeatable documents, use a reviewed template, controlled assets, and explicit render settings, then test important layouts as part of your release process.

What does a failed render cost me?

A failed request returns a structured error. For async work, the job remains available through the Jobs API, and webhook events report failure as well as success. You can configure retry conditions, attempts, and delays for the render workflow.

How do I generate a PDF from my application?

Send one POST request with HTML, a URL, or a template ID. The API returns the file or a job ID for async work.

How do I handle large batches?

Use async mode with webhooks. Each request returns a job ID, then calls your endpoint when the file is ready. Plans run from $9 a month for 1,000 renders to $1,000 for 100,000, and batch renders use the same monthly allowance.

Can I capture a page that requires a signed-in session?

You can send headers and cookies with a request to a reachable URL. That lets the browser reproduce an authenticated web session without exposing those values in the page URL. It does not give the renderer access to a private network.

What happens when a render fails?

The API returns a structured error with a code, a readable message, and a request ID. Keep the request ID in your logs so you can trace the failure or include it in a support request.

Send the first request
from your own stack

Create a free account, choose REST or one of 8 public SDKs, and test the document path before wiring it into production.

No credit card required.