Screenshot, created by Steve Bauman, captures HTML, Blade views, and web pages as PNG, JPEG, or PDF files. Its default driver launches and controls Chrome from PHP, without requiring Node.js or Puppeteer. Captures can be saved locally or stored on any configured Laravel filesystem disk.
Capture views and web pages
Pass your content to html(), view(), or url(). A learning platform could generate an image of a course completion certificate for a learner to share. This example assumes a certificates.show Blade view and a $certificate model:
use DirectoryTree\Screenshot\Facades\Screenshot; Screenshot::view('certificates.show', data: ['certificate' => $certificate]) ->size(width: 1440, height: 900) ->jpeg(quality: 85) ->store(path: "certificates/{$certificate->id}/preview.jpg", disk: 's3');
PNG is the default. Use jpeg() or pdf() to change the format; changing the filename extension won't do it.
JavaScript is disabled by default. For a screenshot of a public product page that uses JavaScript, enable it with javascript(). Here, $product->public_url contains the page's absolute HTTP or HTTPS URL:
use DirectoryTree\Screenshot\Facades\Screenshot; Screenshot::url($product->public_url) ->javascript() ->size(width: 1280, height: 720) ->png() ->viewport() ->save(storage_path("app/product-{$product->id}-page.png"));
Screenshot waits for the page's load event. If your page fetches data or renders a chart after that event, the capture may happen before it finishes. For HTML and Blade views, use absolute asset URLs or a <base href="..."> so Chrome can load stylesheets and images.
Use size() to set the viewport Chrome uses to lay out the page. By default, images capture the full page, cropped to a maximum width of 2048 pixels and height of 10000 pixels. The viewport() call above captures only the visible viewport, within those limits. We've also covered Spatie's Laravel Screenshot for capturing web pages in Laravel.
Element captures and PDFs
Call element() with a CSS selector before selecting the output format. If the certificate page includes navigation or download buttons, wrap the certificate itself in #certificate to export just that element:
use DirectoryTree\Screenshot\Enums\PaperSize;use DirectoryTree\Screenshot\Facades\Screenshot; $source = Screenshot::view('certificates.show', ['certificate' => $certificate]) ->size(1440, 900) ->element('#certificate'); $source->png()->store(path: "certificates/{$certificate->id}/certificate.png", disk: 's3'); $source->pdf() ->paper(PaperSize::A4) ->landscape() ->store(path: "certificates/{$certificate->id}/certificate.pdf", disk: 's3');
Image captures crop to the element's bounds. For PDFs, Chrome moves the element into the document body and prints it with the document's stylesheets. CSS selectors that depend on removed wrappers may need adjustment.
PDFs default to A4 portrait with 10 mm margins and printed backgrounds. Paper dimensions and margins are configurable. If your stylesheet defines an @page size, use preferCssPageSize() to give it precedence. For more on PDF rendering drivers, see our coverage of Spatie's Laravel PDF v2.
Save and reuse captures
To save a certificate preview locally and upload the same image, keep the result of capture():
use DirectoryTree\Screenshot\Facades\Screenshot; $image = Screenshot::view('certificates.show', ['certificate' => $certificate]) ->size(1440, 900) ->element('#certificate') ->png() ->capture(); $image->save(storage_path("app/certificate-{$certificate->id}.png"));$image->store( path: "certificates/{$certificate->id}/certificate.png", disk: 's3', options: ['visibility' => 'private'],);
Calling save() or store() directly on a source starts a new capture each time. The result object holds the captured bytes, so both writes above use the same image.
The parent directory of the file passed to save() must already exist. Omit disk from store() to use Laravel's default disk. Image and PDF results also provide raw contents, Base64 data, and data URIs.
Installation
Screenshot supports Laravel 12 with PHP 8.2 or later, and Laravel 13 with PHP 8.3 or later:
composer require directorytree/screenshotphp artisan screenshot:install
The service provider registers automatically. The install command downloads Chrome for Testing if the package has no existing installation. Downloads require PHP's ZIP extension. Run php artisan screenshot:install --update to check for a newer stable version.
To use an existing Chrome or Chromium executable, set SCREENSHOT_CHROME_PATH to its path. Your server also needs Chrome's system libraries and the fonts your pages use.
For remote rendering, the package supports Gotenberg 8.38 or later. With local Chrome, named sockets let workers share a browser when they run on the same host under the same OS user and use the same private socket directory. Shared browsers also share cookies and storage.
In tests, Screenshot::fake() records captures without starting Chrome. Pair it with Storage::fake() when testing uploads: the screenshot fake still writes files.
See the Screenshot repository for configuration, driver options, and testing examples.