Screenshot API for Java: HttpClient, Spring Boot & Async Capture

Capture screenshots, generate PDFs, and scrape web pages from Java applications using the built-in HttpClient. Works with Java 11+, Spring Boot, Quarkus, Micronaut, and plain Java — no additional dependencies required.

Start Free — 200 captures/moView Docs

Screenshot API for Java — HttpClient Quickstart

Java 11 introduced java.net.http.HttpClient — a modern HTTP client that handles HTTPS, async requests, and streaming responses out of the box. No Apache HttpClient or OkHttp required. Here is a complete method that returns screenshot data as a byte[]:

import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.Duration;

public class SnapApiClient {
    private final HttpClient client;
    private final String apiKey;

    public SnapApiClient(String apiKey) {
        this.apiKey = apiKey;
        this.client = HttpClient.newBuilder()
            .connectTimeout(Duration.ofSeconds(10))
            .build();
    }

    public byte[] screenshot(String url) throws Exception {
        String encodedUrl = URLEncoder.encode(url, StandardCharsets.UTF_8);
        String endpoint = "https://api.snapapi.pics/v1/screenshot"
            + "?url=" + encodedUrl
            + "&full_page=true&format=jpeg&block_ads=true";

        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create(endpoint))
            .header("X-Api-Key", apiKey)
            .timeout(Duration.ofSeconds(30))
            .GET()
            .build();

        HttpResponse<byte[]> response = client.send(
            request, HttpResponse.BodyHandlers.ofByteArray());

        if (response.statusCode() != 200) {
            throw new RuntimeException("SnapAPI error: " + response.statusCode());
        }
        return response.body();
    }
}

// Usage:
// SnapApiClient snap = new SnapApiClient(System.getenv("SNAPAPI_KEY"));
// byte[] jpeg = snap.screenshot("https://example.com");
// Files.write(Path.of("screenshot.jpg"), jpeg);

The HttpResponse.BodyHandlers.ofByteArray() handler accumulates the full binary response in memory. For large captures, use BodyHandlers.ofInputStream() to stream directly to a file without buffering.

Async Screenshot Capture with CompletableFuture

For non-blocking capture in reactive or async Java code, use sendAsync to get a CompletableFuture:

public CompletableFuture<byte[]> screenshotAsync(String url) {
    String encodedUrl = URLEncoder.encode(url, StandardCharsets.UTF_8);
    HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create("https://api.snapapi.pics/v1/screenshot?url=" + encodedUrl
            + "&full_page=true&format=jpeg"))
        .header("X-Api-Key", apiKey)
        .timeout(Duration.ofSeconds(30))
        .GET()
        .build();

    return client.sendAsync(request, HttpResponse.BodyHandlers.ofByteArray())
        .thenApply(response -> {
            if (response.statusCode() != 200) {
                throw new RuntimeException("SnapAPI " + response.statusCode());
            }
            return response.body();
        });
}

// Capture multiple URLs in parallel:
List<CompletableFuture<byte[]>> futures = urls.stream()
    .map(this::screenshotAsync)
    .collect(Collectors.toList());
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();

Parallel capture using CompletableFuture.allOf fires all requests concurrently and waits for the slowest one to complete. This is ideal for batch jobs where you need screenshots of many URLs and total wall-clock time matters.

Spring Boot Integration

In a Spring Boot application, register SnapApiClient as a @Service bean and inject it wherever screenshot capture is needed:

@Service
public class ScreenshotService {
    private final SnapApiClient snapApi;

    public ScreenshotService(@Value("${snapapi.key}") String apiKey) {
        this.snapApi = new SnapApiClient(apiKey);
    }

    @Async
    public CompletableFuture<byte[]> captureAsync(String url) {
        return snapApi.screenshotAsync(url);
    }
}

// In application.properties:
// snapapi.key=${SNAPAPI_KEY}

The @Async annotation runs the capture in Spring's task executor pool, freeing the web thread immediately. Enable async support with @EnableAsync on your configuration class. Return the CompletableFuture from your controller to let Spring MVC handle the async response automatically.

PDF Generation in Java

The PDF endpoint accepts a JSON body. Use HttpRequest.BodyPublishers.ofString with a JSON payload to convert any URL to a PDF:

public byte[] generatePdf(String url) throws Exception {
    String body = "{\"url\":\"" + url + "\",\"page_size\":\"A4\",\"print_background\":true}";

    HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create("https://api.snapapi.pics/v1/pdf"))
        .header("X-Api-Key", apiKey)
        .header("Content-Type", "application/json")
        .timeout(Duration.ofSeconds(60))
        .POST(HttpRequest.BodyPublishers.ofString(body))
        .build();

    HttpResponse<byte[]> response = client.send(
        request, HttpResponse.BodyHandlers.ofByteArray());
    if (response.statusCode() != 200) throw new RuntimeException("PDF error: " + response.statusCode());
    return response.body();
}

For production use, replace string concatenation with a JSON library like Jackson: new ObjectMapper().writeValueAsString(Map.of("url", url, "page_size", "A4")). This handles escaping edge cases correctly when URLs contain query parameters with special characters.

Error Handling and Retry Logic in Java

Production Java services need exponential backoff for transient API failures. Implement retry logic with a simple loop that respects the Retry-After header on 429 responses:

public byte[] screenshotWithRetry(String url, int maxAttempts) throws Exception {
    int attempt = 0;
    while (attempt < maxAttempts) {
        HttpResponse<byte[]> response = client.send(buildRequest(url),
            HttpResponse.BodyHandlers.ofByteArray());
        if (response.statusCode() == 200) return response.body();
        if (response.statusCode() == 429) {
            long retryAfter = response.headers().firstValueAsLong("Retry-After").orElse(5L);
            Thread.sleep(retryAfter * 1000L);
        } else if (response.statusCode() >= 500) {
            Thread.sleep((long) Math.pow(2, attempt) * 1000L);
        } else {
            throw new RuntimeException("Non-retryable error: " + response.statusCode());
        }
        attempt++;
    }
    throw new RuntimeException("Max retry attempts reached");
}

This pattern retries on 429 and 5xx responses, using the Retry-After header value when available and falling back to exponential backoff for server errors. 4xx errors other than 429 are not retried since they indicate a problem with the request itself.

Register at snapapi.pics for 200 free captures per month — no credit card required. The API works with Java 11 or later and requires zero additional dependencies when using the built-in HttpClient.

Web Scraping and Data Extraction in Java

SnapAPI's extract endpoint returns structured JSON that Java parses cleanly with Jackson or Gson. Pass a CSS selector and receive the matched text directly — no HTML parsing required on your end:

public String extractText(String url, String selector) throws Exception {
    String json = String.format(
        "{\"url\":\"%s\",\"selector\":\"%s\",\"wait_for\":\"%s\"}", url, selector, selector);

    HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create("https://api.snapapi.pics/v1/extract"))
        .header("X-Api-Key", apiKey)
        .header("Content-Type", "application/json")
        .timeout(Duration.ofSeconds(30))
        .POST(HttpRequest.BodyPublishers.ofString(json))
        .build();

    HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
    if (response.statusCode() != 200) throw new RuntimeException("Extract error: " + response.statusCode());

    // Parse with Jackson
    ObjectMapper mapper = new ObjectMapper();
    JsonNode root = mapper.readTree(response.body());
    return root.path("text").asText();
}

For production code, use Jackson's ObjectMapper to build the JSON payload rather than string formatting, which fails on URLs containing quotes or special characters. Create a record or POJO for the request body and serialize with mapper.writeValueAsString(requestObj).

Batch Scraping with Java ExecutorService

For processing large lists of URLs concurrently, submit tasks to a fixed thread pool via ExecutorService:

ExecutorService pool = Executors.newFixedThreadPool(5);
List<Future<String>> futures = new ArrayList<>();

for (String url : urlList) {
    futures.add(pool.submit(() -> extractText(url, ".product-price")));
}

for (int i = 0; i < futures.size(); i++) {
    System.out.println(urlList.get(i) + ": " + futures.get(i).get());
}
pool.shutdown();

A pool size of 5 threads is appropriate for the Starter plan rate limit. Increase to 20 for Pro accounts. futures.get(i).get() blocks until that specific task completes and rethrows any exception, making error handling straightforward.

Quarkus and Reactive Java Integration

For Quarkus applications using the reactive stack, the Mutiny-based Uni type wraps SnapAPI calls non-blocking. Use Quarkus REST Client to define a typed interface for the SnapAPI endpoints:

@RegisterRestClient(baseUri = "https://api.snapapi.pics")
@ClientHeaderParam(name = "X-Api-Key", value = "${snapapi.key}")
public interface SnapApiRestClient {

    @POST
    @Path("/v1/screenshot")
    @Consumes(MediaType.APPLICATION_JSON)
    Uni<Response> screenshot(ScreenshotRequest request);

    @POST
    @Path("/v1/extract")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    Uni<ExtractResponse> extract(ExtractRequest request);
}

Quarkus injects the API key from application properties via @ClientHeaderParam. The Uni return type integrates naturally with Mutiny pipelines, allowing you to chain transformations and error handling declaratively without blocking threads.

Pricing and SDK Options

SnapAPI offers 200 free captures per month — no credit card required. The Starter plan at $19 per month provides 5,000 captures per month, suitable for small monitoring pipelines and invoice PDF generation in production. The Pro plan at $79 per month covers 50,000 captures with higher concurrency limits, and the Business plan at $299 per month provides 500,000 captures for high-volume Java data pipelines.

Register at snapapi.pics, get your API key from the dashboard, and make your first Java screenshot call in under five minutes. All endpoints are thoroughly documented at snapapi.pics/docs.html with request and response schemas, error codes, and code examples for Java and seven other languages.

Java Screenshot API for Monitoring and Reporting

Java-based backend services commonly need screenshot capabilities for two categories of work: visual monitoring of deployed applications, and generating PDF or image reports from data dashboards. SnapAPI serves both use cases from the same endpoint with the same Java client code.

For visual regression monitoring, schedule a Spring @Scheduled task that captures key pages after each deployment. Compare the resulting images against baseline screenshots stored in S3 using a library like im4java or Thumbnailator. If the diff percentage exceeds a threshold, publish an alert to your team's Slack channel or PagerDuty incident feed.

For report generation in enterprise Java applications, the PDF endpoint replaces complex JasperReports or iText setups. Build report templates as standard HTML pages, populate them with data from your database using Thymeleaf or Freemarker, then pass the rendered URL to SnapAPI. The resulting PDF supports full CSS, Google Fonts, charts rendered with Chart.js or D3, and custom page sizes — all without touching a PDF library's API.

Every Java plan includes access to all six API endpoints: screenshot, scrape, extract, PDF, video, and AI page analysis. Sign up at snapapi.pics, add your key to your Java environment variables, and make your first capture in under five minutes.

java screenshot api spring boot httpClient concurrent async pdf generation enterprise
java api screenshot capture web page image full page viewport device
java screenshot api httpclient async pdf extract scrape
java spring boot quarkus screenshot
rest api
java

SnapAPI supports Java 11 through Java 21 LTS including virtual threads introduced in Java 21 Project Loom enabling extremely high concurrency with minimal memory overhead per request thread.