ScreenshotNeo

BlogHow-to

Abstract Screenshot API with Laravel: Capture a Webpage as PNG

Use Abstract’s Screenshot API from Laravel to request a webpage image, understand what its docs confirm, and compare it with a Laravel-native option.

By the ScreenshotNeo team4 October 20269 min read

Abstract documents a hosted Screenshot API at https://screenshot.abstractapi.com/v1/. Its example sends an api_key and a target url; the product page says it can accept a URL or raw HTML and return images including PNG. The documentation retrieved for this guide does not establish a Laravel SDK, the complete current parameter list, or exact response handling, so verify those details in Abstract’s live API reference before relying on the minimal request below.

If you need a Laravel-native capture package, Spatie’s Laravel Screenshot is a separate option with documented Browsershot and Cloudflare Browser Rendering drivers. Those package features and requirements are not features or requirements of Abstract’s API.

1. What Abstract documents

  • Endpoint: https://screenshot.abstractapi.com/v1/.
  • Example request inputs: an API key and a URL query parameter.
  • Input types: Abstract describes URL and raw HTML input. It says a publicly accessible source URL is not required when sending raw HTML; that does not establish support for every private-site authentication flow.
  • Image formats: the product page lists JPEG, PNG, and GIF.
  • Advertised customization: resizing and cropping, viewport and dimensions, custom CSS, and delayed captures.

Abstract’s product page is a hosted-service overview, not a Laravel integration guide or a complete current API specification. It does not provide enough verified detail here to specify a PNG format parameter, response body behavior, error schema, quotas, pricing, or rate limits. Check the Abstract Website Screenshot API page and its current linked API reference for those details.

2. Make the minimal request from Laravel

The request shape below follows Abstract’s documented endpoint and API-key-plus-URL example. It keeps the key in Laravel configuration and shows basic HTTP failure handling. It deliberately does not assume how the current service selects PNG or returns image bytes: confirm the current API reference, then adapt the response handling accordingly.

Store the API key in the environment

# .env
ABSTRACT_SCREENSHOT_API_KEY=your_api_key

Add a configuration entry so application code reads the value through Laravel’s configuration system:

// config/services.php
return [
    // Keep your existing service entries.
    'abstract_screenshot' => [
        'key' => env('ABSTRACT_SCREENSHOT_API_KEY'),
    ],
];

If config/services.php already returns an array, add the abstract_screenshot entry inside that array instead of replacing the file. After changing environment-backed configuration in a deployed app, refresh Laravel’s configuration cache as part of your normal deployment process.

Issue the request with Laravel’s HTTP client

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Client\ConnectionException;
use Illuminate\Http\Client\RequestException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Str;
use RuntimeException;

class ScreenshotController
{
    public function capture(Request $request)
    {
        $validated = $request->validate([
            'url' => ['required', 'url', 'max:2048'],
        ]);

        $apiKey = config('services.abstract_screenshot.key');
        if (! is_string($apiKey) || $apiKey === '') {
            throw new RuntimeException('Abstract Screenshot API key is not configured.');
        }

        try {
            $response = Http::accept('image/png')
                ->timeout(60)
                ->get('https://screenshot.abstractapi.com/v1/', [
                    'api_key' => $apiKey,
                    'url' => $validated['url'],
                ]);

            $response->throw();
        } catch (ConnectionException|RequestException $exception) {
            report($exception);
            abort(502, 'The screenshot provider could not complete the request.');
        }

        // Confirm Abstract’s current response format before treating the body
        // as PNG bytes. The product page lists PNG but does not establish the
        // exact response contract or format-selection parameter.
        $contentType = $response->header('Content-Type', '');
        if (! Str::startsWith(strtolower($contentType), 'image/png')) {
            abort(502, 'The provider response was not confirmed as a PNG image.');
        }

        return response($response->body(), 200, [
            'Content-Type' => 'image/png',
            'Content-Disposition' => 'inline; filename="screenshot.png"',
            'Cache-Control' => 'private, no-store',
        ]);
    }
}

The example uses Laravel’s HTTP client and PHP syntax, but the provider-specific response check must match Abstract’s current API contract. If the service returns JSON, a URL, or a different content type for your chosen request, parse that documented response instead of forwarding it as image bytes. Do not pass the API key or an unrestricted URL parameter through to a public endpoint without considering access control and server-side request forgery risks.

Expose an application route

// routes/web.php
use App\Http\Controllers\ScreenshotController;
use Illuminate\Support\Facades\Route;

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

Send a POST request containing a validated URL to this route. Protect it with your application’s authentication, authorization, and rate limiting if users can trigger captures. Avoid logging the API key or sensitive target URLs.

3. Request PNG and handle the result carefully

Abstract’s product page confirms PNG is among its available formats, but the retrieved documentation does not verify the exact parameter name or response contract for selecting and receiving it. Before shipping:

  1. Open Abstract’s current API reference from its product page.
  2. Confirm the current authentication location, HTTP method, and required URL or HTML field.
  3. Find the documented PNG selection option, if one is required, and add that exact parameter.
  4. Confirm whether success returns raw image bytes, JSON, or another representation.
  5. Confirm the documented error format and status codes, then parse provider errors without exposing credentials to callers.
  6. Test a small, known public page and verify the resulting file with an image decoder before treating it as PNG.

Do not infer that an Accept: image/png header selects PNG; the available product page does not establish that behavior. Likewise, the sample Laravel controller’s timeout is an application choice, not an Abstract service guarantee.

4. Laravel-native alternative: Spatie Laravel Screenshot

For capture inside a Laravel application, Spatie documents a separate package with a facade example:

use Spatie\LaravelScreenshot\Facades\Screenshot;

Screenshot::url('https://example.com')->save('screenshot.png');

This is Spatie package code, not an Abstract SDK. Spatie documents two drivers:

Driver Documented deployment needs What to weigh
Browsershot Node.js and a Chrome or Chromium binary Runs browser tooling in your environment; plan for binary installation and operational upkeep.
Cloudflare Browser Rendering Cloudflare account credentials Avoids those server-side browser binaries, while depending on Cloudflare credentials and service.

Spatie’s requirements page specifies PHP 8.4+ and Laravel 12+ for the package version covered there. Requirements can change by release, so check the current package documentation before installing. Spatie also documents URL and raw HTML capture, JavaScript execution for captured HTML, full-page and element captures, clipping, transparency, image format configuration, and wait strategies. Its documented defaults include a 1280×800 viewport, a 2× device scale factor, PNG, and network-idle waiting. These defaults describe Spatie’s package only.

Choose a hosted API when you want a provider to handle rendering infrastructure and your request fits its current API contract. Choose a Laravel package when you want the documented package workflow and can meet its driver requirements. Compare current cost, limits, data handling, and feature details directly: the research available for this article did not establish Abstract pricing or quotas, nor parameter-level feature parity between the products.

5. Operational concerns

Security and input validation

  • Keep provider credentials in environment-backed server configuration; never embed them in browser JavaScript or return them to clients.
  • Validate and authorize capture requests. If end users choose arbitrary URLs, restrict destinations to reduce the risk of your server being used to reach internal services.
  • Do not assume raw HTML support implies private-site login support. Abstract’s dated changelog says password-protected website capture support was expanded on May 20, 2024, but verify the current supported flow before relying on it.
  • Treat captured pages and URLs as potentially sensitive. The reviewed sources do not establish detailed retention or data-handling terms; consult the provider’s current terms for your use case.

Performance and reliability

  • Rendering time depends on the target page and capture settings. Set a caller timeout that fits your application’s request budget, and handle timeouts as a recoverable provider failure.
  • Do not automatically retry every failed request. Retry only transient network or provider failures, use a bounded attempt count with backoff, and avoid duplicate work where the API contract does not provide idempotency guarantees.
  • For user-facing flows, consider queueing captures and returning job status if rendering may exceed normal web request limits. Confirm whether the provider offers asynchronous jobs before designing around provider-side jobs.
  • Cache captures only when the target content and freshness requirements allow it. Include relevant dimensions and capture options in your cache key.
  • Browser-based rendering can be affected by JavaScript, delayed content, blocked resources, and page changes. Abstract advertises custom CSS and delayed captures; confirm the exact controls in its live reference.

Cost and limits

Pricing, quotas, and rate limits were not verified in the reviewed Abstract sources. Check the current provider plan and usage terms before estimating cost. For a self-hosted Browsershot deployment, account for the operational resources needed to run browser processes; for either Spatie driver, verify any service charges and limits that apply to your chosen setup.

6. Troubleshooting

Symptom Likely cause What to do
401 or 403 response Missing or invalid credential, or authentication details differ from the assumed example. Check the current Abstract reference for authentication placement; verify the server environment value and refresh Laravel’s config cache if used.
400 response Missing or malformed request field, unsupported option, or incorrectly encoded URL. Compare the request with the current reference and send the URL as a query parameter through Laravel’s HTTP client rather than concatenating it manually.
Response is not a PNG The current response contract or format-selection parameter may differ from the assumption. Inspect status, content type, and documented response shape; use the verified PNG option and parse JSON if the API returns JSON.
Request times out The target page is slow, rendering is delayed, or the caller’s timeout is too short. Set a suitable bounded timeout, show a recoverable error, and consider an application queue for long captures.
Blank or incomplete capture Page content may depend on JavaScript, delayed loading, authentication, or resources unavailable to the renderer. Check the provider’s current wait and authentication options; do not assume support beyond documented behavior.
Works locally but fails after deployment Missing environment configuration, stale config cache, outbound network restrictions, or proxy/TLS differences. Check deployment configuration and outbound HTTPS access without printing secrets to logs.
Spatie Browsershot cannot launch Node.js or Chrome/Chromium is absent or not available to the application process. Install and configure the documented dependencies, or use the package’s Cloudflare driver if its account requirements fit.
Spatie installation rejects PHP or Laravel version The installed package release has stricter requirements than the application provides. Check the package’s current requirements page and choose a compatible package or application version.

7. Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server. One GET request returns an image or PDF; its API accepts the familiar screenshot parameter names used by other providers. See the ScreenshotNeo API documentation for 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 and removed before capture; 60+ known consent platforms, newsletter popups, and chat widgets can be removed, with each step independently switchable.
  • Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing. Responses identify the page verdict and billing status in headers.
  • An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients.
  • The free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 screenshots; every feature is available on every plan.

Sign up free for 1,000 screenshots a month, with no card required.

8. FAQ

Does Abstract provide a Laravel package?

The reviewed Abstract pages establish a REST API request pattern, not a Laravel-specific package. Laravel can call the endpoint with its HTTP client once you confirm the live API contract.

Can I send HTML instead of a public URL?

Abstract says its API accepts raw HTML, and that the source URL need not be publicly available when raw HTML is sent. That statement does not establish every private-site authentication flow.

Is Spatie’s screenshot package part of Abstract?

No. It is a separate Laravel package with its own drivers, setup, defaults, and version requirements.

Can I rely on the Abstract endpoint example as a complete integration?

No. It gives the endpoint and example query inputs, but the current parameter list and response contract should be verified against Abstract’s live API reference before production use.

Sources