Skip to main content
Version: v2

PHP Integration Guide

Browserless provides multiple ways to integrate with PHP applications, from simple REST API calls using cURL to comprehensive Laravel SDK integration. This guide covers everything from basic usage to advanced automation workflows.

Quick Start: Basic cURL Usage

The simplest way to get started with Browserless in PHP is using cURL to call our REST APIs:

<?php

$curl = curl_init();

curl_setopt_array($curl, [
CURLOPT_URL => "https://production-sfo.browserless.io/screenshot?token=YOUR_API_TOKEN_HERE",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
"url" => "https://example.com/",
"options" => [
"fullPage" => true,
"encoding" => "base64"
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
echo "cURL Error #:" . $err;
} else {
// Save the base64 encoded screenshot
file_put_contents('screenshot.png', base64_decode($response));
echo "Screenshot saved successfully!";
}

Laravel SDK (Community Supported)

Community Package

The Laravel Browserless SDK is a community-supported package created and maintained by Christopher Miller. While not officially supported by Browserless, it provides an excellent Laravel-native way to integrate with our services.

Learn more about the SDK:

Installation

composer require millerphp/laravel-browserless

Laravel SDK Examples

The Laravel SDK provides a fluent, Laravel-native API for all Browserless features:

use MillerPHP\LaravelBrowserless\Facades\Browserless;

// Generate a PDF from a URL
$pdf = Browserless::pdf()
->url('https://example.com/invoice/123')
->printBackground()
->format('A4')
->send()
->save('invoice-123.pdf');

Modern PHP Examples (PHP 8.x)

Using Guzzle HTTP Client

For more robust HTTP handling, consider using Guzzle:

<?php

use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;

class BrowserlessClient
{
private Client $client;
private string $apiToken;
private string $baseUrl;

public function __construct(string $apiToken, string $region = 'sfo')
{
$this->apiToken = $apiToken;
$this->baseUrl = "https://production-{$region}.browserless.io";
$this->client = new Client([
'timeout' => 60,
'headers' => [
'Content-Type' => 'application/json',
'User-Agent' => 'PHP-Browserless-Client/1.0'
]
]);
}

public function screenshot(string $url, array $options = []): string
{
try {
$response = $this->client->post("{$this->baseUrl}/screenshot", [
'query' => ['token' => $this->apiToken],
'json' => [
'url' => $url,
'options' => array_merge([
'fullPage' => true,
'type' => 'png'
], $options)
]
]);

return $response->getBody()->getContents();
} catch (RequestException $e) {
throw new Exception("Screenshot failed: " . $e->getMessage());
}
}

public function generatePdf(string $url, array $options = []): string
{
try {
$response = $this->client->post("{$this->baseUrl}/pdf", [
'query' => ['token' => $this->apiToken],
'json' => [
'url' => $url,
'options' => array_merge([
'format' => 'A4',
'printBackground' => true
], $options)
]
]);

return $response->getBody()->getContents();
} catch (RequestException $e) {
throw new Exception("PDF generation failed: " . $e->getMessage());
}
}

public function getContent(string $url, int $waitFor = 0): array
{
try {
$response = $this->client->post("{$this->baseUrl}/content", [
'query' => ['token' => $this->apiToken],
'json' => [
'url' => $url,
'waitForTimeout' => $waitFor
]
]);

return json_decode($response->getBody()->getContents(), true);
} catch (RequestException $e) {
throw new Exception("Content retrieval failed: " . $e->getMessage());
}
}
}

Usage Example with Error Handling

<?php

try {
$browserless = new BrowserlessClient('YOUR_API_TOKEN_HERE');

// Generate a PDF report
$pdfData = $browserless->generatePdf('https://example.com/report', [
'format' => 'A4',
'margin' => [
'top' => '1cm',
'bottom' => '1cm',
'left' => '1cm',
'right' => '1cm'
]
]);

file_put_contents('report.pdf', $pdfData);
echo "PDF generated successfully!\n";

// Take a mobile screenshot
$screenshotData = $browserless->screenshot('https://example.com', [
'viewport' => [
'width' => 375,
'height' => 667,
'deviceScaleFactor' => 2
]
]);

file_put_contents('mobile-screenshot.png', $screenshotData);
echo "Mobile screenshot captured!\n";

} catch (Exception $e) {
error_log("Browserless operation failed: " . $e->getMessage());
}

Advanced Use Cases

Web Scraping with Content API

<?php

class WebScraper
{
private BrowserlessClient $client;

public function __construct(BrowserlessClient $client)
{
$this->client = $client;
}

public function scrapeProductPrices(string $url): array
{
// Wait for dynamic content to load
$content = $this->client->getContent($url, 3000);

$dom = new DOMDocument();
@$dom->loadHTML($content);
$xpath = new DOMXPath($dom);

$prices = [];
$priceNodes = $xpath->query('//span[@class="price"]');

foreach ($priceNodes as $node) {
$prices[] = trim($node->textContent);
}

return $prices;
}

public function scrapeBatch(array $urls): array
{
$results = [];

foreach ($urls as $url) {
try {
$results[$url] = $this->scrapeProductPrices($url);
// Add delay to be respectful
sleep(1);
} catch (Exception $e) {
$results[$url] = ['error' => $e->getMessage()];
}
}

return $results;
}
}

Using with Proxy Support

<?php

$curl = curl_init();

curl_setopt_array($curl, [
CURLOPT_URL => "https://production-sfo.browserless.io/screenshot?token=YOUR_API_TOKEN_HERE&proxy=residential",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 60,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
"url" => "https://example.com/",
"options" => [
"fullPage" => true
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);

$response = curl_exec($curl);
curl_close($curl);

Function Execution for Custom Logic

<?php

function executeCustomBrowserFunction(string $url, string $jsCode): array
{
$curl = curl_init();

curl_setopt_array($curl, [
CURLOPT_URL => "https://production-sfo.browserless.io/function?token=YOUR_API_TOKEN_HERE",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 60,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
"code" => $jsCode,
"context" => [
"url" => $url
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);

$response = curl_exec($curl);
curl_close($curl);

return json_decode($response, true);
}

// Example: Get page performance metrics
$performanceCode = '
export default async ({ page, context }) => {
await page.goto(context.url);

const metrics = await page.evaluate(() => {
const navigation = performance.getEntriesByType("navigation")[0];
return {
loadTime: navigation.loadEventEnd - navigation.loadEventStart,
domContentLoaded: navigation.domContentLoadedEventEnd - navigation.domContentLoadedEventStart,
firstPaint: performance.getEntriesByType("paint")[0]?.startTime || 0
};
});

return metrics;
};
';

$metrics = executeCustomBrowserFunction('https://example.com', $performanceCode);
echo "Page load time: " . $metrics['loadTime'] . "ms\n";

Framework Integration Examples

Symfony Integration

<?php

namespace App\Service;

use Symfony\Component\HttpClient\HttpClient;
use Symfony\Contracts\HttpClient\HttpClientInterface;

class BrowserlessService
{
private HttpClientInterface $client;
private string $apiToken;

public function __construct(string $apiToken)
{
$this->apiToken = $apiToken;
$this->client = HttpClient::create([
'timeout' => 60,
'headers' => [
'Content-Type' => 'application/json'
]
]);
}

public function generateInvoicePdf(int $invoiceId): string
{
$response = $this->client->request('POST',
'https://production-sfo.browserless.io/pdf', [
'query' => ['token' => $this->apiToken],
'json' => [
'url' => "https://yourapp.com/invoice/{$invoiceId}",
'options' => [
'format' => 'A4',
'printBackground' => true
]
]
]);

return $response->getContent();
}
}

WordPress Plugin Integration

<?php

class WP_Browserless_Plugin
{
private string $apiToken;

public function __construct()
{
$this->apiToken = get_option('browserless_api_token');
add_action('init', [$this, 'init']);
}

public function init(): void
{
add_action('wp_ajax_generate_pdf', [$this, 'generatePdf']);
add_action('wp_ajax_nopriv_generate_pdf', [$this, 'generatePdf']);
}

public function generatePdf(): void
{
$post_id = intval($_POST['post_id']);
$post_url = get_permalink($post_id);

$response = wp_remote_post('https://production-sfo.browserless.io/pdf', [
'headers' => ['Content-Type' => 'application/json'],
'body' => json_encode([
'url' => $post_url,
'options' => [
'format' => 'A4',
'printBackground' => true
]
]),
'timeout' => 60
]);

if (is_wp_error($response)) {
wp_die('PDF generation failed');
}

$pdf_data = wp_remote_retrieve_body($response);

header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename="post-' . $post_id . '.pdf"');
echo $pdf_data;
exit;
}
}

new WP_Browserless_Plugin();

Best Practices

Error Handling and Retry Logic

<?php

class RobustBrowserlessClient
{
private const MAX_RETRIES = 3;
private const RETRY_DELAY = 1; // seconds

private function executeWithRetry(callable $operation, int $maxRetries = self::MAX_RETRIES): mixed
{
$lastException = null;

for ($attempt = 1; $attempt <= $maxRetries; $attempt++) {
try {
return $operation();
} catch (Exception $e) {
$lastException = $e;

if ($attempt < $maxRetries) {
sleep(self::RETRY_DELAY * $attempt); // Exponential backoff
continue;
}
}
}

throw $lastException;
}

public function reliableScreenshot(string $url): string
{
return $this->executeWithRetry(function() use ($url) {
// Your screenshot logic here
return $this->client->screenshot($url);
});
}
}

Configuration Management

<?php

class BrowserlessConfig
{
public readonly string $apiToken;
public readonly string $baseUrl;
public readonly int $timeout;
public readonly array $defaultOptions;

public function __construct(
?string $apiToken = null,
string $region = 'sfo',
int $timeout = 60
) {
$this->apiToken = $apiToken ?? $_ENV['BROWSERLESS_API_TOKEN'] ?? throw new InvalidArgumentException('API token required');
$this->baseUrl = "https://production-{$region}.browserless.io";
$this->timeout = $timeout;
$this->defaultOptions = [
'stealth' => true,
'blockAds' => true
];
}
}

Performance Optimization

Concurrent Requests with ReactPHP

<?php

use React\Http\Browser;
use React\Promise\Promise;

function concurrentScreenshots(array $urls): Promise
{
$browser = new Browser();
$promises = [];

foreach ($urls as $url) {
$promises[] = $browser->post('https://production-sfo.browserless.io/screenshot', [
'Content-Type' => 'application/json'
], json_encode([
'url' => $url,
'options' => ['fullPage' => true]
]));
}

return \React\Promise\all($promises);
}

Security Considerations

  • Never expose your API token in client-side code or public repositories
  • Use environment variables to store sensitive configuration
  • Implement rate limiting in your application to avoid hitting API limits
  • Validate and sanitize URLs before sending them to Browserless
  • Use HTTPS for all communications with the Browserless API

Troubleshooting Common Issues

Timeout Issues

If you're experiencing timeouts, increase the timeout values:

// Increase cURL timeout
curl_setopt($curl, CURLOPT_TIMEOUT, 120);

// Or add timeout parameter to URL
$url = "https://production-sfo.browserless.io/pdf?token=YOUR_TOKEN&timeout=120000";

Memory Issues with Large Responses

For large PDFs or screenshots, consider streaming:

$handle = fopen('large-file.pdf', 'w');
curl_setopt($curl, CURLOPT_FILE, $handle);
curl_exec($curl);
fclose($handle);

Next Steps

Be sure to let us know if you have questions or issues.