Skip to content

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, optional cloudflare.base_url (https://api.cloudflare.com/client/v4).

2) Rendering abstraction

  • Create App\Contracts\RendererInterface:
    • renderPdfFromUrl(string $url, array $options): string
    • renderImageFromUrl(string $url, array $options): string
  • Implement App\Services\Rendering\CloudflareRenderService.
  • Optional: BrowsershotRenderService adapter to support dual-run.

3) Cloudflare service behavior

  • Use Laravel HTTP client with token auth.
  • Endpoints:
    • POST /accounts/{accountId}/browser-rendering/pdf
    • POST /accounts/{accountId}/browser-rendering/screenshot
  • Options mapping:
    • Common: url, waitUntil, viewport, fullPage, timeout
    • PDF: printBackground, preferCSSPageSize, margin, landscape
  • Return raw bytes; persistence handled upstream.

4) Orchestration

  • Introduce App\Services\ExportService to replace BrowsershotService usage 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.
  • Bind RendererInterface to CloudflareRenderService when RENDERER_DRIVER=cloudflare, else to legacy.

5) Controllers

  • Replace direct BrowsershotService instantiations with ExportService while 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.

7) Queueing and rate limiting

  • Optional async job (RenderExportJob) with named limiter cloudflare and 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 CloudflareRenderService with Http::fake(); feature-test ExportService happy and failure paths.
  • Update places that mock Browsershot to use Http::fake() when RENDERER_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.