ScreenshotFreeAPI 1.0.0

dotnet add package ScreenshotFreeAPI --version 1.0.0
                    
NuGet\Install-Package ScreenshotFreeAPI -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ScreenshotFreeAPI" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ScreenshotFreeAPI" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="ScreenshotFreeAPI" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ScreenshotFreeAPI --version 1.0.0
                    
#r "nuget: ScreenshotFreeAPI, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package ScreenshotFreeAPI@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=ScreenshotFreeAPI&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=ScreenshotFreeAPI&version=1.0.0
                    
Install as a Cake Tool

ScreenshotFreeAPI — Official .NET SDK

The official .NET 6+ SDK for ScreenshotFreeAPI — screenshot-as-a-service. Capture any website, mobile app store listing, or raw HTML to a pixel-perfect image or PDF with a single async call.

Installation

dotnet add package ScreenshotFreeAPI

Quick Start

using ScreenshotFreeAPI;

// Create a client (reuse this instance across your app)
using var client = new ScreenshotFreeAPIClient("sfa_your_api_key");

// Capture a screenshot and wait for the result
var result = await client.CaptureAsync("https://stripe.com");

Console.WriteLine(result.Screenshots[0].Url);
// → https://s3.amazonaws.com/...?X-Amz-Expires=900

All Screenshot Types

Web Screenshots

// Simple capture
var result = await client.Screenshots.WebAndWaitAsync(
    new WebScreenshotOptions("https://stripe.com/pricing"));

// Full-page PDF
var result = await client.Screenshots.WebAndWaitAsync(
    new WebScreenshotOptions("https://example.com")
    {
        FullPage = true,
        Format = "pdf",
    });

// AI-targeted element (Claude finds "the pricing table" and crops to it)
var result = await client.Screenshots.WebAndWaitAsync(
    new WebScreenshotOptions("https://stripe.com/pricing")
    {
        Description = "the pricing comparison table",
    });

// CSS selector targeting
var result = await client.Screenshots.WebAndWaitAsync(
    new WebScreenshotOptions("https://example.com")
    {
        Element = ".hero-section",
        Dimensions = new Dimensions(1440, 900),
    });

// Full options
var result = await client.Screenshots.WebAndWaitAsync(
    new WebScreenshotOptions("https://stripe.com/pricing")
    {
        Dimensions = new Dimensions(1440, 900),
        FullPage = false,
        Format = "png",
        BlockAds = true,
        AcceptCookies = true,
        Stealth = true,
        ProxyLocation = "us-east",
        BypassCache = true,
        WebhookUrl = "https://your-app.com/hooks/screenshot-events",
        Storage = new CustomStorage(
            Bucket: "my-bucket",
            Region: "us-east-1",
            AccessKeyId: "AKIA...",
            SecretAccessKey: "secret"),
    });

Mobile App Screenshots

// iOS + Android store listing screenshots
var result = await client.Screenshots.MobileAndWaitAsync(
    new MobileScreenshotOptions
    {
        AppName = "Instagram",
        Platform = "both",
        IncludeStoreListing = true,
    });

// By bundle ID with device emulation
var result = await client.Screenshots.MobileAndWaitAsync(
    new MobileScreenshotOptions
    {
        BundleId = "com.instagram.android",
        Platform = "android",
        DeviceEmulation = "Pixel 5",
    });

HTML Rendering

// Render a raw HTML string (requires STARTER plan)
var result = await client.Screenshots.HtmlAndWaitAsync(
    new HtmlScreenshotOptions("<h1 style='color:red'>Hello!</h1>")
    {
        Css = "body { font-family: sans-serif; }",
        Dimensions = new Dimensions(800, 600),
        Format = "png",
    });

Manual Polling with CancellationToken

// Enqueue and get back a job ID immediately (HTTP 202)
var accepted = await client.Screenshots.WebAsync(
    new WebScreenshotOptions("https://example.com"));

Console.WriteLine($"Job enqueued: {accepted.JobId}");

// Poll until done with a 60-second timeout and progress logging
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(60));

var result = await client.Screenshots.WaitAsync(
    accepted.JobId,
    new WaitOptions(
        PollInterval: TimeSpan.FromSeconds(3),
        Timeout: TimeSpan.FromSeconds(60),
        OnProgress: status =>
            Console.WriteLine($"Status: {status.Status} ({status.Progress}%)")),
    cts.Token);

Console.WriteLine($"Done! {result.Screenshots.Count} screenshot(s).");

ASP.NET Core DI Setup with IHttpClientFactory

// Program.cs
using ScreenshotFreeAPI;

// Register a named HttpClient for connection-pool reuse
builder.Services.AddHttpClient("screenshotfreeapi", c =>
{
    c.BaseAddress = new Uri("https://api.screenshotfreeapi.com");
    c.Timeout = TimeSpan.FromSeconds(30);
});

// Register ScreenshotFreeAPIClient as a singleton
builder.Services.AddSingleton(sp =>
{
    var factory = sp.GetRequiredService<IHttpClientFactory>();
    var config = sp.GetRequiredService<IConfiguration>();
    return new ScreenshotFreeAPIClient(
        factory.CreateClient("screenshotfreeapi"),
        config["ScreenshotFreeAPI:ApiKey"]!);
});
// appsettings.json
{
  "ScreenshotFreeAPI": {
    "ApiKey": "sfa_your_api_key"
  }
}
// A controller using DI
[ApiController]
[Route("api/screenshots")]
public class ScreenshotController : ControllerBase
{
    private readonly ScreenshotFreeAPIClient _client;

    public ScreenshotController(ScreenshotFreeAPIClient client) => _client = client;

    [HttpPost]
    public async Task<IActionResult> Capture([FromBody] CaptureRequest req)
    {
        var result = await _client.CaptureAsync(req.Url);
        return Ok(new { url = result.Screenshots[0].Url });
    }
}

Webhook Verification in ASP.NET Core

[ApiController]
[Route("hooks")]
public class WebhookController : ControllerBase
{
    [HttpPost("screenshot")]
    public async Task<IActionResult> Receive(
        [FromHeader(Name = "X-ScreenshotFree-Signature")] string signature)
    {
        // Read the raw body — do NOT use [FromBody] as that alters the stream
        using var reader = new StreamReader(Request.Body, Encoding.UTF8);
        var rawBody = await reader.ReadToEndAsync();

        var secret = "your_webhook_signing_secret";

        if (!Webhooks.VerifySignature(rawBody, signature, secret))
            return Unauthorized("Invalid webhook signature.");

        // Deserialise and handle the event
        var payload = System.Text.Json.JsonSerializer.Deserialize<WebhookPayload>(rawBody);
        // ... process payload ...

        return Ok();
    }
}

Error Handling

using ScreenshotFreeAPI.Exceptions;

try
{
    var result = await client.CaptureAsync("https://example.com");
    Console.WriteLine(result.Screenshots[0].Url);
}
catch (AuthenticationException ex)
{
    // HTTP 401 — invalid or missing API key
    Console.Error.WriteLine($"Auth error: {ex.Message}");
}
catch (PaymentRequiredException ex)
{
    // HTTP 402 — subscription cancelled or payment overdue
    Console.Error.WriteLine($"Payment required: {ex.Message}");
}
catch (ForbiddenException ex)
{
    // HTTP 403 — key revoked or account suspended
    Console.Error.WriteLine($"Forbidden: {ex.Message}");
}
catch (NotFoundException ex)
{
    // HTTP 404 — job or resource not found
    Console.Error.WriteLine($"Not found: {ex.Message}");
}
catch (ValidationException ex)
{
    // HTTP 400 — request body failed validation
    Console.Error.WriteLine($"Validation error: {ex.Message}");
    if (ex.Details is not null)
        foreach (var detail in ex.Details)
            Console.Error.WriteLine($"  - {detail}");
}
catch (RateLimitException ex)
{
    // HTTP 429 — per-minute rate limit exceeded
    Console.Error.WriteLine($"Rate limited. Retry after {ex.RetryAfter}s.");
    await Task.Delay(TimeSpan.FromSeconds(ex.RetryAfter));
}
catch (QuotaExceededException ex)
{
    // HTTP 429 — monthly screenshot quota exhausted
    Console.Error.WriteLine($"Quota exceeded: {ex.Message}");
}
catch (JobFailedException ex)
{
    // Worker reported the job as failed
    Console.Error.WriteLine($"Job {ex.JobId} failed: {ex.Reason}");
}
catch (JobTimeoutException ex)
{
    // Polling timed out waiting for completion
    Console.Error.WriteLine($"Job {ex.JobId} timed out after {ex.Timeout.TotalSeconds}s.");
}
catch (ScreenshotFreeAPIException ex)
{
    // Catch-all for any other ScreenshotFreeAPI error
    Console.Error.WriteLine($"API error {ex.StatusCode} [{ex.ErrorCode}]: {ex.Message}");
}

Auth and Billing (JWT)

Management endpoints (billing, workspaces, monitors) require a JWT token obtained by logging in:

// Obtain a JWT
var token = await client.Auth.TokenAsync(
    new TokenOptions("you@example.com", "your_password"));

// Get current plan + usage
var plan = await client.Billing.GetPlanAsync(token.Token);
Console.WriteLine($"Plan: {plan.Plan}, {plan.ScreenshotsRemaining} screenshots remaining");

// Get 30-day usage history
var usage = await client.Billing.GetUsageAsync(token.Token);
foreach (var day in usage)
    Console.WriteLine($"{day.Date}: {day.Count} screenshots");

// Upgrade to GROWTH plan
var upgrade = await client.Billing.UpgradeAsync(
    token.Token,
    new UpgradeOptions("GROWTH"));

if (upgrade.PaymentLink is not null)
    Console.WriteLine($"Complete payment at: {upgrade.PaymentLink}");

Workspaces

var token = await client.Auth.TokenAsync(new TokenOptions("you@example.com", "pass"));

// Create a workspace
var ws = await client.Workspaces.CreateAsync(token.Token, new CreateWorkspaceOptions("My Team"));

// Invite a colleague
await client.Workspaces.InviteMemberAsync(
    token.Token, ws.WorkspaceId,
    new InviteMemberOptions("colleague@example.com", Role: "member"));

// List all workspaces
var workspaces = await client.Workspaces.ListAsync(token.Token);

App Monitors

var token = await client.Auth.TokenAsync(new TokenOptions("you@example.com", "pass"));

// Create a daily monitor
var monitor = await client.Monitors.CreateAsync(token.Token,
    new CreateMonitorOptions(
        AppId: "com.instagram.android",
        Platform: "android",
        Schedule: "0 9 * * *")   // daily at 09:00 UTC
    {
        WebhookUrl = "https://your-app.com/hooks/monitor",
    });

// Get run history
var history = await client.Monitors.GetHistoryAsync(token.Token, monitor.MonitorId);
foreach (var run in history)
    Console.WriteLine($"{run.CapturedAt}: changed={run.Changed}, diff={run.DiffRatio:P1}");

Configuration Reference

Option Default Description
apiKey (required) Your API key starting with sfa_
baseUrl https://api.screenshotfreeapi.com Override for local dev/testing
timeout 30 seconds Per-request HTTP timeout
maxRetries 3 Retries on 429/5xx (backoff: 1s, 2s, 4s)
WaitOptions.PollInterval 2 seconds How often to poll job status
WaitOptions.Timeout 120 seconds Max time to wait for job completion

Requirements

  • .NET 6.0 or later
  • No external NuGet dependencies (uses System.Text.Json and System.Net.Http built into the runtime)
Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net6.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 127 6/20/2026