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

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Short answer: a JavaScript alert() does not automatically send its message or the page’s current URL to PHP. For a dependable screenshot, have the page expose a readiness signal—such as a DOM element or, if your installed build supports it, a window.status value—then invoke wkhtmltoimage from PHP and check its exit code. If you need a URL or value shown in the alert, send it explicitly from the page to a server endpoint; do not treat the dialog itself as a PHP-readable result.

First decide what “the URL after the alert” means

There are three different values people may mean by this question. They need different handling, and none is reliably obtained merely by waiting for a dialog to appear.

What you need Where to get it What PHP receives
The address of the page currently open in the browser renderer Read location.href in page JavaScript and report it explicitly if PHP needs it. A value your page sends to a server endpoint, or a value supplied separately to the PHP job.
A URL or other value printed in the alert text Change the page code that creates the alert so it sends that value through an agreed channel. The value in the request or job data, not a value automatically extracted from the dialog.
A signal that the page is ready to capture Expose a readiness marker in the page, for example a known DOM element or a supported window.status value. PHP can ask the renderer to wait for the agreed marker, subject to the installed build’s behavior.

A browser alert is a user-interface dialog, not a result channel between a rendered page and the PHP process that launched the renderer. Depending on the browser engine and page behavior, an alert can also interrupt JavaScript. If the page is under your control, avoid using an alert as the signal that rendering is complete. If you cannot change it, test the exact page and renderer build rather than assuming the alert will be observed or handled as you expect.

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

Make the page report its value and readiness explicitly

If PHP needs the current page URL

In page code, location.href identifies the current document URL. It may change after redirects or client-side navigation, so read it at the point in the page flow that matters. If PHP must store or act on that value, send it to a server endpoint you control. The following illustrates the client-side shape; replace the endpoint and authentication approach with your application’s own implementation.

const currentUrl = location.href;

await fetch('/capture-ready', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ url: currentUrl, ready: true })
});

Do not treat a URL submitted by a browser as trusted just because your own page sent it. Validate the expected host and scheme on the server, authenticate the request where appropriate, and apply your application’s normal authorization rules.

If a URL is currently only inside alert text

Change the code that creates the alert so it also sends the underlying value to your server or places it in an agreed, machine-readable location. For example, if the page has already computed resultUrl, use that variable for both the display and the request. Do not try to scrape text from a dialog as a substitute for an application interface: the renderer is not a PHP browser session that automatically returns dialog text to the caller.

If the alert means “the page is done”

Have the application mark the actual point at which the required work is complete. A readiness marker should be set after the data, navigation, or UI state needed in the image is ready—not merely when the initial document loads. A marker might be a DOM element that appears only after rendering, or a status value assigned by page JavaScript. This turns an informal event into a condition the capture job can test.

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

Check what your wkhtmltoimage build can wait for

The wkhtmltoimage command reference documents JavaScript as enabled by default, with options including --javascript-delay, --run-script, and --window-status. The project’s settings reference distinguishes image settings from page-loading settings and notes that some settings do not affect wkhtmltoimage. Verify that an option applies to the image executable you run; do not assume a wkhtmltopdf option has the same effect.

Behavior is version- and build-sensitive. A historical project issue reports that --javascript-delay and --window-status were ignored in wkhtmltoimage 0.12.2 and points to a fix associated with milestone 0.12.2.1. That is evidence that older behavior varied, not proof that every current build works—or fails—the same way. Check the binary installed on the server and reproduce the wait against that exact executable and target page.

  1. Identify the executable PHP will run. In the same environment and account context as the web application, inspect the installed wkhtmltoimage version and its help output. A shell available to you locally may use a different binary from PHP’s service environment.
  2. Confirm JavaScript is enabled. The CLI documents JavaScript as enabled by default, but check that your command or configuration has not disabled it.
  3. Try the actual readiness condition. Test a minimal page whose JavaScript sets the status value or DOM marker only when the required content is ready. Do not infer success from a screenshot of a page that happens to load quickly.
  4. Check the resulting file and process status. A command returning does not prove the image contains the intended final state. Inspect the output and capture the process exit code in PHP.

Use a bounded wait appropriate to your application. A fixed delay may work as a fallback when the page cannot expose a better condition, but it can waste time on fast loads and still be too short for slow ones. A status wait is more meaningful only if your installed build honors it and the page actually sets the expected value.

Call wkhtmltoimage safely from PHP

PHP’s exec() can collect command output and provide the process result code. Escape every user-controlled shell argument; never interpolate an incoming URL or output path directly into a shell command. This example uses escapeshellarg() for each argument, captures output and status, and treats a nonzero exit code as failure.

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.
<?php
$url = 'https://example.com/page';       // Validate before this point.
$outputPath = '/var/tmp/page-shot.png';  // Use a controlled writable directory.
$readyStatus = 'capture-ready';          // Must match the page's signal.

$command = implode(' ', [
    'wkhtmltoimage',
    '--enable-javascript',
    '--window-status', escapeshellarg($readyStatus),
    escapeshellarg($url),
    escapeshellarg($outputPath),
]);

$lines = [];
$exitCode = 0;
exec($command, $lines, $exitCode);

if ($exitCode !== 0) {
    error_log('wkhtmltoimage failed: ' . implode("n", $lines));
    throw new RuntimeException('Screenshot capture failed.');
}

if (!is_file($outputPath) || filesize($outputPath) === 0) {
    throw new RuntimeException('Screenshot output is missing or empty.');
}

// The image is available at $outputPath.
?>

The page must set window.status to the exact value passed to --window-status, and the installed executable must support that wait for image capture. For a delay-based test, replace the wait option with a bounded --javascript-delay value in milliseconds, for example --javascript-delay 1500. That number is an example, not a guarantee of readiness; measure the page’s actual completion condition and validate the result.

Keep command execution isolated from untrusted input. In a web app, a caller-controlled URL can create risks beyond shell injection, including requests from your server to internal services. Apply an allowlist or other strict URL policy, limit output destinations to a private controlled directory, and avoid returning raw command output or server paths to untrusted users. Set operational time limits at the job or process-management layer so a stuck renderer does not occupy a PHP worker indefinitely.

Use exec() when you need a reliable failure signal

shell_exec() returns command output as a string, but null can mean either that the command produced no output or that an error occurred. PHP’s manual recommends exec() when the process exit code is needed. For a capture workflow, the exit code, captured diagnostics, and a check that the expected output file exists and is non-empty provide a more useful failure path than treating any returned string as success.

Log enough information to diagnose failures—such as the exit code and sanitized renderer output—without logging secrets embedded in URLs, headers, or cookies. Avoid exposing internal filesystem paths in errors sent to a browser.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshoot the common failure modes

The screenshot is taken before the alert or final content appears

  • Likely cause: the command waits only for navigation or a short delay, while the page’s later JavaScript work is still running.
  • Fix: add an application-controlled readiness marker after the needed content is rendered, then validate the corresponding status or wait behavior against the installed binary.

The command waits forever or does not recognize the status

  • Likely cause: the page never sets the exact status value, or that build does not honor the wait option for wkhtmltoimage.
  • Fix: check spelling and timing in the page code, inspect the installed version and help output, and run a minimal reproduction. Use a bounded delay only as a tested fallback.

The alert appears, but PHP has no URL or message

  • Likely cause: the alert is a browser dialog; it does not automatically communicate its text or the current location to the PHP caller.
  • Fix: change the page code to send the URL/value explicitly, or pass the relevant value to the capture job through your application’s own validated input.

PHP reports success but the image is blank or incomplete

  • Likely cause: the renderer exited successfully without capturing the application state you expected, the wait condition was not effective, or the page failed to load its content.
  • Fix: check the actual output image, captured command output, target page behavior, and wait condition. Do not use exit status alone as proof that the screenshot is semantically correct.

PHP cannot find the command or write the output

  • Likely cause: the web service has a different PATH or permissions from your interactive shell, or the chosen output directory is not writable by the PHP process.
  • Fix: configure the executable path appropriate to the host, verify it as the service account, and choose a private directory that account can write to.

The page loads differently from your desktop browser

  • Likely cause: the legacy renderer’s engine or environment differs from the browser used to view the page; modern application behavior may not be reproduced identically.
  • Fix: test the specific page and build. If the page requires browser behavior this renderer cannot reliably provide, assess a browser-based screenshot service, including whether sending the page URL or data to a hosted provider is acceptable for your privacy, security, and budget requirements.

Or skip the browser setup

ScreenshotNeo offers a website screenshot API and MCP server for developers. A GET request can return a PNG, JPEG, WebP, or PDF. For a one-call image capture, use the API as documented at ScreenshotNeo’s 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

The call above uses Stripe as the example target; replace it with the URL you are authorized to capture. In contrast with running a renderer yourself, ScreenshotNeo accepts cookie or consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each of those steps can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and responses include X-Page-Verdict and X-Billed headers. It also provides an MCP server with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots.

Sign up for ScreenshotNeo’s free plan to get 1,000 screenshots a month with no card.

Frequently Asked Questions

Does a JavaScript alert prove that the page has finished loading?

No. It only indicates that page code reached the point where it invoked the alert; it does not guarantee that every image, request, or later UI update needed for your screenshot is complete.

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

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.