ScreenshotNeo

BlogHTML to image & PDF

How to Convert a React Page to PDF with DocRaptor

Generate a PDF from React-rendered HTML with DocRaptor. Learn how to enable JavaScript, wait for data, secure your API key, and fix layout and asset issues.

By the ScreenshotNeo team4 October 202610 min read

To convert a React page to PDF with DocRaptor, send HTML content or a reachable page URL to DocRaptor’s API and enable JavaScript when React must render during conversion. DocRaptor does not accept a React component object: it converts HTML/XML or fetches a document URL. Make the page’s data and assets available to the renderer, keep the API key on your server, and check the resulting PDF against print styles.

1. Prepare a PDF-ready React document

Decide how the conversion service will receive the page:

  • document_content: send HTML assembled by your application. Include the document structure, styles, and content. If React must execute in the renderer, include the scripts and data it needs and set javascript: true.
  • document_url: provide a URL DocRaptor can reach. The response at that URL must be accessible to the service and render the intended document without relying on a user’s browser session.

Use a dedicated print or report view where practical. Keep the document’s data stable for the duration of a conversion, and make stylesheet, font, script, and image URLs reachable. For content passed directly, use absolute asset URLs, a <base> element, or the API’s prince_options.baseurl setting to resolve relative references. A leading slash resolves from the host root, which may not be the directory you expect.

Example document markup

<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Quarterly report</title>
    <style>
      @page { size: A4; margin: 18mm; }
      body { font: 12pt/1.45 sans-serif; color: #172033; }
      h1 { break-after: avoid; }
      .report-section { break-inside: avoid; }
      @media print {
        .screen-only { display: none !important; }
      }
    </style>
  </head>
  <body>
    <main>
      <h1>Quarterly report</h1>
      <section class="report-section">
        <h2>Revenue</h2>
        <p>Render the report data here.</p>
      </section>
    </main>
  </body>
</html>

This is document markup, not a React component passed directly to DocRaptor. Your application can render the markup using React before sending it, or make the React-powered document available at a URL for DocRaptor to fetch and execute.

2. Call DocRaptor from a trusted server

Send a JSON POST request to https://api.docraptor.com/docs. DocRaptor’s API accepts a doc object containing fields such as document_type, document_content or document_url, and javascript; the account credential is supplied as user_credentials. Keep the account key in a server environment variable. Do not put a private key in a public React bundle or browser request: client-side code exposes it in page source.

The following Node.js example uses the built-in fetch available in current Node releases. It reads an HTML document from a local file, requests a PDF in test mode, and saves the binary response. Test mode produces a watermarked document.

// save as make-pdf.mjs; set DOCRAPTOR_API_KEY in the server environment
import { readFile, writeFile } from 'node:fs/promises';

const apiKey = process.env.DOCRAPTOR_API_KEY;
if (!apiKey) throw new Error('Set DOCRAPTOR_API_KEY');

const html = await readFile('./report.html', 'utf8');
const response = await fetch('https://api.docraptor.com/docs', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    user_credentials: apiKey,
    doc: {
      name: 'quarterly-report',
      document_type: 'pdf',
      document_content: html,
      javascript: true,
      test: true
    }
  })
});

const bytes = new Uint8Array(await response.arrayBuffer());
if (!response.ok) {
  const detail = new TextDecoder().decode(bytes);
  throw new Error(`DocRaptor returned HTTP ${response.status}: ${detail}`);
}
await writeFile('./report.pdf', bytes);
console.log('Saved report.pdf');

Run it with DOCRAPTOR_API_KEY=your_key node make-pdf.mjs after creating report.html. For production, set test to false or omit it, and use your account’s documented credential handling. Never ship the environment variable to the browser.

3. Equivalent cURL and Python requests

These examples use the same JSON API shape. Replace the placeholder key, and place the HTML in report.html. They use test mode so generated documents are watermarked.

cURL

export DOCRAPTOR_API_KEY='your_api_key'
curl --fail-with-body \
  -H 'Content-Type: application/json' \
  -d "{\"user_credentials\":\"$DOCRAPTOR_API_KEY\",\"doc\":{\"name\":\"quarterly-report\",\"document_type\":\"pdf\",\"document_content\":$(python3 -c 'import json; print(json.dumps(open("report.html").read()))'),\"javascript\":true,\"test\":true}}" \
  https://api.docraptor.com/docs \
  -o report.pdf

This cURL form uses Python only to JSON-encode the HTML file safely. For a URL input, replace document_content with document_url and its reachable URL.

Python

import os
from pathlib import Path
import requests

api_key = os.environ["DOCRAPTOR_API_KEY"]
html = Path("report.html").read_text(encoding="utf-8")

response = requests.post(
    "https://api.docraptor.com/docs",
    json={
        "user_credentials": api_key,
        "doc": {
            "name": "quarterly-report",
            "document_type": "pdf",
            "document_content": html,
            "javascript": True,
            "test": True,
        },
    },
    timeout=180,
)
if not response.ok:
    raise RuntimeError(f"DocRaptor returned HTTP {response.status_code}: {response.text}")
Path("report.pdf").write_bytes(response.content)

4. Make React rendering and data loading finish

DocRaptor’s standard JavaScript engine supports React, but JavaScript is off by default. Set the API option javascript to true when the HTML depends on React execution. This is separate from passing a React component: the service still needs HTML or a URL.

Rendering may involve asynchronous API requests, delayed component updates, or client-side data fetching. Ensure those operations complete before the converter considers the page rendered. DocRaptor documents a JavaScript completion function, docraptorJavaScriptFinished(), and rendering delay controls for pages that need more time. Choose a completion approach that reflects actual readiness; a fixed delay can be too short under slow conditions and waste time when the page is fast.

If you use the completion function, make the page report completion only after the data is available and React has updated the document. The precise implementation depends on your application and must be available to the JavaScript engine in the rendered page. Test with representative data and delayed responses.

5. Choose input, JavaScript engine, and media settings

Decision Use it when Check
document_content or document_url Choose content when your server has assembled the HTML; choose a URL when DocRaptor can retrieve the document directly. Content often needs an explicit base for relative assets. A URL must be reachable and have the access needed to render.
Standard JavaScript or Prince JavaScript The standard engine is the documented general choice for typical React execution. Prince’s engine is for Prince-specific scripting cases such as canvas or PDF-specific capabilities. The engines differ. Prince is not a modern browser, and its behavior may differ from browser JavaScript. Avoid enabling both casually: both can execute JavaScript, potentially twice.
Print or screen media Print is the default and is usually appropriate for a PDF document. If the PDF should match screen styling, select the relevant media option in the API and check its effect. Review print rules, page size, margins, and breaks.
Synchronous or asynchronous/hosted result Use the result mode that suits the request and document volume. A successful synchronous generation returns PDF bytes. Hosted document mode returns a URL; asynchronous generation returns a status_id to retrieve later.

Use prince_options for Prince-specific configuration such as a base URL or Prince features. Keep the standard javascript option distinct from prince_options.javascript; they refer to different JavaScript engines. Consult the API reference for the complete current option list and exact parameter nesting before adding less common settings.

6. Make print layout and assets predictable

  • Print CSS: PDF conversion uses print media rules by default. Add or review @media print styles and @page size and margins. Hide controls that are useful on screen but not in a report.
  • Page breaks: Use print CSS break properties intentionally around headings, tables, and sections. Check long tables and sections that may split across pages.
  • Fonts and images: Use absolute URLs or a configured base, and confirm the conversion service can retrieve every asset. A page that depends on local development paths will not have those files in the remote render.
  • Authentication: If the document URL is private, arrange an access method suitable for the conversion request. Do not assume the renderer has the end user’s cookies or browser state.
  • Data consistency: Render one coherent report snapshot. Avoid a page whose data can change between initial HTML and later client-side fetches.

7. Handle responses and failures

Always check the HTTP status before treating a response as a PDF. Successful synchronous generation returns binary PDF bytes; generation errors can return XML rather than PDF. Decode and log the error response on failure, while keeping API keys and sensitive document data out of logs. For asynchronous generation, retain and poll or retrieve by the returned status_id according to the API flow; for hosted mode, handle the returned document URL rather than attempting to save the response as PDF bytes.

8. Troubleshooting

Symptom Likely cause Fix
PDF is blank or missing React-rendered content JavaScript is disabled, or the page is captured before React renders. Set javascript: true. Ensure the document includes the required scripts and data, then use the documented completion signal or delay for asynchronous work.
Some report sections are absent or stale Data fetching or delayed state updates have not finished when rendering ends. Signal completion only after data and the React update are complete. Reproduce with realistic network and data timing.
Images, CSS, or fonts are missing Relative URLs resolve against the wrong base, or assets are not reachable to DocRaptor. Use absolute asset URLs, a <base> element, or prince_options.baseurl. Check access and URL paths.
PDF styling differs from the browser Print media is the default, while the page was designed around screen styles. Review @media print, page size, margins, and break rules. Use screen media only if that is the intended output.
JavaScript behaves differently from local browser preview The selected engine differs from a full browser, or Prince-specific behavior is being used. Use DocRaptor’s standard engine for typical React rendering. Select Prince JavaScript only for cases requiring its capabilities, and verify engine-specific code.
PDF file contains an error message or is corrupt An error response was saved as if it were PDF bytes, or the request failed. Check response.ok or the HTTP status first; decode the error body and save bytes only on success.
API key appears in browser source The conversion request was made from public client code. Move the call to a trusted server. Use a carefully configured referrer-based approach only where it fits the documented account setup.
Test PDF has a visible watermark The request used test mode. That watermark is expected in test output. Use the appropriate production setting for final documents.

9. Performance, reliability, and cost

JavaScript execution adds work compared with converting static HTML; DocRaptor says JavaScript is disabled by default to speed up documents that do not require it. Enable it for React-dependent content, but keep the document focused: avoid unnecessary scripts, wait for only the work the report needs, and make assets directly reachable. No benchmark or fixed generation time can be inferred for your page; measure representative documents in your own workflow.

For reliability, treat conversion as a network operation: set a client timeout suitable for your document, inspect errors, and avoid assuming every response is a PDF. If the request volume or generation time makes a synchronous request unsuitable, consider the documented asynchronous flow and its status_id retrieval. Retrying should be deliberate so application behavior does not create duplicate work.

DocRaptor usage and account pricing depend on the current account terms; this guide does not assume a price or quota. Test mode is watermarked. Review current DocRaptor account documentation for applicable limits and costs before choosing synchronous versus asynchronous processing.

10. Or skip the browser setup

If you need a screenshot of a React page rather than a PDF, ScreenshotNeo is a screenshot API and MCP server. One GET request returns a PNG, JPEG, WebP, or PDF capture. For the PDF workflow in this article, DocRaptor remains the conversion API; ScreenshotNeo is useful when a screenshot or page capture is the output.

For a URL that the capture service can reach, the basic request is:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo API documentation for request options. Cookie banners, popups, and chat widgets are removed before the shot; bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000.

Sign up for ScreenshotNeo and get 1,000 screenshots a month free, with no card.

FAQ

Can I pass a React component directly to DocRaptor?

No. Render or provide HTML, or make the page available at a URL DocRaptor can fetch.

Do I always need JavaScript enabled?

No. Enable it when React or other client-side code must run to produce the document. Static, already assembled HTML may not need it.

Can I use DocRaptor from a browser button?

A browser button can call your own server endpoint. Keep a private account API key out of publicly served JavaScript.

Will the PDF look exactly like my screen page?

Not necessarily. Print media is the default, so screen and print styles can produce different layouts.