Urlbox API Integration in PHP for Indian Web Developers
Build a PHP website screenshot integration with Urlbox using signed render links or its JSON API. See runnable examples, capture options, security guidance, and costs.
To add website screenshots to a PHP application with Urlbox, install its urlbox-php Composer package, create a client with your API key and secret, generate a signed render URL on the server, and use that URL as an image source. For a server-to-server workflow, call Urlbox’s POST /v1/render/sync endpoint with JSON and a Bearer token, then download or store the returned render URL.
This guide covers both approaches, full-page and element captures, security, errors, performance, and cost planning for Indian developers. The integration steps are the same regardless of where your application runs; the available sources do not establish India-specific pricing, GST treatment, or payment options.
1. Choose a PHP integration pattern
| Pattern | Best for | What your PHP code receives |
|---|---|---|
| Signed render link | Displaying a screenshot in an HTML page with minimal server-side handling | A URL that can be used in an <img> element |
| JSON synchronous API | Backend workflows that need a render result as data | JSON containing a temporary renderUrl and size information |
These are distinct request flows. Signed links put the options in a query string and use a server-generated HMAC-SHA256 signature. The current API reference documents POST /v1/render/sync with the project secret as a Bearer token. Do not combine its authentication with the separate legacy /v1/render Post API instructions, which describe HTTP Basic authentication. See the [Urlbox API reference](https://urlbox.com/docs/api), [quickstart](https://urlbox.com/docs/quickstart), and [legacy Post API page](https://urlbox.com/docs/postapi).
2. Create credentials and install the PHP package
- Create or access a Urlbox project and obtain its API key and secret from the account settings.
- Keep both values on the server. Store them in environment variables or a secrets manager; never put the secret in browser JavaScript, a public repository, or a client-visible configuration file.
- Install the Composer package identified in the official PHP example:
composer require urlbox/urlbox-php
The official sample uses the Urlbox\\Screenshots\\Urlbox class. The reviewed documentation does not specify a minimum PHP version, a package version, or a Laravel compatibility matrix, so check the package metadata and your application’s supported runtime before deployment. See the [official PHP sample](https://urlbox.com/docs/examplecode/php).
3. Generate a signed render link in PHP
This example follows the documented Composer client flow. Set URLBOX_API_KEY and URLBOX_API_SECRET in the PHP process environment before running it. It prints an HTML image element, so it can also be adapted into a template variable.
<?php
require __DIR__ . '/vendor/autoload.php';
use Urlbox\\Screenshots\\Urlbox;
$apiKey = getenv('URLBOX_API_KEY');
$apiSecret = getenv('URLBOX_API_SECRET');
if (!$apiKey || !$apiSecret) {
throw new RuntimeException('Set URLBOX_API_KEY and URLBOX_API_SECRET.');
}
$urlbox = Urlbox::fromCredentials($apiKey, $apiSecret);
$options = [
'url' => 'https://example.com',
'width' => 1280,
'height' => 800,
'format' => 'png',
];
$signedUrl = $urlbox->generateSignedUrl($options);
echo '<img src="' . htmlspecialchars($signedUrl, ENT_QUOTES, 'UTF-8')
. '" alt="Screenshot of example.com">';
Replace the example URL with the page you are authorized to capture. The PHP sample documents setting the URL and optional dimensions, generating the signed link, and embedding it in an image element. Add only options supported by the live Urlbox documentation. Signing covers the query-string options; changing signed options after generation invalidates the signature. The [render links guide](https://urlbox.com/docs/render-links) describes the signed-link flow.
Use the generated URL in a PHP template
In an application, pass $signedUrl to the template layer and escape it in the HTML attribute context. Do not expose the project secret to create the signature in the browser. If the signed URL itself grants access to a render, treat it as a URL you should only share where intended.
4. Call the JSON synchronous API from PHP
Use this flow when the application needs a backend response containing the render location. The current API reference documents POST https://api.urlbox.com/v1/render/sync, JSON or form-encoded options, and Authorization: Bearer YOUR_URLBOX_SECRET. This complete PHP example uses cURL and decodes the JSON response.
<?php
$secret = getenv('URLBOX_API_SECRET');
if (!$secret) {
throw new RuntimeException('Set URLBOX_API_SECRET.');
}
$payload = [
'url' => 'https://example.com',
'width' => 1280,
'height' => 800,
'format' => 'png',
];
$ch = curl_init('https://api.urlbox.com/v1/render/sync');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($payload, JSON_THROW_ON_ERROR),
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $secret,
'Content-Type: application/json',
'Accept: application/json',
],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_TIMEOUT => 120,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($body === false) {
$message = curl_error($ch);
curl_close($ch);
throw new RuntimeException('Urlbox request failed: ' . $message);
}
curl_close($ch);
$data = json_decode($body, true, 512, JSON_THROW_ON_ERROR);
if ($status < 200 || $status >= 300) {
throw new RuntimeException('Urlbox returned HTTP ' . $status . ': ' . $body);
}
if (empty($data['renderUrl'])) {
throw new RuntimeException('Response did not include renderUrl.');
}
echo $data['renderUrl'] . PHP_EOL;
Use the endpoint-specific authentication and schema in the [current API reference](https://urlbox.com/docs/api). A successful synchronous response includes a temporary renderUrl and size information. The [quickstart](https://urlbox.com/docs/quickstart) says that render URLs expire after 30 days. Download the output promptly or configure storage when your application needs longer retention.
5. cURL, Python, and Node.js request examples
These examples show the same JSON POST request shape as the current synchronous API reference. Keep the secret in an environment variable, not in source code that ships to a browser.
cURL
curl --request POST 'https://api.urlbox.com/v1/render/sync' \
--header "Authorization: Bearer $URLBOX_API_SECRET" \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{"url":"https://example.com","width":1280,"height":800,"format":"png"}'
Python
import os
import requests
secret = os.environ["URLBOX_API_SECRET"]
response = requests.post(
"https://api.urlbox.com/v1/render/sync",
headers={
"Authorization": f"Bearer {secret}",
"Accept": "application/json",
},
json={
"url": "https://example.com",
"width": 1280,
"height": 800,
"format": "png",
},
timeout=120,
)
response.raise_for_status()
result = response.json()
print(result["renderUrl"])
Node.js
const secret = process.env.URLBOX_API_SECRET;
if (!secret) throw new Error('Set URLBOX_API_SECRET');
const response = await fetch('https://api.urlbox.com/v1/render/sync', {
method: 'POST',
headers: {
Authorization: `Bearer ${secret}`,
'Content-Type': 'application/json',
Accept: 'application/json',
},
body: JSON.stringify({
url: 'https://example.com',
width: 1280,
height: 800,
format: 'png',
}),
signal: AbortSignal.timeout(120000),
});
if (!response.ok) {
throw new Error(`Urlbox returned HTTP ${response.status}: ${await response.text()}`);
}
const result = await response.json();
console.log(result.renderUrl);
6. Choose the capture options that match the page
Urlbox accepts a URL or HTML and supports screenshots and other render outputs. Its API reference shows PNG and PDF examples; its overview also describes video, metadata, and HTML extraction. Check the live [API reference](https://urlbox.com/docs/api) for the exact parameters and output-specific requirements.
| Need | Option or approach | Trade-off |
|---|---|---|
| Capture a page beyond the viewport | full_page: true |
Default full-page behavior scrolls down to trigger lazy content and measure page height. |
| Reduce initial scrolling | skip_scroll: true |
May reduce render time, but content that loads on scroll may be missing. |
| Capture long pages accurately | full_page: true with documented stitch mode |
Scrolls and combines sections to handle more page layouts. |
| Use browser-native full-page capture | Documented native mode |
Faster, but can fail on some sites. |
| Capture a component or region | selector with a CSS selector |
Targets the selected element; verify the selector matches the rendered page. |
| Include horizontally scrolling content | full_width |
Useful when the page scrolls horizontally. |
| Return a document | PDF output and its documented paper, layout, and related options | Choose PDF when the consumer needs a paginated document rather than an image. |
For format limits, the screenshot documentation lists JPEG’s maximum dimensions as 65,535 × 65,535 and WebP’s as 16,383 × 16,383. It recommends PNG for full-page captures without those size limits. See [Urlbox screenshot options](https://urlbox.com/docs/screenshots) and confirm current parameter names and valid values before rollout.
7. Handle output and retention
- For a signed-link integration, put the generated URL in the image source and let the browser request the render.
- For the JSON API, read
renderUrlfrom the response and decide whether to display, download, or transfer the file into your own storage. - Do not treat the synchronous API’s returned URL as permanent: the quickstart documents a 30-day expiry.
- For durable retention, download the rendered file or configure the documented storage integration appropriate to your account.
- For large or slow workflows, review Urlbox’s asynchronous API options in its current documentation rather than holding a web request open indefinitely.
8. Security and production checklist
- Keep the API secret in server-side environment configuration or a secrets manager.
- Generate signed render links on the server; HMAC-SHA256 signatures are tied to the query options.
- Do not edit a signed URL’s options after generating it. Regenerate the URL when options change.
- Use the authentication method documented for the exact endpoint. The current synchronous API reference uses a Bearer secret; the legacy Post API page describes a different endpoint and Basic authentication.
- Validate URLs submitted by users. Restrict captures to permitted destinations in your application to avoid turning your integration into an open proxy or exposing internal resources.
- Escape generated links for the output context when writing HTML.
- Set connect and overall timeouts, handle non-success HTTP statuses, and avoid logging secrets or full authorization headers.
- Plan for temporary render URLs to expire and keep application records from promising indefinite availability.
9. Troubleshooting
| Symptom | Likely cause | What to do |
|---|---|---|
| Signed render link is rejected | The signature was created with different options than those in the URL, or credentials are wrong. | Regenerate the URL from the final options on the server and verify the project key and secret. |
| JSON request returns an authentication error | Wrong credential, malformed Bearer header, or authentication instructions for another endpoint were used. | For /v1/render/sync, follow the current API reference and send Authorization: Bearer SECRET. |
| PHP reports cURL error or timeout | Network connectivity, DNS, TLS, or a slow render exceeded the client timeout. | Inspect the cURL error, check server outbound HTTPS access, and choose a timeout suitable for the workflow. Use an asynchronous flow for work that should not block a request. |
| Response is not valid JSON | An intermediary or API error returned a different body, or the response was treated as success without checking status. | Record the HTTP status and response body safely, check status before consuming fields, and decode JSON with exception handling. |
| Screenshot misses images or below-fold content | Lazy-loaded content may not have been triggered or the selected capture mode may not fit the layout. | Use full-page capture’s default scroll behavior and stitch mode; avoid skip_scroll if the page depends on scrolling. |
| Native full-page capture is incomplete | Native full-page mode can fail on some page layouts. | Switch to the documented stitch mode and compare output on representative pages. |
| Element capture is empty or wrong | The CSS selector does not match at render time or the target is not visible yet. | Check the selector against the page, and consult current wait options if the element appears after scripts run. |
| Render URL no longer works | The temporary URL has expired. | Generate another render or retain the earlier output in application-controlled storage. |
| Large JPEG or WebP capture fails | Output dimension limits were exceeded. | Reduce capture dimensions or use PNG for full-page captures, as recommended by the screenshot documentation. |
10. Performance, reliability, and cost
Performance
Capture time depends on the target page and chosen workflow; the reviewed sources do not provide a benchmark to quote. Full-page scrolling helps trigger lazy content but can add work. skip_scroll may reduce render time when scroll-triggered content is not needed. The docs describe native full-page mode as faster, with lower reliability on some sites, while stitch mode supports more layouts. Set client timeouts based on your application’s request budget and use asynchronous processing for jobs that should not tie up a user-facing request.
Reliability
Check both transport errors and HTTP status, parse the response shape defensively, and make retries bounded. Retrying a failed request can be appropriate for transient network problems, but avoid unbounded retry loops. Keep the expiring render URL lifecycle in mind. For visual quality, test the chosen mode against representative pages, including long pages, lazy-loaded content, and horizontally scrolling layouts.
Cost and India-specific considerations
Urlbox’s pricing page currently lists Lo-Fi at $19/month for up to 2,000 renders, Hi-Fi at $49/month for up to 5,000, Ultra at $99/month for up to 15,000, Business at a $495 base plus $3 per 1,000 renders, and Enterprise from $3,000/month. It says prices exclude VAT at the prevailing rate. These are live plan listings, not India-specific quotes; confirm current prices, included limits, and terms on the [Urlbox pricing page](https://urlbox.com/pricing). The reviewed sources do not establish INR pricing, GST handling, local payment methods, or your tax obligations. Estimate monthly volume and required capture features before selecting a plan.
11. Or skip the browser setup
If you want one HTTP call instead of maintaining a rendering integration, [ScreenshotNeo](https://screenshotneo.com) is a website screenshot API and MCP server for developers. It accepts one GET request and returns a PNG, JPEG, WebP, or PDF. Its [API documentation](https://screenshotneo.com/docs/) covers the request options.
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}`);
- Cookie banners are accepted like a visitor, then 60+ known consent platforms, newsletter popups, and chat widgets are removed before the shot; each step can be turned off.
- Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed; response headers identify the page verdict and billing status.
- An MCP server provides
take_screenshot,get_page_info, andcapture_pdftools for Claude, Cursor, and other MCP clients. - The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Every feature is on every plan.
Create a free ScreenshotNeo account for 1,000 screenshots a month with no card.
12. FAQ
Can I use the signed screenshot URL directly in an HTML image?
Yes. The official PHP example generates a signed URL and embeds it as the image source. Generate it server-side and escape it in the HTML attribute.
Does the signed-link flow return the same kind of response as the JSON API?
No. The signed-link flow produces a render URL for use as an image source. The synchronous JSON API returns JSON including a temporary renderUrl and size information.
Does the available documentation confirm Laravel support?
The reviewed PHP sample documents a Composer package, but it does not establish a Laravel compatibility matrix. Verify the package requirements against your Laravel and PHP versions.
Where can I check whether Urlbox pricing changed?
Use the live [Urlbox pricing page](https://urlbox.com/pricing); listed prices and plan details can change.


