Quickstart — first edge render
At a glance
Section titled “At a glance”On this page, you turn one Hypertext Markup Language (HTML) string into
a Portable Document Format (PDF) file. Each call maps to a method, and
the behavior of each method is verified in
tests/Unit/Cloudflare/CloudflareHtmlRendererTest.php.
Prerequisites
Section titled “Prerequisites”- A Worker endpoint that serves the render contract over Hypertext Transfer Protocol Secure (HTTPS).
- A bearer token accepted by the Worker.
- A PHP Standards Recommendation 18 (PSR-18) client and PHP Standards Recommendation 17 (PSR-17) factories on the path (see /integrations/cloudflare/install/).
The Worker contract, as observed from CloudflareResponseParser: on
success, it returns Hypertext Transfer Protocol (HTTP) 200. The
response carries either Content-Type: application/pdf (raw PDF bytes)
or Content-Type: application/json with a base64 pdf field. Any
non-200 status, or any body that does not start with the %PDF marker,
is treated as a failure.
Step 1 — Construct the configuration
Section titled “Step 1 — Construct the configuration”<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Cloudflare\CloudflareRendererConfig;
$config = new CloudflareRendererConfig( workerUrl: 'https://pdf-renderer.example.workers.dev/render', apiToken: getenv('CF_PDF_TOKEN') ?: throw new RuntimeException('CF_PDF_TOKEN not set'),);The token comes from the environment and is never hard-coded. workerUrl
must use HTTPS. If you pass an http:// URL, the bridge rejects it with
Worker URL must use HTTPS before it sends any request.
Step 2 — Build the renderer
Section titled “Step 2 — Build the renderer”use GuzzleHttp\Client;use GuzzleHttp\Psr7\HttpFactory;use NextPDF\Cloudflare\CloudflareHtmlRenderer;
$httpFactory = new HttpFactory();
$renderer = new CloudflareHtmlRenderer( config: $config, httpClient: new Client(), // PSR-18 ClientInterface requestFactory: $httpFactory, // PSR-17 RequestFactoryInterface streamFactory: $httpFactory, // PSR-17 StreamFactoryInterface logger: null, // optional PSR-3 LoggerInterface responseFactory: $httpFactory, // PSR-17; enables the pinned transport);The constructor requires four arguments: the config, the PSR-18 client, the request factory, and the stream factory. Four more arguments are optional: the logger, the local-renderer factory, an explicit HTML security policy, and the response factory. Supplying the response factory enables the pinned client URL (cURL) transport if a resolved Internet Protocol (IP) set or a Subject Public Key Info (SPKI) pin set is present (see /integrations/cloudflare/security-and-operations/).
Step 3 — Render and write
Section titled “Step 3 — Render and write”use NextPDF\Cloudflare\Exception\CloudflareNotAvailableException;use NextPDF\Cloudflare\Exception\CloudflareRenderException;
try { $result = $renderer->render('<h1>Hello from the edge</h1>');
if (!$result->isValid()) { throw new RuntimeException('Worker did not return a valid PDF'); }
file_put_contents('output.pdf', $result->pdfData); printf("Wrote %d bytes from edge %s in %.1f ms\n", $result->size(), $result->renderLocation !== '' ? $result->renderLocation : 'unknown', $result->renderTimeMs, );} catch (CloudflareRenderException $e) { // Worker answered but the render failed (HTTP error or malformed body). fwrite(STDERR, 'Render failed: ' . $e->getMessage() . PHP_EOL); exit(1);} catch (CloudflareNotAvailableException $e) { // Worker unreachable and no usable fallback. fwrite(STDERR, 'Edge unavailable: ' . $e->getMessage() . PHP_EOL); exit(2);}render() defaults to A4 width (595.28 PDF points) and auto-detected
height (heightPt: 0). The two exception types are intentionally
separate. CloudflareRenderException is a Worker-side failure, and it is
not retried with a fallback. CloudflareNotAvailableException means
the edge could not be reached and no local fallback was available.
Step 4 — Inspect the result
Section titled “Step 4 — Inspect the result”CloudflareRenderResult is final readonly. The fields below are
filled from response headers on the binary path, or from JavaScript
Object Notation (JSON) fields on the JSON path.
| Member | Source |
|---|---|
pdfData | Raw PDF bytes |
widthPt | The width you requested |
heightPt | X-Pdf-Height-Pt header / JSON heightPt; defaults to 841.89 (A4 height) when absent or non-positive |
contentHeightPx | X-Content-Height-Px / JSON contentHeightPx |
renderLocation | Derived from the CF-Ray header suffix (binary path) or JSON renderLocation |
renderTimeMs | X-Render-Time-Ms / JSON renderTimeMs |
size() | strlen($pdfData) |
isValid() | true when the bytes start with %PDF |
Optional — custom paper size, fonts, CSS
Section titled “Optional — custom paper size, fonts, CSS”$result = $renderer->render( html: '<div style="font-family: NotoSansCJK;">繁體中文文件</div>', widthPt: 595.28, heightPt: 841.89, // explicit A4; 0 lets the Worker auto-detect fontFiles: ['NotoSansCJKtc-Regular.ttf'],);fontFiles is meaningful only when the config sets r2FontBucket. The
payload then carries the bucket name and the requested font file paths so
the Worker can load them.
Optional — reachability probe
Section titled “Optional — reachability probe”if ($renderer->isAvailable()) { $result = $renderer->render($html);}isAvailable() sends an authenticated HTTP HEAD to the Worker URL. It
returns true when the status is below 500. It returns false without
throwing when the config is invalid or the request fails. Treat it as a
hint, not a guarantee. The Worker can still fail the subsequent POST.
See also
Section titled “See also”- /integrations/cloudflare/production-usage/ — fallback wiring, telemetry, and R2 archival.
- /integrations/cloudflare/troubleshooting/ — every failure mapped to its exception and message.
- /integrations/cloudflare/configuration/ — full field reference.