To convert HTML to a PNG in Laravel, render that HTML in a real browser and save the resulting screenshot. Spatie Browsershot is the direct option: Browsershot::html($html)->save($pathToImage). For a page already hosted at a URL, use Browsershot::url($url). Browsershot controls headless Chrome through Puppeteer, so modern CSS, web fonts, and JavaScript can be rendered instead of treated as plain text.
This guide covers local rendering, the Laravel Screenshot facade, hosted rendering, sizing and readiness controls, deployment requirements, failure diagnosis, and an API alternative when you do not want to maintain a browser installation.
Choose the rendering route
| Route | Input | Where Chrome runs | Best fit |
|---|---|---|---|
| Spatie Browsershot | HTML string or URL | Your Laravel host through Puppeteer | Direct control when Node.js and Chrome can be installed |
| Spatie Laravel Screenshot | Laravel-oriented screenshot configuration | Browsershot by default; Cloudflare driver is also available | Facade-style integration, documented defaults, and queueing workflows |
| Laravel Screenshot with Cloudflare driver | Laravel Screenshot requests | Cloudflare Browser Rendering | Deployments where running local Node.js or a Chrome binary is undesirable |
The official package documentation does not establish a universal winner for speed, cost, memory use, or throughput. Those results depend on your page, host, concurrency, and service configuration.
Convert an HTML string with Browsershot
Use this when Laravel has generated the markup itself—for example, an invoice, certificate, report, or social card.
Recommended Free Tools
#1 Best Overall
- CRISP CLARITY: This 23.8″ Philips V line monitor delivers crisp Full HD 1920x1080 visuals. Enjoy movies, shows and videos with remarkable detail
- INCREDIBLE CONTRAST: The VA panel produces brighter whites and deeper blacks. You get true-to-life images and more gradients with 16.7 million colors
- THE PERFECT VIEW: The 178/178 degree extra wide viewing angle prevents the shifting of colors when viewed from an offset angle, so you always get consistent colors
- WORK SEAMLESSLY: This sleek monitor is virtually bezel-free on three sides, so the screen looks even bigger for the viewer. This minimalistic design also allows for seamless multi-monitor setups that enhance your workflow and boost productivity
- A BETTER READING EXPERIENCE: For busy office workers, EasyRead mode provides a more paper-like experience for when viewing lengthy documents
1. Install and prepare the browser runtime
Browsershot uses Puppeteer to control headless Google Chrome. Install the package and its browser dependencies according to the current Browsershot installation documentation, then verify that your deployment can execute Node.js, Puppeteer, and Chrome. The exact commands vary with the Browsershot and Laravel versions you select, so keep the package’s setup instructions alongside your deployment configuration.
2. Save a PNG from HTML
<?php
namespace AppHttpControllers;
use IlluminateHttpResponse;
use SpatieBrowsershotBrowsershot;
class ReportImageController extends Controller
{
public function __invoke(): Response
{
$html = view('reports.card', [
'title' => 'Monthly report',
'total' => '$12,480',
])->render();
$path = storage_path('app/public/reports/monthly-report.png');
Browsershot::html($html)
->save($path);
return response()->download($path, 'monthly-report.png', [
'Content-Type' => 'image/png',
]);
}
}
PNG is Browsershot’s documented default image type. A filename ending in .png makes the intent clear; do not call an image “PNG” if you configured another format.
3. Render a URL instead
use SpatieBrowsershotBrowsershot;
$path = storage_path('app/public/pages/home.png');
Browsershot::url('https://example.com')
->save($path);
url() asks Chrome to navigate to the address, while html() supplies markup directly. A URL is useful when the page already has its own routes, assets, authentication flow, and JavaScript.
Make the capture deterministic
A browser screenshot is affected by viewport, device scale, fonts, asynchronous requests, and page state. Set the values that matter to your output rather than relying on defaults.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Viewport and full-page output
$shot = Browsershot::html($html)
->windowSize(1200, 800)
->deviceScaleFactor(2)
->fullPage()
->save($path);
Use a fixed viewport for repeatable layouts. A device scale factor changes pixel density; it is not the same as changing the CSS viewport. Full-page capture includes content beyond the initial viewport, which is useful for long reports but can create very tall images.
Rank #2
- CRISP CLARITY: This 22 inch class (21.5″ viewable) Philips V line monitor delivers crisp Full HD 1920x1080 visuals. Enjoy movies, shows and videos with remarkable detail
- 100HZ FAST REFRESH RATE: 100Hz brings your favorite movies and video games to life. Stream, binge, and play effortlessly
- SMOOTH ACTION WITH ADAPTIVE-SYNC: Adaptive-Sync technology ensures fluid action sequences and rapid response time. Every frame will be rendered smoothly with crystal clarity and without stutter
- INCREDIBLE CONTRAST: The VA panel produces brighter whites and deeper blacks. You get true-to-life images and more gradients with 16.7 million colors
- THE PERFECT VIEW: The 178/178 degree extra wide viewing angle prevents the shifting of colors when viewed from an offset angle, so you always get consistent colors
Wait for dynamic content
Capture only after the content you need exists. Browsershot documents delay-based waits and waits for selectors or functions. A selector is usually more robust than an arbitrary sleep:
Browsershot::url($url)
->waitForSelector('.report-ready')
->save($path);
Some Laravel Screenshot configurations document waiting for network idle as a default. Network idle is not always a reliable readiness signal: analytics, WebSockets, polling, or advertisements can keep a page active indefinitely. Prefer a page-specific ready marker when you control the HTML. Use a short delay only when the page has a known animation or late font transition.
Backgrounds, CSS, and assets
- Ensure stylesheets, images, and fonts are reachable from the browser process. Relative URLs in an HTML string may not resolve unless you provide a suitable base URL or use absolute asset URLs.
- Keep important styles inline or hosted at an address accessible from the rendering environment.
- Wait for a meaningful image or component selector when lazy-loaded content is required.
- Set background behavior explicitly when a transparent or colored background is part of the design.
Use Laravel Screenshot for a facade workflow
Spatie Laravel Screenshot adds a Laravel-focused facade and configuration layer around screenshot generation. Its overview documents defaults of 1280×800, a 2× device scale, PNG output, and waiting for network idle; these are package defaults, not guarantees after you override configuration.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →The package uses a Browsershot driver by default and documents configurable screenshot options and queueing examples. This can keep controllers small and centralize dimensions, output format, and driver settings. Install the package and its required driver dependencies using its current installation documentation, then configure the driver in the package’s configuration file.
When the Cloudflare driver fits
The Laravel Screenshot installation documentation describes a Cloudflare Browser Rendering driver that does not require local Node.js or a Chrome binary. It can suit a container or serverless deployment where installing and maintaining a browser is impractical. It is still a hosted rendering dependency: configure the required Cloudflare credentials and service settings, and evaluate its behavior against your workload. The available documentation does not establish that it is cheaper or faster than local Browsershot.
Rank #3
- Clear visuals. Fluid motion: A 144Hz refresh rate and 1ms MPRT deliver smooth, tear‑free motion across work, gaming, and streaming for clearer, more fluid viewing.
- Eye comfort: TÜV Rheinland 3‑star* certification reduces harmful blue light while preserving stunning color quality without compromise. *TÜV Rheinland 3-star eye comfort certification.
- Wide viewing angle: Get consistent views across a wide 178° /178° viewing angle.
- In-Plane Switching (IPS): See excellent color accuracy and consistency across wide viewing angles with In-plane Switching (IPS) technology.
- Ultra-thin bezels: Maximize your viewing experience with thin bezels.
Return, store, and secure the PNG
Stream or download it
For a one-off response, return the generated file with Laravel’s download or file response. For persistent assets, write to a disk and return a URL generated by your filesystem configuration. Use a non-public disk for private reports and authorize the route that triggers generation.
Avoid untrusted HTML risks
Rendering arbitrary user HTML executes it in a browser context. Sanitize user-provided markup, restrict remote resources, and do not pass attacker-controlled URLs to an internal browser that can reach private network addresses. Treat screenshots as generated files, not as a security boundary.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Repair Windows errors before they cause bigger problems3Scan for outdated or missing drivers - takes under a minuteQueue expensive work
Long pages, full-page captures, and font-heavy documents can exceed a web request’s time budget. Dispatch a queued job, write the PNG to storage, and notify the client when it is ready. Configure job timeouts and retries for your host; the package documentation does not prescribe a universal value.
Common failures and fixes
“Command not found” or browser launch errors
Cause: Node.js, Puppeteer, or Chrome is missing, or the process user cannot execute the binary.
Fix: Install the Browsershot dependencies in the same image or host that runs Laravel, set the documented executable paths when your environment requires them, and test as the web-worker user rather than only from an interactive shell.
The PNG is blank or missing fonts
Cause: Assets are unreachable, the capture occurs before rendering completes, or the font is not installed/loaded.
Fix: Inspect asset URLs from the browser environment, use absolute or correctly based URLs, wait for a ready selector, and make font loading part of that readiness condition.
Rank #4
- CURVED FOR ENHANCED ENGAGEMENT: An immersive viewing experience with a curved monitor that wraps more closely around your field of vision; It creates a wider view, enhancing depth perception and minimizing peripheral distraction
- SMOOTH PERFORMANCE FOR SEAMLESS CONTENT: Stay in the action when playing games, watching videos, or working on creative projects; The 100Hz refresh rate reduces lag and motion blur so you don't miss a thing in fast-paced moments¹
- MORE GAMING POWER: Gain the edge with optimizable game settings; Color and image contrast can be adjusted to see scenes more vividly and spot enemies hiding in the dark; Game Mode adjusts any game to fill the screen so you can view every detail²
- KEEP IT EASY ON THE EYES: Care for your eyes and stay comfortable, even during long sessions; Advanced eye comfort technology certified by TÜV reduces eye strain by minimizing blue light and reducing irritating screen flicker²
- INCREASED VERSATILITY: Connect to more; Plug devices straight into your monitor for increased flexibility, making your computing environment even more convenient
JavaScript content is absent
Cause: The screenshot is taken before the client-side app finishes mounting.
Fix: Add a deterministic ready element and wait for it. A network-idle wait may fail on pages with persistent requests.
Only the top of a long page appears
Cause: The default viewport screenshot was used.
Fix: Enable full-page capture, or capture a defined element/section when one very tall PNG is not practical.
Works locally but fails in production
Cause: Different OS libraries, sandbox permissions, environment variables, outbound network rules, or missing fonts.
Fix: Reproduce with the production container image, log the browser command and exit output, install required system libraries, and confirm that the queue/web user has write permission for the destination directory.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server. Send one request with a URL and receive PNG, JPEG, WebP, or PDF. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the page verdict and billing result in X-Page-Verdict and X-Billed headers.
For a Laravel application, call the API from a job or service class:
Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minutePC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11use IlluminateSupportFacadesHttp;
$response = Http::timeout(90)->get(
'https://api.screenshotneo.com/v1/shot',
[
'access_key' => config('services.screenshotneo.key'),
'url' => 'https://example.com',
]
)->throw();
file_put_contents(
storage_path('app/public/example.png'),
$response->body()
);
See the ScreenshotNeo documentation for the complete parameter list. Options include full-page capture with lazy images loaded, CSS-selector element capture, dark mode, 12 device presets or a custom viewport, retina scale, PDF paper settings, custom CSS and JavaScript, pre-capture clicks, hidden selectors, selector/delay/network-idle waits, request and resource blocking, headers, cookies, user agent, authorization, timezone, geolocation, transparent backgrounds, resizing, TTL caching, signed image links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, a usage API, and an OpenAPI specification. Existing parameter names used by other screenshot APIs also work, which can simplify migration.
Best Value
- 【INTEGRATED SPEAKERS】Whether you're at work or in the midst of an intense gaming session, our built-in speakers provide rich and seamless audio, all while keeping your desk clutter-free.
- 【EASY ON THE EYES】 Protect your eyes and enhance your comfort with Blue-Light Shift technology. This feature reduces harmful blue light emissions from your screen, helping to alleviate eye strain during long hours of use and promoting healthier viewing habits.
- 【WIDEN YOUR PERSPECTIVE】Our sleek minimal bezel design ensures undivided attention. The nearly bezel-free display seamlessly connects in a dual monitor arrangement, delivering an unobstructed view that lets you focus on more at once, completely distraction-free.
The MCP server exposes take_screenshot, get_page_info, and capture_pdf tools to Claude, Cursor, and other MCP clients. Plans are Free for 1,000 shots per month with no card, then Starter $5 for 3,000, Growth $15 for 15,000, Pro $39 for 60,000, Scale $99 for 250,000, and Business $249 for 1,000,000; yearly billing provides two months free, and every feature is included on every plan.
Use the documented one-call examples when a hosted renderer is preferable:
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}`);
Create a free ScreenshotNeo account for 1,000 screenshots a month without adding a card.
Operational checklist
- Choose HTML input or a URL deliberately.
- Install and test the browser runtime as the production worker user, or select a hosted driver.
- Set viewport, device scale, format, and full-page behavior explicitly.
- Wait for a page-specific ready selector when content is asynchronous.
- Verify fonts, images, and external stylesheets from the renderer’s network.
- Queue long captures and write files to a controlled disk.
- Sanitize untrusted HTML and restrict untrusted navigation targets.
- Log failures and, where applicable, inspect verdict and billing headers from the API.
Frequently Asked Questions
Can I convert a Blade view directly?
Yes. Render the view with view('name', $data)->render(), pass the resulting string to Browsershot::html(), and save to a path ending in .png.
Is network idle always the best wait condition?
No. Pages with polling, WebSockets, or analytics may never become idle. A selector that your page adds after rendering is usually more deterministic.
Does Laravel itself render CSS into PNG?
No. The documented approaches use a browser renderer: Browsershot controls headless Chrome, while the Cloudflare driver delegates rendering to Cloudflare Browser Rendering.
Can I use this for private pages?
Yes, with the appropriate local browser setup or authenticated headers/cookies in a hosted renderer. Keep credentials secret and authorize the Laravel endpoint that creates the image.
Free tools Windows power users keep installed
One-click scans. No signup required.
Quick Recap
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.




