Capture a Website Screenshot in PHP with Laravel Dusk
Use Laravel Dusk to capture a full-page or element screenshot in a browser test, find the saved files, and troubleshoot ChromeDriver setup.
In a Laravel Dusk browser test, call $browser->screenshot('homepage'). Laravel documents the output directory as tests/Browser/screenshots. Use screenshotElement('#selector', 'element') for one element, or responsiveScreenshots('homepage') for a series of captures at different breakpoints.
1. Install and configure Laravel Dusk
Dusk automates a real browser for Laravel browser tests. The current Laravel 13.x documentation describes a default setup using Google Chrome and a standalone ChromeDriver.
- Add Dusk as a development dependency:
composer require laravel/dusk --dev. - Install its scaffolding and driver:
php artisan dusk:install. - Set
APP_URLin your environment to the application URL that the browser should visit. - Ensure Chrome or Chromium is available to the test environment. If you use Laravel Sail, follow Laravel’s Sail-specific Dusk configuration.
The install command creates the tests/Browser directory and an example test, and installs a ChromeDriver binary for the operating system. Keep Chrome or Chromium and its driver compatible; use the detection command below when updating the browser.
2. Capture a screenshot in a Dusk test
Put the capture in a browser test after navigating to the page you want to inspect:
<?php
namespace Tests\Browser;
use Laravel\Dusk\Browser;
use Tests\DuskTestCase;
class HomepageScreenshotTest extends DuskTestCase
{
public function test_homepage_screenshot(): void
{
$this->browse(function (Browser $browser): void {
$browser->visit('/')
->screenshot('homepage');
});
}
}
Run the Dusk suite with php artisan dusk. Laravel documents screenshots under tests/Browser/screenshots. Use a descriptive filename to make artifacts easy to identify. The documented API accepts a filename; check your installed Dusk version if your workflow depends on a particular extension or overwrite behavior.
3. Choose the capture scope
| Need | Dusk method | Example |
|---|---|---|
| Capture the page in the browser | screenshot |
$browser->screenshot('homepage') |
| Capture one selected element | screenshotElement |
$browser->screenshotElement('#pricing', 'pricing') |
| Capture a responsive series | responsiveScreenshots |
$browser->responsiveScreenshots('homepage') |
For an element capture, replace #pricing with a CSS selector that identifies an element present on the page. The documentation describes responsive captures at various breakpoints but does not specify their values in the material used for this guide; do not assume a particular set without checking the Dusk version in your project.
4. Driver setup and failure screenshots
If the browser and driver versions do not match, install the driver for the detected Chrome or Chromium version:
php artisan dusk:chrome-driver --detect
Dusk’s default setup uses standalone ChromeDriver. You can also run your own Selenium server and configure a Selenium-compatible driver when that better fits your environment. Verify the actual browser and driver versions in the environment running the tests instead of copying a version number from an older guide.
Failure screenshots are separate from an explicit call to screenshot(): when a Dusk test fails, Dusk automatically resizes the browser to fit the content before taking its screenshot. Call disableFitOnFailure if you need to disable that behavior.
5. Troubleshooting
| Symptom | Likely cause | What to check or do |
|---|---|---|
| ChromeDriver cannot start Chrome | Chrome or Chromium is missing, or the driver and browser are incompatible. | Confirm the browser is installed in the test environment, then run php artisan dusk:chrome-driver --detect and verify both versions. |
| The browser opens the wrong host or cannot reach the app | APP_URL does not match the application address available to the browser. |
Set APP_URL to the URL reachable from the Dusk browser. In containerized setups, check the Sail Dusk configuration and network address. |
| Element screenshot fails or captures the wrong thing | The selector is invalid, or the target element is absent on the current page. | Visit the intended route first and use a CSS selector that matches the element in that rendered page. |
| Failure screenshot dimensions differ from the test window | Dusk fits the browser to the content before its automatic failure capture. | Use disableFitOnFailure to turn off that failure-only behavior if needed. Explicit screenshots are a separate operation. |
| Expected breakpoint files or names are unclear | The documentation describes a responsive series but the expected breakpoint values are not specified here. | Inspect behavior for the Dusk version installed in the project and avoid relying on undocumented names or defaults. |
6. Performance, reliability, and cost
Dusk captures run through browser automation, so they require a working browser and compatible driver in the test environment. Keep captures focused on the pages and states you need to verify, and use stable, meaningful filenames for artifacts. Browser or driver changes can affect reliability; check compatibility as part of environment updates.
The research source does not provide timing or cost benchmarks for Dusk, so no performance figures are claimed here. Dusk is the direct choice when screenshots belong in Laravel browser tests. Laravel 13.x documentation currently recommends Pest for new browser testing projects; Dusk remains useful for existing Dusk suites and teams that have selected it.
Or skip the browser setup
If you need a screenshot from a URL without maintaining a Dusk browser setup, ScreenshotNeo provides a website screenshot API and MCP server. See the API documentation.
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://stripe.com \
-o shot.webp
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}`);
Replace YOUR_API_KEY with your key and change the target URL as needed. ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before the capture. Bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots, and 1,000 screenshots per month are free with no card; paid plans start at $5 for 3,000. Sign up for free and get 1,000 screenshots a month with no card.
FAQ
Where does Laravel Dusk save screenshots?
Laravel documents the directory as tests/Browser/screenshots.
Can Dusk capture just part of a page?
Yes. Use screenshotElement with a CSS selector and a filename.
Does Dusk take a screenshot when a test fails?
Dusk takes failure screenshots automatically. It fits the browser to the content first unless failure fitting has been disabled.
What should a new Laravel browser-testing project use?
Laravel’s current 13.x documentation recommends Pest for new projects. This guide covers Dusk for teams using Dusk or maintaining an existing Dusk suite.
Source
Laravel 13.x Dusk documentation covers installation, ChromeDriver, screenshots, and Laravel’s current browser-testing recommendation.


