Screenshot -- PHP SDK

Official PHP SDK for the Nodium Screenshot API. Requires PHP 8.1+ and Guzzle HTTP client.

Installation

bash
composer require nodium/screenshot-sdk

Requirements

  • PHP 8.1 or higher
  • Guzzle 7.0+ (installed automatically as a dependency)
  • ext-json (included in most PHP installations)

Quick Start

php
<?php

require_once 'vendor/autoload.php';

use Nodium\Screenshot\Client;

$client = new Client('YOUR_API_KEY');

$result = $client->take([
    'url' => 'https://example.com',
    'format' => 'png',
]);

file_put_contents('screenshot.png', $result->data);

Client Initialization

php
use Nodium\Screenshot\Client;

// Basic initialization
$client = new Client('YOUR_API_KEY');

// With options
$client = new Client('YOUR_API_KEY', [
    'base_url' => 'https://api.nodium.io/api/v1/screenshot',
    'timeout'  => 60,      // Request timeout in seconds (default: 60)
    'retries'  => 3,       // Automatic retries on 5xx errors (default: 3)
]);

Environment Variable

php
// Reads from the NODIUM_API_KEY environment variable automatically
$client = new Client();

Methods

take() -- Capture a Screenshot

php
$result = $client->take([
    'url'             => 'https://example.com',
    'format'          => 'png',
    'viewport_width'  => 1280,
    'viewport_height' => 1024,
    'full_page'       => true,
    'image_quality'   => 90,
]);

// $result->data     -- string with raw image/PDF bytes
// $result->headers  -- array with response headers
file_put_contents('screenshot.png', $result->data);

echo "Rendering time: {$result->headers['rendering_seconds']}s\n";
echo "File size: {$result->headers['size_bytes']} bytes\n";

animate() -- Record an Animated Screenshot

php
$result = $client->animate([
    'url'                => 'https://example.com',
    'format'             => 'mp4',
    'scroll_animation'   => 'smooth',
    'animation_duration' => 5,
    'viewport_width'     => 1280,
    'viewport_height'    => 720,
]);

file_put_contents('animation.mp4', $result->data);

bulk() -- Batch Capture

php
$results = $client->bulk([
    'urls' => [
        'https://example.com',
        'https://example.org',
        'https://example.net',
    ],
    'format'          => 'png',
    'viewport_width'  => 1280,
    'viewport_height' => 1024,
]);

foreach ($results as $i => $result) {
    file_put_contents("screenshot-{$i}.png", $result->data);
}

getUsage() -- Check API Usage

php
$usage = $client->getUsage();

echo "Screenshots taken: {$usage->screenshots_taken}\n";
echo "Monthly limit: {$usage->monthly_limit}\n";
echo "Remaining: {$usage->remaining}\n";
echo "Billing period ends: {$usage->period_end}\n";

Fluent Builder API

Build screenshot requests using a chainable interface.

php
$result = $client->take()
    ->url('https://example.com')
    ->format('png')
    ->viewport(1280, 1024)
    ->fullPage(true)
    ->imageQuality(90)
    ->execute();

file_put_contents('screenshot.png', $result->data);

Builder Methods

MethodDescription
->url($url)Target URL to capture
->html($html)Raw HTML to render
->markdown($md)Markdown content to render
->format($fmt)Output format: png, jpeg, webp, avif, pdf, etc.
->viewport($w, $h)Viewport dimensions
->viewportDevice($device)Device emulation (e.g. iphone_16_pro)
->fullPage($bool)Capture the entire scrollable page
->imageQuality($n)JPEG/WebP quality (1-100)
->selector($css)Capture a specific CSS selector
->delay($ms)Wait before capture (milliseconds)
->blockAds($bool)Block ads and trackers
->darkMode($bool)Force dark color scheme
->responseType($type)by_format, json, or empty
->webhook($url)Webhook URL for async delivery
->execute()Execute the request and return the result

Chaining Example

php
$pdf = $client->take()
    ->url('https://example.com/report')
    ->format('pdf')
    ->fullPage(true)
    ->viewport(1440, 900)
    ->delay(2000)
    ->blockAds(true)
    ->execute();

file_put_contents('report.pdf', $pdf->data);

Error Handling

The SDK throws typed exceptions for all API errors.

php
use Nodium\Screenshot\Client;
use Nodium\Screenshot\Exceptions\NodiumAPIException;
use Nodium\Screenshot\Exceptions\NodiumTimeoutException;
use Nodium\Screenshot\Exceptions\NodiumException;

try {
    $result = $client->take([
        'url'    => 'https://example.com',
        'format' => 'png',
    ]);

    file_put_contents('screenshot.png', $result->data);

} catch (NodiumAPIException $e) {
    echo "Error code: {$e->getErrorCode()}\n";      // e.g. "request_not_valid"
    echo "Message: {$e->getMessage()}\n";             // Human-readable description
    echo "HTTP status: {$e->getHttpStatus()}\n";      // e.g. 400
    echo "Retryable: " . ($e->isRetryable() ? 'yes' : 'no') . "\n";

    if ($e->getErrorCode() === 'screenshots_limit_reached') {
        echo "Monthly quota exceeded. Upgrade your plan.\n";
    }

} catch (NodiumTimeoutException $e) {
    echo "Request timed out: {$e->getMessage()}\n";

} catch (NodiumException $e) {
    // Base exception for all SDK errors
    echo "SDK error: {$e->getMessage()}\n";
}

Error Codes

CodeHTTP StatusRetryable
access_key_required400No
access_key_invalid400No
request_not_valid400No
screenshots_limit_reached400No
concurrency_limit_reached400No
timeout_error500Yes
network_error500Yes
internal_application_error500Yes
temporary_unavailable503Yes

Laravel Integration

Service Provider Configuration

Add your API key to .env:

env
NODIUM_API_KEY=your_api_key_here

Add the config value in config/services.php:

php
// config/services.php
return [
    // ...
    'nodium' => [
        'api_key' => env('NODIUM_API_KEY'),
    ],
];

Register in a Service Provider

php
// app/Providers/AppServiceProvider.php
use Nodium\Screenshot\Client;

public function register(): void
{
    $this->app->singleton(Client::class, function ($app) {
        return new Client(config('services.nodium.api_key'), [
            'timeout' => 60,
            'retries' => 3,
        ]);
    });
}

Controller Example

php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Nodium\Screenshot\Client;
use Nodium\Screenshot\Exceptions\NodiumAPIException;

class ScreenshotController extends Controller
{
    public function __construct(
        private readonly Client $screenshot,
    ) {}

    public function capture(Request $request): Response
    {
        $request->validate([
            'url' => 'required|url',
        ]);

        try {
            $result = $this->screenshot->take()
                ->url($request->input('url'))
                ->format('png')
                ->viewport(1280, 1024)
                ->execute();

            return response($result->data, 200, [
                'Content-Type' => 'image/png',
                'Content-Disposition' => 'inline; filename="screenshot.png"',
            ]);

        } catch (NodiumAPIException $e) {
            return response()->json([
                'error'   => $e->getErrorCode(),
                'message' => $e->getMessage(),
            ], $e->getHttpStatus());
        }
    }
}

Route

php
// routes/web.php
use App\Http\Controllers\ScreenshotController;

Route::get('/screenshot', [ScreenshotController::class, 'capture']);

Signed URL Generation

Generate pre-signed URLs for safe sharing without exposing your API key.

php
$signedUrl = $client->generateSignedUrl([
    'url'             => 'https://example.com',
    'format'          => 'png',
    'viewport_width'  => 1280,
    'viewport_height' => 1024,
    'expires_in'      => 3600, // Valid for 1 hour
]);

echo $signedUrl;
// https://api.nodium.io/api/v1/screenshot/take?url=...&signature=...&expires=...

Use in Blade Templates

php
// Controller
public function show()
{
    $signedUrl = $this->screenshot->generateSignedUrl([
        'url'        => 'https://example.com',
        'format'     => 'png',
        'expires_in' => 300,
    ]);

    return view('preview', compact('signedUrl'));
}
blade
<!-- resources/views/preview.blade.php -->
<img src="{{ $signedUrl }}" alt="Screenshot preview" />

Full Example

A complete example that captures a screenshot, saves it to disk, and handles all error scenarios.

php
<?php

require_once 'vendor/autoload.php';

use Nodium\Screenshot\Client;
use Nodium\Screenshot\Exceptions\NodiumAPIException;
use Nodium\Screenshot\Exceptions\NodiumException;

function captureAndSave(string $targetUrl, string $outputPath): void
{
    $client = new Client(getenv('NODIUM_API_KEY') ?: null);

    try {
        // Check usage before capturing
        $usage = $client->getUsage();
        if ($usage->remaining <= 0) {
            fwrite(STDERR, "No screenshots remaining this billing period.\n");
            exit(1);
        }

        echo "Remaining quota: {$usage->remaining}/{$usage->monthly_limit}\n";

        // Take the screenshot using the fluent builder
        $result = $client->take()
            ->url($targetUrl)
            ->format('png')
            ->viewport(1440, 900)
            ->fullPage(true)
            ->blockAds(true)
            ->delay(1000)
            ->imageQuality(95)
            ->execute();

        // Ensure the output directory exists
        $dir = dirname($outputPath);
        if (!is_dir($dir)) {
            mkdir($dir, 0755, true);
        }

        // Write the screenshot to disk
        file_put_contents($outputPath, $result->data);

        echo "Screenshot saved to {$outputPath}\n";
        echo "Rendering time: {$result->headers['rendering_seconds']}s\n";
        echo "File size: " . round($result->headers['size_bytes'] / 1024, 1) . " KB\n";
        echo "Reference: {$result->headers['reference']}\n";

    } catch (NodiumAPIException $e) {
        fwrite(STDERR, "API error [{$e->getErrorCode()}]: {$e->getMessage()}\n");
        if ($e->isRetryable()) {
            fwrite(STDERR, "This error is retryable. The SDK already retried automatically.\n");
        }
        exit(1);

    } catch (NodiumException $e) {
        fwrite(STDERR, "SDK error: {$e->getMessage()}\n");
        exit(1);
    }
}

captureAndSave('https://example.com', './output/screenshot.png');

Next Steps