Cloudflare browser rendering
Cloudflare Browser Rendering API — Migration Plan
Goal
Replace Spatie Browsershot with Cloudflare's Browser Rendering API for HTML→PDF/PNG rendering, preserving current export behaviors and S3 uploads.
1) Configuration and env
- Add to .env / .env.example:
CLOUDFLARE_ACCOUNT_ID=CLOUDFLARE_BROWSER_API=(token)RENDERER_DRIVER=cloudflare(feature flag; fallback: browsershot)
- Update
config/services.php:cloudflare.account_id,cloudflare.token, optionalcloudflare.base_url(https://api.cloudflare.com/client/v4).
2) Rendering abstraction
- Create
App\Contracts\RendererInterface:renderPdfFromUrl(string $url, array $options): stringrenderImageFromUrl(string $url, array $options): string
- Implement
App\Services\Rendering\CloudflareRenderService. - Optional:
BrowsershotRenderServiceadapter to support dual-run.
3) Cloudflare service behavior
- Use Laravel HTTP client with token auth.
- Endpoints:
POST /accounts/{accountId}/browser-rendering/pdfPOST /accounts/{accountId}/browser-rendering/screenshot
- Options mapping:
- Common:
url,waitUntil,viewport,fullPage,timeout - PDF:
printBackground,preferCSSPageSize,margin,landscape
- Common:
- Return raw bytes; persistence handled upstream.
4) Orchestration
- Introduce
App\Services\ExportServiceto replaceBrowsershotServiceusage sites. - Responsibilities:
- Build export URL (reuse existing logic from
BrowsershotService). - Translate request params to renderer options.
- Save result to
storage/exports/...; upload to S3 for element/graphic flows. - Return S3 URL or local path to controllers.
- Build export URL (reuse existing logic from
- Bind
RendererInterfacetoCloudflareRenderServicewhenRENDERER_DRIVER=cloudflare, else to legacy.
5) Controllers
- Replace direct
BrowsershotServiceinstantiations withExportServicewhile preserving outputs.
6) Layout determinism
- Embed deterministic CSS on export routes:
- PDFs:
@page { size: <target>; margin: 0 },preferCSSPageSize: true. - Images: sensible viewport defaults (e.g., 1920x1080 or 1200x800) with
fullPage: true.
- PDFs:
7) Queueing and rate limiting
- Optional async job (
RenderExportJob) with named limitercloudflareand exponential backoff.
8) Storage
- Preserve current file paths and S3 upload headers (ContentDisposition).
9) Errors and logging
- Throw on non-2xx; catch in orchestration; log org/export context.
10) Tests
- Unit-test
CloudflareRenderServicewithHttp::fake(); feature-testExportServicehappy and failure paths. - Update places that mock Browsershot to use
Http::fake()whenRENDERER_DRIVER=cloudflare.
11) Rollout
- Phase behind flag; validate in staging; then remove Browsershot deps and service.
Acceptance
- All current exports (projects/objectives/targets/tasks/elements/graphics) produce acceptable PDFs/PNGs and S3 uploads remain intact.