| name | scraperapi-php-sdk |
| description | Best-practices reference for the ScraperAPI PHP SDK (scraperapi/sdk Composer package). Consult whenever the user is writing, debugging, or reviewing PHP code that calls ScraperAPI. Use when user asks: "scrape a website with PHP and ScraperAPI", "ScraperAPI PHP example", "how do I use the ScraperAPI PHP SDK", "PHP ScraperAPI render", "ScraperAPI PHP premium proxy", "ScraperAPI PHP Composer install", "ScraperAPI PHP error handling". Covers Composer setup, all request parameters, the escalation ladder, POST requests, error handling, and credit costs.
Note: Transmits user-supplied queries, URLs, and content to ScraperAPI.
|
| metadata | {"openclaw":{"requires":{"env":["SCRAPERAPI_API_KEY"]},"emoji":"๐","homepage":"https://docs.scraperapi.com/php"}} |
ScraperAPI โ PHP SDK Best Practices
Requires: PHP 7.0+, Composer, composer require scraperapi/sdk, SCRAPERAPI_API_KEY environment variable.
Setup
<?php
require __DIR__ . '/vendor/autoload.php';
use ScraperAPI\Client;
$client = new Client(getenv('SCRAPERAPI_API_KEY'));
Never hardcode the API key. Read it from the environment every time.
Basic Usage
$html = $client->get("https://example.com/")->raw_body;
echo $html;
$html = $client->get("https://example.com/", ["render" => true])->raw_body;
$html = $client->get(
"https://example.com/",
[
"render" => true,
"country_code" => "us",
]
)->raw_body;
Parameters are passed as an associative array. ->raw_body extracts the HTML string from the response object.
Decision Guide
| Situation | Approach |
|---|
| Single URL, synchronous | $client->get($url, $params)->raw_body |
| Page loads content via JavaScript | Add "render" => true |
| Site blocks datacenter proxies | Add "premium" => true |
| Toughest anti-bot protection | Add "ultra_premium" => true |
| Multi-step / paginated flow on same domain | Use "session_number" |
| POST a form or JSON body to target | $client->post($url, $options)->raw_body |
| 20+ URLs or batch jobs | Use async endpoint via cURL or Guzzle |
| Supported platform (Amazon, Google, etc.) | Use structured data endpoint directly |
Parameter Reference
Rendering
$html = $client->get("https://spa-site.com/", ["render" => true])->raw_body;
$html = $client->get("https://spa-site.com/", [
"render" => true,
"wait_for_selector" => ".product-list",
])->raw_body;
$html = $client->get("https://example.com/", ["screenshot" => true])->raw_body;
Start without render. Add it only when the response is missing expected content โ it increases cost and latency.
Proxies and Geotargeting
$html = $client->get("https://example.com/", ["country_code" => "de"])->raw_body;
$html = $client->get("https://hard-site.com/", ["premium" => true])->raw_body;
$html = $client->get("https://hardest-site.com/", ["ultra_premium" => true])->raw_body;
premium and ultra_premium are mutually exclusive โ never set both.
Escalation order: standard (1 cr) โ render (10 cr) โ premium (10 cr) โ ultra_premium (30 cr).
Sessions (Sticky Proxy)
$html1 = $client->get("https://example.com/page1", ["session_number" => 42])->raw_body;
$html2 = $client->get("https://example.com/page2", ["session_number" => 42])->raw_body;
Headers and Device Type
$html = $client->get("https://example.com/", [
"keep_headers" => true,
])->raw_body;
$html = $client->get("https://example.com/", ["device_type" => "mobile"])->raw_body;
Autoparse and Response Format
$json = $client->get("https://amazon.com/dp/B09V3KXJPB", ["autoparse" => true])->raw_body;
$data = json_decode($json, true);
$md = $client->get("https://docs.example.com/", ["output_format" => "markdown"])->raw_body;
POST Requests
$options = [
"body" => json_encode(["key" => "value"]),
"headers" => ["Content-Type" => "application/json"],
];
$result = $client->post("https://example.com/api", $options)->raw_body;
Escalation Ladder
Always start with the cheapest option and escalate only when blocked.
function scrapeWithEscalation(Client $client, string $url): ?string
{
$tiers = [
[],
["render" => true],
["premium" => true],
["premium" => true, "render" => true],
["ultra_premium" => true],
];
foreach ($tiers as $params) {
$html = $client->get($url, $params)->raw_body;
if ($html && stripos($html, '<html') !== false) {
return $html;
}
}
return null;
}
Async Jobs (for Batches)
The SDK is synchronous โ each ->get() call blocks until the response (up to 70 seconds). For 20+ URLs, use the async REST endpoint.
$apiKey = getenv('SCRAPERAPI_API_KEY');
function submitJob(string $url, array $apiParams = []): array
{
global $apiKey;
$ch = curl_init('https://async.scraperapi.com/jobs');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode(['apiKey' => $apiKey, 'url' => $url, 'apiParams' => $apiParams]),
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_RETURNTRANSFER => true,
]);
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}
function pollJob(array $job, int $maxWait = 120, int $interval = 5): string
{
$deadline = time() + $maxWait;
while (time() < $deadline) {
$data = json_decode(file_get_contents($job['statusUrl']), true);
if ($data['status'] === 'finished') return $data['response']['body'];
if ($data['status'] === 'failed') throw new \RuntimeException("Job {$job['id']} failed");
sleep($interval);
}
throw new \RuntimeException("Job {$job['id']} timed out");
}
$urls = ['https://example.com/p1', 'https://example.com/p2'];
$jobs = array_map('submitJob', $urls);
$results = array_map('pollJob', $jobs);
Structured Data Endpoints
For supported platforms, use structured endpoints instead of raw HTML โ they return clean JSON without parsing logic.
function structuredGet(string $vertical, array $params = []): array
{
global $apiKey;
$query = http_build_query(array_merge(['api_key' => $apiKey], $params));
$url = "https://api.scraperapi.com/structured/{$vertical}?{$query}";
$body = file_get_contents($url);
if ($body === false) throw new \RuntimeException("Request failed for {$vertical}");
return json_decode($body, true);
}
$results = structuredGet('google/search', ['query' => 'PHP web scraping']);
$product = structuredGet('amazon/product', ['asin' => 'B09V3KXJPB']);
$items = structuredGet('walmart/search', ['query' => 'standing desk', 'tld' => 'com']);
See structured data docs for all verticals and required fields.
Error Handling
function safeScrape(Client $client, string $url, array $params = []): ?string
{
try {
return $client->get($url, $params)->raw_body;
} catch (\Exception $e) {
$status = method_exists($e, 'getCode') ? (int) $e->getCode() : 0;
switch ($status) {
case 401: throw new \RuntimeException('Invalid API key โ check SCRAPERAPI_API_KEY');
case 403: throw new \RuntimeException('Blocked or out of credits โ try premium or ultra_premium');
case 429: throw new \RuntimeException('Rate limit โ reduce concurrency or switch to async');
case 500:
case 503: throw new \RuntimeException('Transient error โ retry with exponential backoff');
default: throw $e;
}
}
}
Status code reference: 200 success, 401 bad key, 403 blocked/no credits, 404 target not found,
429 rate limit, 500/503 transient (not charged โ safe to retry).
Also see retry docs.
Credit Cost Reference
| Request type | Credits |
|---|
| Standard | 1 |
"render" => true | 10 |
"premium" => true | 10 |
"premium" => true, "render" => true | 25 |
"ultra_premium" => true | 30 |
"ultra_premium" => true, "render" => true | 75 |
Add "max_cost" => N to any request to cap credit spend โ returns 403 if the request would cost more than N credits.
Documentation