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" />
<PackageReference Include="ScreenshotFreeAPI" />
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
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#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
#tool nuget:?package=ScreenshotFreeAPI&version=1.0.0
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
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.JsonandSystem.Net.Httpbuilt into the runtime)
| Product | Versions 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 |