Cloudflare developer guide
At a glance
Section titled “At a glance”The Cloudflare package moves Portable Document Format (PDF) rendering to a Worker boundary. Treat Worker rendering, local fallback, application programming interface (API) protection, and the R2 archive as separate capabilities, each with its own failure handling.
Use this guide when you build edge-rendering services, protected render endpoints, archive workflows, or local fallback paths with nextpdf/cloudflare.
Architecture boundary
Section titled “Architecture boundary”| Layer | Owned by | Responsibility | Do not put here |
|---|---|---|---|
| Application endpoint | Application | Authorize the caller, normalize the render request, and enforce business policy. | Worker tokens stored in code. |
| API protection | nextpdf/cloudflare and application | API key checks, payload size checks, and in-process rate-limit decisions. | Billing, tenant entitlement, or durable quota enforcement. |
| Cloudflare renderer | nextpdf/cloudflare | Validate Hypertext Markup Language (HTML) and the Worker Uniform Resource Locator (URL), send the render payload, and parse the response. | Template rendering or domain queries. |
| Worker | Application deployment | Run Browser Rendering and return PDF bytes or a structured result. | PHP-side storage policy. |
| Local fallback | Application deployment | Render when the Worker is unavailable. | Silent fallback that hides operational outages. |
| R2 archive | nextpdf/cloudflare | Upload PDF files, build object keys, and create signed URLs. | Sensitive business metadata without review. |
Runtime lifecycle
Section titled “Runtime lifecycle”| Stage | Behavior | Developer action |
|---|---|---|
| Config creation | Loads the Worker URL, API token, timeouts, size limits, fallback, and pins. | Keep secrets in deployment config. |
| Request protection | Optional ApiProtection validates the key, size, and rate limit. | Run it before expensive render work. |
| Renderer call | CloudflareHtmlRenderer validates HTML and the Worker URL, then sends JavaScript Object Notation (JSON). | Handle Worker unavailability and render failures separately. |
| Response parsing | CloudflareResponseParser::parse() accepts binary PDF output or structured JSON output. | Reject invalid or non-PDF output. |
| Local fallback | An optional local renderer handles Worker failure. | Inject a local renderer factory only when the host supports it. |
| R2 archive | R2ArchiveManager stores PDF bytes and creates signed URLs. | Keep metadata non-sensitive unless you intentionally store it. |
Recommended application structure
Section titled “Recommended application structure”| Path | Purpose |
|---|---|
app/Pdf/Cloudflare/* | Application wrapper for CloudflareHtmlRenderer. |
app/Pdf/Workers/* | Worker request data transfer objects (DTOs) and endpoint-specific policy. |
app/Pdf/Archive/* | R2 archive orchestration and retention decisions. |
app/Pdf/Fallback/* | LocalRendererFactoryInterface implementation for allowed fallback. |
tests/Pdf/Cloudflare/* | Worker-down, invalid-token, payload, and archive tests. |
Keep the PHP API token separate from the Worker token. PHP authenticates to the Worker. The Worker should authenticate incoming requests before it starts browser work.
<?php
use NextPDF\Cloudflare\ApiProtection;use NextPDF\Cloudflare\ApiProtectionConfig;use NextPDF\Cloudflare\ApiKeyValidator;
$protection = new ApiProtection( new ApiProtectionConfig(maxRequestsPerMinute: 30), new ApiKeyValidator([$expectedApiKey]),);
$result = $protection->checkRequest( clientId: $clientId, payloadSize: strlen($html), apiKey: $presentedApiKey,);
if (!$result->allowed) { return new JsonResponse(['error' => $result->denialReason], 429, $result->toHeaders());}Renderer pattern
Section titled “Renderer pattern”Build the renderer with PHP Standards Recommendation (PSR) dependencies, including PSR-18 and PSR-17, from your framework. Keep local fallback explicit so operators can see when the system stops using the Worker.
<?php
use NextPDF\Cloudflare\CloudflareHtmlRenderer;use NextPDF\Cloudflare\CloudflareRendererConfig;
$renderer = new CloudflareHtmlRenderer( config: CloudflareRendererConfig::fromArray([ 'worker_url' => getenv('NEXTPDF_CLOUDFLARE_WORKER_URL'), 'api_token' => getenv('NEXTPDF_CLOUDFLARE_API_TOKEN'), 'render_timeout' => 30, 'max_html_size' => 1_000_000, 'fallback_to_local' => false, ]), httpClient: $httpClient, requestFactory: $requestFactory, streamFactory: $streamFactory,);
$rendered = $renderer->render($html, widthPt: 595.28);R2 archive pattern
Section titled “R2 archive pattern”Archive only after rendering succeeds and policy approves the result. Treat public URLs and signed URLs as separate decisions.
<?php
use NextPDF\Cloudflare\R2ArchiveManager;
$upload = $archive->upload( pdfData: $rendered->pdfData, filename: 'invoice-1234.pdf', metadata: [ 'document_type' => 'invoice', ],);
if ($upload->isValid()) { $temporaryUrl = $archive->generateSignedUrl($upload->key, 600);}Do not put customer names, email addresses, invoice totals, or regulated identifiers in object metadata unless your retention and access policy explicitly allows it.
Extension points
Section titled “Extension points”| Extension point | Use it for | Constraint |
|---|---|---|
LocalRendererFactoryInterface | Local fallback through Artisan or another renderer. | Must return an object that implements LocalRendererInterface. |
ApiProtectionConfig | API key, payload size, and rate-limit policy. | In-memory limits apply per process. |
ApiKeyValidator | Timing-safe key validation and key rotation helpers. | Store secrets outside source code. |
R2ArchiveConfig | Bucket, credentials, path prefix, endpoint, and size limits. | Credentials must never be logged. |
PinnedCurlTransport | Internet Protocol (IP) and Subject Public Key Info (SPKI) pin enforcement. | Requires a cURL-capable runtime and response factory. |
CloudflareResponseParser | Worker response parsing. | Rejects invalid PDF output or error responses. |
Development workflow
Section titled “Development workflow”- Build a local render path first.
- Add Worker rendering with a small representative HTML fixture.
- Enable request protection before exposing public endpoints.
- Add R2 upload only after the render and response flows are stable.
- Test Worker-down, invalid-token, oversize-payload, rate-limit, and R2-failure paths.
- Add logs that distinguish Worker render, fallback render, archive upload, and signed URL creation.
Failure handling
Section titled “Failure handling”| Failure | Where it should be handled | Recommended response |
|---|---|---|
| Missing or invalid API key | API protection layer. | Reject the request before render work starts. |
| Oversize payload | API protection or renderer validation. | Return a validation failure with no Worker call. |
| Unsafe Worker URL | Renderer security policy. | Fail configuration or the request before network input/output (I/O). |
| Worker unavailable | Renderer boundary. | Use explicit fallback only when allowed; otherwise fail visibly. |
| R2 upload failure | Archive boundary. | Return the PDF response if archive is optional; fail if archive is required by policy. |
| Pin rotation failure | Deployment and operations. | Rotate with backup pins and a rollback plan. |
Safe defaults
Section titled “Safe defaults”| Concern | Default | When to override |
|---|---|---|
| Fallback | Enabled by config default. | Disable when local rendering would violate deployment isolation. |
| Max HTML size | 5,000,000 bytes. | Lower for public endpoints. |
| Signed URL time to live (TTL) | 3600 seconds. | Shorten it for sensitive PDFs. |
| Pin sets | Empty. | Add pins only with a rotation plan and backup pins. |
| API key requirement | Enabled by protection config default. | Disable only for private, already-authenticated internal calls. |
Testing checklist
Section titled “Testing checklist”- Renderer tests cover valid HTML, oversize HTML, invalid Worker URL, and a Worker error response.
- API protection tests cover a missing key, an invalid key, a payload that is too large, and an exceeded rate limit.
- R2 tests cover successful upload, too-large upload, failed Hypertext Transfer Protocol (HTTP) status, invalid bucket, and signed URL generation.
- Fallback tests verify the local renderer path is explicit and observable.
- Transport tests cover pinned IPs, public-key pins, timeout, and redirects disabled by policy.
- Observability tests assert distinct log events for render, fallback, archive, and signed URL creation.