Generate PDFs with Cloudflare and Laravel: A Step-by-Step Guide

June 16, 2025 · 6 min read

Generating PDFs on the fly is a common requirement for many web applications, especially those dealing with invoices, reports, or any document-heavy functionalities. However, scaling this process can be a real headache, especially when your VPS starts struggling with numerous Puppeteer instances. In this tutorial, we’ll dive into how you can use Cloudflare’s Browser Rendering to handle PDF generation easily with Laravel.
Why Cloudflare for PDF Rendering?
Have you ever tried juggling multiple PDF generation tasks on your server only to watch it buckle under the pressure? It’s like trying to bake a dozen cookies in a toaster oven: possible, but not ideal. Cloudflare offers a more scalable solution by handling the heavy lifting of rendering PDFs, freeing up your server to focus on what it does best.
By offloading PDF rendering to Cloudflare, you benefit from:
Scalability: Handle numerous PDF requests without overloading your VPS.
Speed: Generate PDFs in under 200ms with Cloudflare’s efficient rendering.
Cost-Efficiency: Take advantage of Cloudflare’s generous usage limits, minimizing expenses.

Prerequisites
Before we start, make sure you have the following:
Laravel Installed: A fresh Laravel project set up.
Cloudflare Account: Sign up for a Cloudflare account if you haven’t already.
Installing Required Packages
We’ll be using Saloon PHP for handling API integrations. Saloon offers a fluent and intuitive way to interact with APIs, you can also use the default Laravel HTTP Client.
Install Saloon via Composer:
composer require saloonphp/saloon "^3.0"
# Make sure to also install the Laravel Plugin:
composer require saloonphp/laravel-plugin "^3.0"Configuring Saloon PHP
Saloon allows us to define connectors and manage API interactions efficiently. We’ll create a new connector for Cloudflare.
Run the following Artisan command to generate a Saloon connector:
php artisan saloon:connectorThis command scaffolds a basic connector structure for you. Let’s customize it for Cloudflare.
Creating the Cloudflare Connector
Navigate to the newly created connector file, typically found at app/Http/Integrations/Cloudflare/CloudflareConnector.php.
Here’s how your CloudflareConnector should look:
namespace App\Http\Integrations\Cloudflare;
use Saloon\Contracts\Authenticator;
use Saloon\Http\Auth\TokenAuthenticator;
use Saloon\Http\Connector;
use Saloon\Http\Response;
use Saloon\Traits\Plugins\AcceptsJson;
class CloudflareConnector extends Connector
{
use AcceptsJson;
/**
* The Base URL of the API
*/
public function resolveBaseUrl(): string
{
$accountId = config('services.cloudflare.account_id');
return "https://api.cloudflare.com/client/v4/accounts/$accountId/browser-rendering";
}
protected function defaultAuth(): ?Authenticator
{
return new TokenAuthenticator(config('services.cloudflare.api_key'));
}
}Key Points:
Base URL: Customized to include your Cloudflare account ID.
Authentication: Uses
TokenAuthenticatorwith your Cloudflare API key.
Obtaining Your Cloudflare Credentials
Account ID:
Log in to your Cloudflare Dashboard.
Navigate to the Account Overview.
Locate your Account ID.
API Token:
Go to My Profile > API Tokens.
Generate a new token with permissions for Browser Rendering.
Ensure you store these credentials securely, preferably in your .env file.
Updating Configuration
Add your Cloudflare credentials to config/services.php:
return [
// ...rest of the config here
'cloudflare' => [
'account_id' => env('CLOUDFLARE_ACCOUNT_ID'),
'api_key' => env('CLOUDFLARE_API_KEY'),
]
]Next, update your .env file with the new variables:
CLOUDFLARE_ACCOUNT_ID=your_account_id_here
CLOUDFLARE_API_KEY=your_api_key_here
Building the RenderPDF Request
With our connector in place, it’s time to define the request that will handle PDF rendering.
Generate a new Saloon request:
php artisan saloon:requestThis creates a request class, typically at app/Http/Integrations/Cloudflare/Requests/RenderPDF.php.
Here’s a detailed look at our RenderPDF request:
namespace App\Http\Integrations\Cloudflare\Requests;
use Illuminate\Contracts\View\View;
use Saloon\Contracts\Body\HasBody;
use Saloon\Enums\Method;
use Saloon\Http\Request;
use Saloon\Traits\Body\HasJsonBody;
class RenderPDF extends Request implements HasBody
{
use HasJsonBody;
/**
* The HTTP method of the request
*/
protected Method $method = Method::POST;
public function __construct(
public View $html,
) {}
public function defaultBody(): array
{
return [
'html' => $this->html->render(),
'addScriptTag' => [
[
'url' => 'https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4'
]
]
];
}
/**
* The endpoint for the request
*/
public function resolveEndpoint(): string
{
return '/pdf';
}
}What’s Happening Here:
HTTP Method: We’re using a
POSTrequest to send our HTML content.Constructor: Accepts a Laravel
Viewinstance containing the HTML to be converted.Default Body: Sends the rendered HTML and includes a script tag for Tailwind CSS to style the PDF.
By implementing HasJsonBody, we ensure our request body is correctly formatted as JSON, which Cloudflare expects.
Adding a helper method to our connector
Now that we have the RenderPDF request class, we like to add a helper method to our connector that calls the Request class with the required params. We can do this by editing our CloudflareConnector:
namespace App\Http\Integrations\Cloudflare;
use App\Http\Integrations\Cloudflare\Requests\RenderPDF;
use Illuminate\Contracts\View\View;
use Saloon\Contracts\Authenticator;
use Saloon\Http\Auth\TokenAuthenticator;
use Saloon\Http\Connector;
use Saloon\Http\Response;
use Saloon\Traits\Plugins\AcceptsJson;
class CloudflareConnector extends Connector
{
use AcceptsJson;
/**
* The Base URL of the API
*/
public function resolveBaseUrl(): string
{
$accountId = config('services.cloudflare.account_id');
return "https://api.cloudflare.com/client/v4/accounts/$accountId/browser-rendering";
}
protected function defaultAuth(): ?Authenticator
{
return new TokenAuthenticator(config('services.cloudflare.api_key'));
}
public function render(View $html): Response
{
return $this->send(new RenderPDF($html));
}
}You can also call the Request on its own, but we prefer having the methods inside the integration as it makes the code a bit cleaner and easier to read.
Designing Blade Views for PDFs
Now, let’s create the Blade views that will serve as the HTML templates for our PDFs.
Creating the Print Layout
In resources/views/components/, create a new Blade component named print.blade.php:
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<style type="text/tailwindcss">
@theme {
--color-clifford: #da373d;
}
</style>
</head>
<body {{ $attributes->merge() }}>
{{ $slot }}
</body>
</html>Highlights:
Tailwind CSS Integration: Using the Tailwind CDN for styling.
Custom Themes: The
@themedirective allows for color customization, making your PDFs visually appealing.
Creating the Invoice Blade View
Next, create a print directory inside resources/views and add an invoice.blade.php file:
<x-print class="bg-gray-200">
<div class="max-w-[85rem] px-4 sm:px-6 lg:px-8 mx-auto my-4 sm:my-10">
@foreach($items as $item)
<!-- Your invoice item markup here -->
@endforeach
</div>
</x-print>Customization Tips:
Data Binding: Pass dynamic data such as
$itemsto list invoice details.Styling: Use Tailwind classes to style your PDF layout.
Feel free to expand upon this template with additional Blade directives and HTML as per your requirements.
Implementing the Invoice Controller
With our views ready, it’s time to create a controller that ties everything together.
Generate an invokable controller:
php artisan make:controller InvoiceController --invokableOpen app/Http/Controllers/InvoiceController.php and update it as follows:
namespace App\Http\Controllers;
use Exception;
use Illuminate\Http\Request;
use App\Http\Integrations\Cloudflare\CloudflareConnector;
class InvoiceController extends Controller
{
/**
* Handle the incoming request.
*/
public function __invoke(Request $request, CloudflareConnector $cloudflare)
{
try {
$pdf = $cloudflare->render(view('print.invoice', [
'title' => 'Awesome PDF',
'items' => $request->input('items', []),
]));
return response($pdf, 200, [
'Content-Type' => 'application/pdf',
]);
} catch (Exception $e) {
return response()->json([
'error' => 'Failed to generate PDF',
'message' => $e->getMessage()
], 500);
}
}
}Key Features:
Dependency Injection: Injects the
CloudflareConnectorfor sending render requests.Error Handling: Uses a try-catch block to manage potential exceptions.
Dynamic Data: Passes data from the request to the Blade view for dynamic PDF content.

Routing the Controller
Define a route for your invoice PDF generation. In routes/web.php, add:
use App\Http\Controllers\InvoiceController;
Route::post('/generate-invoice', InvoiceController::class);Now, your application is ready to handle invoice generation requests.
Handling Errors
Robust applications anticipate the unexpected. Let’s enhance our controller to handle errors more effectively.
In the InvoiceController, the try-catch block ensures that any issues during PDF generation are caught and a user-friendly error message is returned. You can further customize this by implementing specific exception handling based on Saloon’s capabilities.
For instance, you might want to handle network errors separately or provide retry mechanisms. Implementing such features ensures a smoother user experience, even when things go sideways.
Debugging Tips
Check Cloudflare Logs: Ensure that requests are being sent and received correctly.
Laravel Logs: Inspect
storage/logs/laravel.logfor any errors or warnings.View Rendering: Verify that your Blade views render correctly by accessing them in a browser.
Optimizing for Performance
While Cloudflare handles the heavy lifting, optimizing your Laravel application ensures maximum efficiency.
Caching Blade Views
Render views efficiently by caching them. Laravel automatically caches views, but ensure you’re not introducing unnecessary complexities that might hinder this process.
Asynchronous Requests
Consider offloading PDF generation to Laravel Jobs, especially when these tasks are triggered by user actions that don’t require immediate feedback.
Monitoring Usage
Keep an eye on your Cloudflare usage to stay within the generous limits.
Conclusion
Scaling PDF generation in your Laravel application doesn’t have to be a daunting task. By using Cloudflare’s Browser Rendering, you offload the resource-intensive process of rendering PDFs, ensuring your VPS remains performant and responsive. With Saloon PHP handling API interactions and Laravel’s robust framework powering your application, generating PDFs becomes a breeze.
Whether you’re dealing with numerous invoices, reports, or any document-heavy functionalities, this setup offers a scalable, efficient, and cost-effective solution. Give your Laravel app the power of Cloudflare and easily handle your PDF generation process.
FAQs
Why should I use Cloudflare for PDF rendering instead of handling it on my server?
Using Cloudflare offloads the resource-intensive task of PDF rendering from your server, ensuring better scalability and performance. It also helps in reducing memory usage and handling high volumes of PDF generation without hitting server limits.
Can I customize the styling of my PDFs generated via Cloudflare?
By using Blade views and Tailwind CSS, you can design and style your PDFs to match your application’s requirements. Tailwind’s utility classes make it easy to create responsive and visually appealing layouts.
What happens if Cloudflare’s API limits are exceeded?
While Cloudflare offers generous limits, exceeding them may result in throttled requests or additional charges. It’s essential to monitor your usage and implement appropriate error handling to manage such scenarios.
Is Saloon PHP the only package I can use for this integration?
Saloon PHP is a great choice for handling API integrations in Laravel, but it’s not the only option. Depending on your preferences, you can also use the default Laravel HTTP Cl. However, Saloon provides a more structured and intuitive approach for API interactions.
How secure is the PDF generation process with Cloudflare?
Cloudflare ensures secure communication between your application and its services using HTTPS. Additionally, by using API tokens with specific permissions, you can maintain a high level of security and control over your PDF rendering processes.
Bring Your Ideas to Life 🚀
If you need help with a Laravel project let’s get in touch.
Lucky Media is proud to be recognized as a leading Laravel Development Agency
Technologies

Stay up-to-date
Be updated with all news, products and tips we share!
On this page
- Why Cloudflare for PDF Rendering?
- Prerequisites
- Installing Required Packages
- Configuring Saloon PHP
- Creating the Cloudflare Connector
- Obtaining Your Cloudflare Credentials
- Updating Configuration
- Building the RenderPDF Request
- Adding a helper method to our connector
- Designing Blade Views for PDFs
- Implementing the Invoice Controller
- Optimizing for Performance
- Conclusion
- FAQs
- Bring Your Ideas to Life 🚀

