Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Guzzle cannot create a PDF by itself. It is a PHP HTTP client: use it to fetch HTML or call a remote conversion service, then pass that input to a PDF renderer such as Dompdf, tc-lib-pdf, or a wkhtmltox-based converter. “Full-height” must also be defined: you may need one unusually tall page, or normal pages that continue across automatic page breaks. The implementation, settings, and testing differ.

What “full-height PDF” means

Before writing code, choose the output behavior. A PDF document can contain:

  • One custom-height page: the page is tall enough for a known, finite document, such as a receipt, dashboard, or poster.
  • Normal multipage flow: long HTML continues onto additional pages with headers, margins, and page breaks.

These are not interchangeable. A very tall single page can become awkward to view, print, or share. Multipage output is usually the better choice for reports whose length is not known in advance.

Understand Guzzle’s role

Guzzle sends HTTP requests and exposes the responses. It does not lay out HTML, calculate page dimensions, or emit PDF bytes. In a typical pipeline:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  1. Guzzle requests HTML from a URL or an API.
  2. A renderer loads that HTML and applies its supported CSS and print rules.
  3. The renderer returns PDF bytes, which your PHP application saves or streams to a browser.

If a remote service performs conversion, Guzzle instead uploads the HTML and receives a PDF response. Keep the transport and rendering responsibilities separate when diagnosing failures.

Recommended in-process route: Guzzle plus Dompdf

Dompdf’s documented sequence is to load HTML, optionally select paper size and orientation, render, then obtain the bytes or stream a download. The following complete example fetches a page with Guzzle and writes a PDF file. Install the packages with Composer first:

composer require guzzlehttp/guzzle dompdf/dompdf

Save this as a command-line script or adapt the final response section to your framework:

<?php
require __DIR__ . '/vendor/autoload.php';

use DompdfDompdf;
use DompdfOptions;
use GuzzleHttpClient;
use GuzzleHttpExceptionGuzzleException;

$url = 'https://example.com/report';

$http = new Client([
    'timeout' => 30,
    'connect_timeout' => 10,
    'allow_redirects' => true,
    'http_errors' => true,
    'headers' => ['User-Agent' => 'PDF generator/1.0'],
]);

try {
    $response = $http->request('GET', $url);
    $html = (string) $response->getBody();
} catch (GuzzleException $e) {
    http_response_code(502);
    exit('Could not fetch source HTML: ' . $e->getMessage());
}

$options = new Options();
$options->set('isRemoteEnabled', true); // Needed only when the HTML loads remote assets.
$options->set('defaultFont', 'DejaVu Sans');

$dompdf = new Dompdf($options);
$dompdf->loadHtml($html, 'UTF-8');

// Use a standard page for normal flow. See the custom-size example below for one tall page.
$dompdf->setPaper('A4', 'portrait');
$dompdf->render();

$pdfBytes = $dompdf->output();
file_put_contents(__DIR__ . '/report.pdf', $pdfBytes);

echo "Wrote report.pdfn";

For an HTTP endpoint, replace file_put_contents with a response having Content-Type: application/pdf and a suitable Content-Disposition. Dompdf also provides a stream operation for sending a download directly.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Creating one deliberately tall page

Only choose a single tall page when its content length is bounded and that presentation is useful. Dompdf accepts a paper size as a named format or a custom array; the exact array units and coordinate order depend on the Dompdf version you installed, so verify them against that version’s API before deploying. Do not guess a height from the browser viewport.

A conversion engine based on PHP’s wkhtmltox extension exposes explicit size.width, size.height, orientation, and margin settings. Its documented default height is 297 mm. Set a height intentionally in the units accepted by your installed extension, for example:

// Illustrative wkhtmltox settings; confirm the extension's version-specific API.
$settings = [
    'size.width' => '210mm',
    'size.height' => '600mm',
    'orientation' => 'Portrait',
    'margin.top' => '10mm',
    'margin.right' => '10mm',
    'margin.bottom' => '10mm',
    'margin.left' => '10mm',
];

There is no universal, renderer-independent recipe for measuring arbitrary HTML and selecting an exact content height. Fonts, images, web fonts, asynchronous content, and CSS all change the rendered length. If the content can grow, use page flow instead of repeatedly increasing a guessed height.

Multipage output for long documents

With Dompdf, keep a standard paper size and use print CSS to control breaks:

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
<style>
@page { margin: 16mm 14mm; }
.report-section { break-inside: avoid; }
.page-break { break-before: page; }
header { position: running(report-header); }
</style>

Use a renderer whose HTML engine supports the CSS your document actually uses. tc-lib-pdf documents automatic page and region breaks, custom page sizes, and controls for content spanning pages. Its HTML/CSS renderer does not implement CSS flexbox or grid, so a responsive web page that relies on those features may need a print-specific layout with tables, blocks, and explicit widths. Do not assume that a browser-perfect page will look identical in a PHP renderer.

Fetching HTML safely with Guzzle

Authenticate and send headers

Private source pages may require an authorization header or cookie. Keep credentials outside source control and pass only what the origin requires:

$response = $http->request('GET', $url, [
    'headers' => [
        'Authorization' => 'Bearer ' . getenv('REPORT_TOKEN'),
        'Accept' => 'text/html',
    ],
]);

Check status and content

With http_errors enabled, Guzzle throws for HTTP error responses. Even a successful status can return a login page, bot challenge, or an empty shell. Inspect the final URL, content type, and a marker in the HTML before rendering:

$type = $response->getHeaderLine('Content-Type');
if (stripos($type, 'text/html') === false || strpos($html, '<main') === false) {
    throw new RuntimeException('Unexpected source response');
}

Dynamic pages

Guzzle downloads the server response; it does not execute JavaScript. If the report is assembled in the browser, request a server-rendered endpoint, call the site’s data API and build print HTML yourself, or use a browser-capable conversion service. Increasing Guzzle’s timeout cannot make JavaScript run.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Renderer and layout choices

Requirement Better fit Important limitation
One bounded, custom-height page A renderer with explicit page dimensions, such as wkhtmltox settings You must choose units and a height; arbitrary HTML has no universal exact-height calculation.
Long report with automatic breaks Dompdf or tc-lib-pdf in normal page flow CSS support differs; test page breaks, fonts, and images.
Modern flexbox/grid layout An engine that explicitly supports the required CSS tc-lib-pdf documents no flexbox or grid support, so simplify the print layout or choose another engine.
Remote conversion Guzzle calling the service API Guzzle transports the request; the service performs rendering and may have its own limits.

Performance, reliability, and cost considerations

  • Bound both connection and total request timeouts. A slow origin should fail predictably rather than consume a PHP worker indefinitely.
  • Cache source HTML or generated PDFs when the document is immutable. Avoid re-rendering the same report for every download.
  • Large images and embedded fonts increase memory use. Resize images for print, remove unused assets, and avoid embedding data that the PDF does not need.
  • Use a queue for large documents or high volume. Keep the web request short and let a worker write the PDF, then return a download URL.
  • Record the renderer and package versions, paper size, orientation, margins, and source URL with each job. Reproducibility matters when a library update changes CSS behavior.
  • There are no universal performance figures established for these libraries here; benchmark your own templates and hosting limits.

Common failures and fixes

“The PDF is blank”

Log the fetched HTML before rendering. A redirect to authentication, a bot response, an empty JavaScript shell, or malformed markup can all produce a blank result. Confirm the response status, final URL, content type, and a known content marker.

“Images or CSS are missing”

Use absolute, reachable URLs; enable remote assets only when required; and ensure the PHP process can resolve and access those hosts. Local filesystem paths and browser-only relative paths often fail in a server worker.

“The page is cut off”

You likely selected a single page that is shorter than the rendered content. Switch to a standard paper size and multipage flow, or measure a bounded template and set a deliberately larger custom height in the renderer’s documented units.

“The layout differs from Chrome”

Check the renderer’s CSS support. Replace unsupported flexbox/grid rules with print-specific blocks or tables, provide explicit widths, and add page-break rules. Browser DevTools screenshots are not a reliable prediction of a server renderer’s output.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

“Guzzle times out”

Separate connection and total timeouts, verify DNS and TLS from the server, and test the URL without the PDF step. For JavaScript-heavy pages, use a server-rendered source or a browser-capable conversion path.

“Memory is exhausted”

Reduce image dimensions, avoid loading unnecessary remote assets, split a huge report into jobs, and raise the worker’s memory limit only after reducing the document’s actual requirements.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If your goal is a clean screenshot or PDF of a URL rather than an in-process PHP renderer, ScreenshotNeo provides a website screenshot API and MCP server. It accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be disabled. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP tools—take_screenshot, get_page_info, and capture_pdf—work with Claude, Cursor, and other MCP clients.

One-call cURL example (see the ScreenshotNeo documentation for all options):

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

The same request in PHP, Python, and Node.js:

<?php
$client = new GuzzleHttpClient();
$response = $client->get('https://api.screenshotneo.com/v1/shot', [
    'query' => ['access_key' => 'YOUR_API_KEY', 'url' => 'https://stripe.com'],
    'timeout' => 90,
]);
file_put_contents('shot.webp', $response->getBody()->getContents());
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

ScreenshotNeo also supports full-page capture with lazy images loaded, element selectors, dark mode, device presets, custom viewports and retina scale, PDF paper settings and page ranges, HTML/CSS input, custom JavaScript, waits, request blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, configurable caching, signed links, asynchronous webhooks, bulk capture of 100 URLs per call, a usage API, and an OpenAPI specification. Its parameter names are compatible with those used by other screenshot APIs, which can simplify migration.

Plans include 1,000 screenshots per month free with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.

FAQ

Can Guzzle render a PDF from HTML?

No. Guzzle retrieves or sends data; a PDF renderer or conversion service must perform layout and produce the PDF.

Should every long document use one tall page?

No. Use one custom-height page only for bounded content where that format is intentional. Otherwise use ordinary pages with automatic breaks.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Why does a browser layout fail in a PHP PDF library?

Server renderers implement different subsets of HTML and CSS. Unsupported features, including flexbox or grid in tc-lib-pdf’s documented renderer, require a simpler print layout or another engine.

Frequently Asked Questions

Can Guzzle render a PDF from HTML?

No. Guzzle retrieves or sends data; a PDF renderer or conversion service must perform layout and produce the PDF.

Should every long document use one tall page?

No. Use one custom-height page only for bounded content where that format is intentional. Otherwise use ordinary pages with automatic breaks.

Why does a browser layout fail in a PHP PDF library?

Server renderers implement different subsets of HTML and CSS. Unsupported features, including flexbox or grid in tc-lib-pdf’s documented renderer, require a simpler print layout or another engine.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The Bottom Line

Use Guzzle for transport and a dedicated renderer for PDF generation. Choose a custom tall page only when its height is bounded and intentional; for variable-length content, standard multipage flow is safer and easier to maintain.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.