Add a PDF download to an existing Laravel page, or generate a PDF from a template. The examples use PDFCrowd's HTML to PDF API and work for invoices, reports, receipts, and other documents built from application data.
Set up the client
Install the PHP client in your Laravel application:
composer require pdfcrowd/pdfcrowd
Laravel already loads Composer's autoloader. You can run the examples below with the
included demo credentials, or replace them with your
PDFCrowd username and API key.
Add a PDF download to an existing page
An existing page can display its usual HTML and return a PDF when the user clicks a download button. Reuse the page's template, data preparation, and access checks.
Choose what to send to PDFCrowd:
- Rendered HTML uses content Laravel has already prepared.
- The page URL lets PDFCrowd fetch the page itself.
Convert rendered HTML
This example extends a document route in routes/web.php.
The getDocumentForCurrentUser($documentId) function is a placeholder for your application's
document lookup and permission checks. Replace it with your own logic and keep any existing
authentication middleware. The Blade template at resources/views/documents/detail.blade.php
receives the result as $document.
The optional pdfBaseUrl value is explained under CSS and images.
use Illuminate\Http\Request; use Illuminate\Support\Facades\Route; Route::match(['get', 'post'], '/documents/{documentId}', function (Request $request, int $documentId) { $document = getDocumentForCurrentUser($documentId); if ($request->isMethod('post') && $request->post('download_pdf')) { $html = view('documents.detail', [ 'document' => $document, 'pdfBaseUrl' => config('services.pdfcrowd.base_url'), ])->render(); try { $client = new \Pdfcrowd\HtmlToPdfClient('demo', 'demo'); $client->setContentViewportWidth('balanced'); $pdf = $client->convertString($html); // Binary string } catch (\Pdfcrowd\Error $error) { // Add your application's error handling here. throw $error; } return response($pdf, 200, [ 'Content-Type' => 'application/pdf', 'Content-Disposition' => 'attachment; filename="document-' . $documentId . '.pdf"', ]); } return view('documents.detail', ['document' => $document]); } )->whereNumber('documentId');
Add this form to the Blade template, outside any existing form:
<form method="post" class="pdfcrowd-remove">
@csrf
<button type="submit" name="download_pdf" value="1">Download PDF</button>
</form>
The web middleware applies Laravel's
request forgery protection.
Keep it enabled; @csrf supplies the form's CSRF token.
GET requests display the HTML page. Submitting the download button sends a POST, renders
the same template, converts it, and returns a PDF download. The pdfcrowd-remove class
hides the form in the PDF while leaving it visible on the webpage.
The response is created only after conversion succeeds, with the PDF held in memory as a
binary string. The catch block rethrows SDK errors to Laravel's error handler. Keep
APP_DEBUG disabled in production
so error responses do not expose private details. See
SDK error handling for details.
To display the PDF in the browser, change attachment to inline. Set
page size,
margins, or other
PDF options before convertString().
Make CSS and images available
PDFCrowd needs reachable URLs for stylesheets, images, and fonts referenced by the rendered
HTML. Absolute asset URLs, such as https://your-site.example/css/document.css, need no
additional base URL.
For relative paths, add the public site or directory URL to the array in config/services.php:
'pdfcrowd' => [ 'base_url' => 'https://your-site.example/', ],
Replace https://your-site.example/ with your website's public URL. Then add this to the
Blade template's <head>, before stylesheet links:
@if (!empty($pdfBaseUrl))
<base href="{{ $pdfBaseUrl }}">
@endif
The PDF branch passes this setting as $pdfBaseUrl. The <base> element tells PDFCrowd
where to resolve relative URLs. For example, /css/document.css becomes
https://your-site.example/css/document.css. This applies to assets and hyperlinks;
avoid adding a second <base> if the template already supplies one.
PDFCrowd cannot reach assets on your development machine through localhost or 127.0.0.1.
For local assets, you can instead package the HTML and assets in a ZIP archive.
Keep paths relative to the archive's folders and omit the website <base> for that approach.
Convert the page URL instead
Instead of sending rendered HTML, you can ask PDFCrowd to open the page through its URL.
Keep the lookup, POST check, client setup, error handling, and response code above. In the
PDF branch, remove the statement that sets $html. Then replace the convertString()
line with:
$pdf = $client->convertUrl($request->fullUrl()); // Binary string
This preserves the current path and query parameters. PDFCrowd makes a separate GET request, so the route returns HTML; only the original POST triggers conversion. The server must be able to handle that GET while the POST waits for the PDF. PHP's built-in development server handles one request at a time by default, so this approach can time out there.
Use a URL that PDFCrowd can reach. Ensure $request->fullUrl() uses your public address,
with the appropriate
trusted-host and
proxy settings.
The separate request does not inherit the user's Laravel session. For protected pages, configure cookies or HTTP authentication as appropriate, or use rendered HTML from the original request. If session blocking makes that GET wait for the POST to finish, use the rendered-HTML approach.
Generate a PDF from a template
You can also generate a PDF directly from a template and application data. Use an existing Blade template or a separate template designed for the document.
Place this function in a helper file that your Laravel application already loads. It renders the supplied view and returns the PDF as a binary string, using the same asset configuration as the route example:
function renderPdf(string $viewName, array $context): string { $context['pdfBaseUrl'] = config('services.pdfcrowd.base_url'); $html = view($viewName, $context)->render(); $client = new \Pdfcrowd\HtmlToPdfClient('demo', 'demo'); $client->setContentViewportWidth('balanced'); return $client->convertString($html); }
For example, given a $document, call it from a route or controller:
$pdf = renderPdf('documents.detail', ['document' => $document]); // PDF bytes
Pass all data the template needs in $context. Use the resulting bytes for a download,
storage, or email. If rendering or conversion fails, the caller receives the exception.
Outside a web request, call the helper from an Artisan command or other code that has initialized Laravel. Use a template that does not depend on request or session data.
For more conversion inputs and PDF settings, see the PHP examples and API reference.