How to Generate PDFs from a Webpage with PDFShift in PHP
Convert a webpage or raw HTML to PDF with PDFShift in PHP, with runnable code, configuration guidance, and fixes for common errors.
To generate a PDF from a webpage in PHP with PDFShift, send a JSON POST request to https://api.pdfshift.io/v3/convert/pdf. Put the webpage URL or raw HTML in the source field, authenticate with the X-API-Key header, check the HTTP status, and save the successful response body as a .pdf file.
Use a URL when PDFShift can reach the page and should fetch it. Use raw HTML when your PHP application already has the markup or the page is private. PDFShift recommends raw HTML, and says that inlining CSS and JavaScript can reduce resource requests and conversion time. These are the vendor’s recommendations, not independent performance measurements. PDFShift’s PHP guide documents the conversion flow.
1. Prepare PHP and your API key
The examples below use PHP’s cURL extension. Confirm that cURL is enabled in the PHP runtime that will make the request. Store the PDFShift API key in a server-side environment variable or secret store; never put it in browser JavaScript or commit it to a public repository.
export PDFSHIFT_API_KEY='your_api_key'
In a long-running application or managed hosting environment, configure the variable through that environment’s secret settings. The shell command above is suitable for a local session and does not persist across every hosting setup.
2. Convert a webpage URL to PDF
This complete PHP script asks PDFShift to fetch a public page and writes the returned PDF to webpage.pdf. Run it from the command line as php webpage_to_pdf.php. Choose an output path your PHP process is allowed to write.
<?php
$apiKey = getenv('PDFSHIFT_API_KEY');
if ($apiKey === false || $apiKey === '') {
throw new RuntimeException('Set the PDFSHIFT_API_KEY environment variable.');
}
$params = [
'source' => 'https://example.com',
];
$ch = curl_init('https://api.pdfshift.io/v3/convert/pdf');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($params, JSON_THROW_ON_ERROR),
CURLOPT_HTTPHEADER => [
'X-API-Key: ' . $apiKey,
'Content-Type: application/json',
'Accept: application/pdf',
],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => 15,
CURLOPT_TIMEOUT => 120,
]);
$pdf = curl_exec($ch);
if ($pdf === false) {
$error = curl_error($ch);
curl_close($ch);
throw new RuntimeException('PDFShift transport error: ' . $error);
}
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status < 200 || $status >= 300) {
throw new RuntimeException(
'PDFShift returned HTTP ' . $status . ': ' . substr($pdf, 0, 2000)
);
}
if (strncmp($pdf, '%PDF-', 5) !== 0) {
throw new RuntimeException('The successful response did not look like a PDF.');
}
$outputPath = __DIR__ . '/webpage.pdf';
if (file_put_contents($outputPath, $pdf) === false) {
throw new RuntimeException('Could not write PDF to ' . $outputPath);
}
echo "Saved PDF to {$outputPath}\n";
Replace https://example.com with the page to convert. The script keeps the API key out of the request body and reports transport, HTTP, response-format, and file-write failures separately.
3. Convert raw HTML instead
Set source to an HTML string when your application creates the document or when PDFShift cannot fetch the page itself. The request and response handling stay the same:
<?php
$html = '<!doctype html>
<html>
<head>
<meta charset="utf-8">
<style>
body { font-family: sans-serif; margin: 32px; }
h1 { color: #183153; }
</style>
</head>
<body>
<h1>Invoice 1042</h1>
<p>Amount due: $125.00</p>
</body>
</html>';
$params = ['source' => $html];
// Send $params as JSON to the PDFShift endpoint using the cURL flow above.
For a complete script, use the first example and replace its $params assignment with the HTML example’s assignment. Keep the document self-contained where practical: inline styles and scripts, or ensure referenced resources are reachable to the conversion service. PDFShift’s PHP guide recommends raw HTML and notes that inlining resources can reduce network requests and loading time. See the official PHP guide for its raw HTML example.
4. Choose URL or HTML input
| Input | Use it when | Things to check |
|---|---|---|
| Page URL | The page is reachable by PDFShift and you want it to retrieve the rendered document. | The server is public or otherwise reachable; required assets load; the page does not depend on a logged-in browser session. |
| Raw HTML | PHP already has the markup, the document is private, or you want direct control over the HTML sent for conversion. | Include necessary CSS and content, and make external assets accessible or inline them where appropriate. |
Both approaches use the same source parameter. URL input delegates page retrieval to the conversion service. Raw input avoids fetching the HTML document from your application a second time, though linked assets may still need retrieval.
5. Return the PDF from a PHP web endpoint
For an application route that should deliver the PDF to a browser, capture the PDF bytes as above, then send PDF headers and the bytes instead of writing a file. Do not print debug output before the headers.
<?php
// Assume $pdf contains a successful PDF response body.
header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename="webpage.pdf"');
header('Content-Length: ' . strlen($pdf));
echo $pdf;
exit;
Only send these headers after verifying the HTTP status was successful and the response is a PDF. For large documents, consider the memory implications of buffering the full response in PHP; the basic cURL example uses CURLOPT_RETURNTRANSFER and therefore holds the body in memory.
6. Authentication, options, and related workflows
Use the current API key header
Send the key as X-API-Key. PDFShift’s help article identifies this as the current API-key header and says that a request without authentication can fall back to unauthenticated mode and produce a watermark. If a PDF unexpectedly has a watermark, first confirm that the header is present and that the key is valid. PDFShift authentication guidance.
Conversion options
The core request needs a source. PDFShift documents further conversion topics in its PHP guide index. These include custom headers and footers, text and image watermarks, time limits, page selection, full-height output, CSS or JavaScript supplied inline or by URL, PDF protection, webhooks, hosted output, Amazon S3 delivery, custom HTTP headers, cookies, and waiting for a custom page element. The exact option names and accepted values depend on the individual feature; consult the relevant official PHP guide before adding them rather than guessing parameter names.
The PHP guide index includes both cURL and Guzzle examples. Pick the client your application already uses; the available research does not establish a universal performance advantage for either one.
Check account usage
PDFShift’s help material describes GET https://api.pdfshift.io/v3/credits/usage as an authenticated way to check usage. Use the current official documentation for the precise request and response details. Authentication and usage guidance.
7. cURL, Python, and Node.js reference requests
These examples show the same API request from other clients. Keep the API key in a server-side environment variable. They are included as language references; the PHP implementation above is the main workflow for this article.
cURL
curl --request POST \
--url https://api.pdfshift.io/v3/convert/pdf \
--header "X-API-Key: $PDFSHIFT_API_KEY" \
--header "Content-Type: application/json" \
--data '{"source":"https://example.com"}' \
--output webpage.pdf
For production shell scripts, check the HTTP status and command exit code before treating the output file as a valid PDF.
Python
import os
import requests
api_key = os.environ["PDFSHIFT_API_KEY"]
response = requests.post(
"https://api.pdfshift.io/v3/convert/pdf",
headers={"X-API-Key": api_key, "Accept": "application/pdf"},
json={"source": "https://example.com"},
timeout=(15, 120),
)
response.raise_for_status()
if not response.content.startswith(b"%PDF-"):
raise RuntimeError("Successful response did not look like a PDF")
with open("webpage.pdf", "wb") as pdf_file:
pdf_file.write(response.content)
Node.js
const apiKey = process.env.PDFSHIFT_API_KEY;
if (!apiKey) throw new Error('Set PDFSHIFT_API_KEY');
const response = await fetch('https://api.pdfshift.io/v3/convert/pdf', {
method: 'POST',
headers: {
'X-API-Key': apiKey,
'Content-Type': 'application/json',
'Accept': 'application/pdf'
},
body: JSON.stringify({ source: 'https://example.com' }),
signal: AbortSignal.timeout(120_000)
});
if (!response.ok) {
throw new Error(`PDFShift returned HTTP ${response.status}: ${await response.text()}`);
}
const pdf = Buffer.from(await response.arrayBuffer());
if (!pdf.subarray(0, 5).equals(Buffer.from('%PDF-'))) {
throw new Error('Successful response did not look like a PDF');
}
await import('node:fs/promises').then(({ writeFile }) => writeFile('webpage.pdf', pdf));
8. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| PDF contains a watermark | The request did not authenticate; PDFShift says unauthenticated mode can add one. | Send a valid key in X-API-Key. Check that the environment variable is set in the PHP worker or process that makes the request. |
| HTTP error response | Invalid credentials, invalid request data, or an issue retrieving/converting the source. | Record the HTTP status and a bounded portion of the error body on the server. Check the endpoint, JSON encoding, API key, and source accessibility. Do not return secret-bearing diagnostics to end users. |
curl_exec() returns false |
Transport failure such as a connection or TLS error, or a timeout. | Read curl_error(), verify outbound HTTPS access and certificates, and set a timeout suitable for the document. Retry only transient failures, with a limit. |
| PDF is blank or missing images/styles | The source page or its assets were unavailable to the converter, or the page was not ready when captured. | Try raw HTML, inline CSS and scripts where practical, verify asset URLs are reachable, and consult PDFShift’s documented custom-element waiting or time-limit options. |
| Saved file is not a PDF | An error body was saved as if it were a successful binary response. | Check HTTP status before saving, inspect the error body separately, and verify the PDF signature as in the examples. |
| PHP cannot write the output | The selected directory is not writable by the PHP process or the path is wrong. | Choose an application-controlled writable directory, check file_put_contents(), and review process permissions. |
| Request times out | Slow source rendering, unavailable assets, or a timeout shorter than the conversion duration. | Check the page independently, reduce unnecessary external resource dependencies, set a realistic client timeout, and consult the documented PDFShift time-limit settings. |
9. Performance, reliability, and cost considerations
- Reduce resource fetches: PDFShift recommends raw HTML and says inline CSS and JavaScript can reduce resource requests and conversion time. Treat this as vendor guidance; actual duration depends on the document and its resources.
- Set bounded timeouts: Use separate connection and total timeouts so a stalled request does not occupy a PHP worker indefinitely. Choose values based on your own document and application requirements.
- Retry carefully: Retry transient network or service failures only with a small bounded policy and backoff. Avoid blindly retrying malformed requests or authentication errors. Consider that repeating a request may perform another conversion.
- Protect availability: Log status codes and correlation details available to your application, alert on sustained failures, and keep generated PDFs only as long as your product needs. Do not log API keys or sensitive document contents.
- Budget by actual account terms: Conversion pricing and quotas are not established in the research dossier. Check PDFShift’s current plan and usage information before estimating costs. The vendor homepage displays its own conversion, developer, average-time, and uptime figures; those are vendor-reported claims, not independent measurements. PDFShift homepage.
10. Or skip the browser setup
If your task is to capture a webpage as an image or PDF without building browser automation, ScreenshotNeo offers a website screenshot API and MCP server. One GET request can return PNG, JPEG, WebP, or PDF. Its clean-shot flow accepts cookie banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers indicate the page verdict and billing status.
For a PDF response, use the PDF format option documented in the ScreenshotNeo API docs. This PHP example follows the documented one-call endpoint pattern; add the PDF format parameter described there for a PDF output.
<?php
$query = http_build_query([
'access_key' => getenv('SCREENSHOTNEO_API_KEY'),
'url' => 'https://example.com',
'format' => 'pdf',
]);
$pdf = file_get_contents('https://api.screenshotneo.com/v1/shot?' . $query);
if ($pdf === false) {
throw new RuntimeException('ScreenshotNeo request failed');
}
file_put_contents(__DIR__ . '/webpage.pdf', $pdf);
ScreenshotNeo also has an MCP server with take_screenshot, get_page_info, and capture_pdf tools for AI agents including Claude, Cursor, and other MCP clients. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. See the docs for request parameters and PDF output, then sign up free for 1,000 screenshots a month, with no card required.
FAQ
Can PDFShift convert HTML that is not hosted publicly?
Yes. Send the HTML string in source instead of asking PDFShift to fetch a URL. Ensure the document’s linked assets are also available or included in the markup.
Why does PDFShift use X-API-Key?
PDFShift’s current help guidance identifies that header for API-key authentication. It also warns that unauthenticated requests can produce a watermarked result.
Should I use cURL or Guzzle in PHP?
Use the client your project already maintains. PDFShift publishes both PHP tracks; the research does not establish a universal speed winner.
Can the service save directly to cloud storage?
PDFShift’s PHP guide index lists hosted output and Amazon S3 delivery guides. Check those guides for current parameters and setup requirements.


