Capture screenshots and generate PDFs from any C#, ASP.NET Core, or .NET application with a single HTTP call.
No Playwright NuGet packages, no Chromium to install — just HttpClient and a SnapAPI key.
Quick Start with HttpClient
using System.Net.Http.Json;
var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-Api-Key", Environment.GetEnvironmentVariable("SNAPAPI_KEY"));
var response = await client.PostAsJsonAsync("https://api.snapapi.pics/v1/screenshot", new {
url = "https://example.com",
fullPage = true,
width = 1280,
height = 800,
format = "png",
blockAds = true
});
var result = await response.Content.ReadFromJsonAsync<ScreenshotResult>();
Console.WriteLine(result?.Url);
record ScreenshotResult(string Url, int Width, int Height, long Size);
ASP.NET Core Controller
[ApiController]
[Route("api/[controller]")]
public class ScreenshotController : ControllerBase
{
private readonly IHttpClientFactory _httpClientFactory;
private readonly IConfiguration _config;
public ScreenshotController(IHttpClientFactory factory, IConfiguration config)
{
_httpClientFactory = factory;
_config = config;
}
[HttpPost]
public async Task<IActionResult> Capture([FromBody] CaptureRequest req)
{
var client = _httpClientFactory.CreateClient();
client.DefaultRequestHeaders.Add("X-Api-Key", _config["SnapAPI:Key"]);
var response = await client.PostAsJsonAsync(
"https://api.snapapi.pics/v1/screenshot",
new { url = req.Url, fullPage = req.FullPage, width = 1280 }
);
if (!response.IsSuccessStatusCode)
return StatusCode((int)response.StatusCode);
var result = await response.Content.ReadFromJsonAsync<ScreenshotResult>();
return Ok(result);
}
}
public record CaptureRequest(string Url, bool FullPage = false);
public record ScreenshotResult(string Url, int Width, int Height);
Typed Client with DI
// Services/SnapApiClient.cs
public class SnapApiClient
{
private readonly HttpClient _client;
public SnapApiClient(HttpClient client, IConfiguration config)
{
_client = client;
_client.BaseAddress = new Uri("https://api.snapapi.pics/");
_client.DefaultRequestHeaders.Add("X-Api-Key", config["SnapAPI:Key"]);
}
public async Task<string?> ScreenshotAsync(string url, bool fullPage = false)
{
var res = await _client.PostAsJsonAsync("v1/screenshot",
new { url, fullPage, blockAds = true });
res.EnsureSuccessStatusCode();
var data = await res.Content.ReadFromJsonAsync<ScreenshotResult>();
return data?.Url;
}
public async Task<string?> PdfAsync(string url, string format = "A4")
{
var res = await _client.PostAsJsonAsync("v1/pdf",
new { url, format, printBackground = true });
res.EnsureSuccessStatusCode();
var data = await res.Content.ReadFromJsonAsync<PdfResult>();
return data?.Url;
}
record ScreenshotResult(string Url);
record PdfResult(string Url, string Base64);
}
// Program.cs
builder.Services.AddHttpClient<SnapApiClient>();
Pricing
Free: 200/mo. Starter $19/mo: 5K. Pro $79/mo: 50K. Business $299/mo: 500K.
Get your free API key.
C# Screenshot API — Full Reference
All Request Parameters
Parameter
Type
Default
Description
url
string
required
URL to capture
fullPage
bool
false
Capture full scrollable page
width
int
1280
Viewport width in pixels
height
int
800
Viewport height in pixels
format
string
png
png, jpeg, webp
device
string
—
Device preset (iPhone 15 Pro, iPad Pro, etc.)
blockAds
bool
false
Block ads and trackers
waitUntil
string
networkidle
load, domcontentloaded, networkidle
delay
int
0
Wait ms after load before capture
customCss
string
—
CSS injected before capture
Use Cases in .NET
Invoice PDF generation: In ASP.NET Core, render your Razor invoice view to a URL, capture it with SnapAPI's PDF endpoint, and return a FileResult. No wkhtmltopdf binary, no SelectPdf license — just an HTTP call from your service layer.
Link preview thumbnails: When users paste URLs in your Blazor or MVC application, call SnapAPI from a background job and store the thumbnail URL alongside the user-submitted link. Display the preview in real time using SignalR to push the result when ready.
Visual regression in CI: Add SnapAPI calls to your xUnit or NUnit test suite. Capture pages against a running test server, compare pixel hashes against baseline images stored in your test project, and fail the build on unexpected diffs.
OG image generation for Razor Pages: On page creation, queue a background job (Hangfire or .NET Background Service) that calls SnapAPI with the rendered page URL and writes the resulting PNG URL back to the database. The meta tag is then served from the database value.
Background Service Pattern
// Hosted background service using Channel for queued jobs
public class ScreenshotService : BackgroundService
{
private readonly Channel<ScreenshotJob> _queue = Channel.CreateUnbounded<ScreenshotJob>();
private readonly SnapApiClient _api;
private readonly AppDbContext _db;
public async Task EnqueueAsync(ScreenshotJob job) =>
await _queue.Writer.WriteAsync(job);
protected override async Task ExecuteAsync(CancellationToken ct)
{
await foreach (var job in _queue.Reader.ReadAllAsync(ct))
{
var url = await _api.ScreenshotAsync(job.TargetUrl);
var item = await _db.Links.FindAsync(job.LinkId);
if (item != null) { item.ThumbnailUrl = url; await _db.SaveChangesAsync(); }
}
}
}
Why SnapAPI Over Playwright.NET?
Playwright.NET works but adds Chromium to your deployment. On Azure App Service, this means a custom Docker image. On AWS Lambda, the zip package exceeds the 250MB unzipped limit. On IIS-hosted servers, Chromium needs specific sandbox permissions. SnapAPI removes all of this — your ASP.NET app stays a standard .NET binary, deployable anywhere.
Free plan: 200/mo. Starter $19/mo: 5K. Pro $79/mo: 50K. Get your free key.
C# vs Other .NET PDF Libraries
The .NET ecosystem has several PDF generation options. SelectPdf and IronPDF are commercial libraries that bundle their own rendering engine — they work but require per-server licensing fees ($400-800/year) and produce inconsistent results for modern CSS. Playwright.NET uses real Chromium but adds a 300MB+ dependency to your deployment. SnapAPI is an HTTP call — no binaries, no licenses, no deployment complications.
For screenshot capture specifically, Puppeteer Sharp (C# Puppeteer port) and Playwright.NET both work but require Chromium installed on the target machine. This causes issues on Azure App Service (needs Docker), AWS Lambda (zip size limit), and IIS-hosted servers (sandbox permissions). SnapAPI moves Chromium to the API side so your .NET application remains a standard binary deployable anywhere.
The X-Api-Key authentication header works with any .NET HTTP client: HttpClient, RestSharp, Refit, or Flurl. Store the key in appsettings.json under an SnapAPI section and inject it via IConfiguration — the standard .NET pattern for API credentials.
// Generate invoice PDF and return as file download
[HttpGet("invoice/{id}/pdf")]
public async Task<IActionResult> DownloadInvoice(int id)
{
var invoice = await _db.Invoices.FindAsync(id);
if (invoice == null) return NotFound();
// Build signed URL to your Razor invoice page
var token = _tokenService.GenerateSignedToken(id, TimeSpan.FromMinutes(5));
var invoiceUrl = Url.Action("View", "Invoice", new { id, token },
Request.Scheme, Request.Host.Value);
var client = _httpClientFactory.CreateClient();
client.DefaultRequestHeaders.Add("X-Api-Key",
_config["SnapAPI:Key"]);
var res = await client.PostAsJsonAsync("https://api.snapapi.pics/v1/pdf",
new {
url = invoiceUrl,
format = "A4",
marginTop = "15mm",
marginBottom = "15mm",
printBackground = true
});
var data = await res.Content.ReadFromJsonAsync<PdfResult>();
var bytes = Convert.FromBase64String(data!.Base64);
return File(bytes, "application/pdf",
$"Invoice-{invoice.Number}.pdf");
}
record PdfResult(string Url, string Base64);
Configuring in Program.cs
// Program.cs — register typed client
builder.Services.AddHttpClient<SnapApiClient>(client =>
{
client.BaseAddress = new Uri("https://api.snapapi.pics/");
client.DefaultRequestHeaders.Add(
"X-Api-Key",
builder.Configuration["SnapAPI:Key"]);
client.Timeout = TimeSpan.FromSeconds(30);
});
// appsettings.json
// {
// "SnapAPI": {
// "Key": "sk_live_your_key_here"
// }
// }
// For production: store in Azure Key Vault, AWS Secrets Manager,
// or environment variables via dotnet user-secrets in development
Frequently Asked Questions
Does SnapAPI work with Blazor? Yes. Calls go server-side in Blazor Server or via an API endpoint in Blazor WebAssembly. The API key never reaches the browser.
What about .NET MAUI or mobile? Route calls through your backend — never put API keys in mobile apps. Your MAUI app calls your ASP.NET endpoint which forwards to SnapAPI.
Can I use it in Azure Functions? Yes. HttpClient works fine in isolated worker Azure Functions. Use dependency injection to register the client and inject your key from Azure Key Vault or App Settings.
Is there a NuGet package? Not yet — the typed client pattern above covers 95% of use cases with no additional dependencies. A NuGet wrapper is on the roadmap.
Error Handling and Retry Logic in C#
Production .NET applications demand robust error handling. SnapAPI returns standard HTTP status codes: 200 for success, 400 for bad parameters, 401 for invalid API keys, 429 for rate limits, and 5xx for server-side issues. Implementing retry logic with exponential backoff is straightforward using Polly, the resilience library for .NET.
// Install: dotnet add package Polly.Extensions.Http
using Polly;
using Polly.Extensions.Http;
// In Program.cs
var retryPolicy = HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(r => r.StatusCode == System.Net.HttpStatusCode.TooManyRequests)
.WaitAndRetryAsync(3, attempt =>
TimeSpan.FromSeconds(Math.Pow(2, attempt)));
builder.Services.AddHttpClient<SnapApiService>()
.AddPolicyHandler(retryPolicy);
For ASP.NET Core MVC projects, inject a typed SnapApiService into controllers rather than using raw HttpClient. This improves testability: you can mock the service interface in unit tests using xUnit and Moq without making real HTTP calls during CI runs.
Logging API Responses
Integrate with Microsoft.Extensions.Logging to trace API calls in production. Log the request URL, response status, and elapsed time. For distributed tracing, pass a correlation ID via a custom request header to link browser snapshot requests with application traces in Application Insights, Datadog, or OpenTelemetry.
Developers on .NET 8 or later can leverage primary constructors and collection expressions for leaner service classes. SnapAPI's C# integration needs no third-party SDK: the entire client is a handful of DTOs and a single async method, keeping your dependency graph minimal and your NuGet restore times fast.
SnapAPI is compatible with all .NET runtimes including .NET Framework 4.8, .NET Core 3.1, and all modern .NET versions through .NET 9. The API surface uses standard REST conventions with JSON responses, so any HTTP client that runs on .NET will work without modification.