Capture screenshots, generate PDFs, and extract structured data from .NET using SnapAPI. Works with ASP.NET Core, Blazor Server, Worker Services, and console applications targeting .NET 6, 7, 8, and 9.
// dotnet add package Microsoft.Extensions.Http
// Program.cs — register typed client
builder.Services.AddHttpClient<SnapApiService>(client => {
client.BaseAddress = new Uri("https://api.snapapi.pics");
client.DefaultRequestHeaders.Add("X-Api-Key", builder.Configuration["SnapApi:Key"]);
client.Timeout = TimeSpan.FromSeconds(60);
});
public class SnapApiService
{
private readonly HttpClient _http;
public SnapApiService(HttpClient http) => _http = http;
public async Task<byte[]> ScreenshotAsync(string url, bool fullPage = true)
{
var payload = JsonSerializer.Serialize(new { url, full_page = fullPage, format = "png" });
var content = new StringContent(payload, Encoding.UTF8, "application/json");
var response = await _http.PostAsync("/v1/screenshot", content);
response.EnsureSuccessStatusCode();
var json = await JsonSerializer.DeserializeAsync<JsonElement>(
await response.Content.ReadAsStreamAsync());
var b64 = json.GetProperty("image").GetString()!;
return Convert.FromBase64String(b64);
}
public async Task<byte[]> PdfAsync(string url, string format = "A4")
{
var payload = JsonSerializer.Serialize(new { url, format, print_background = true });
var content = new StringContent(payload, Encoding.UTF8, "application/json");
var response = await _http.PostAsync("/v1/pdf", content);
response.EnsureSuccessStatusCode();
var json = await JsonSerializer.DeserializeAsync<JsonElement>(
await response.Content.ReadAsStreamAsync());
return Convert.FromBase64String(json.GetProperty("pdf").GetString()!);
}
}
Inject SnapApiService into controllers, Razor Pages, or Blazor components via constructor injection. The typed client pattern ensures the HttpClient is properly pooled and disposed — avoiding the classic socket exhaustion issue that occurs when instantiating HttpClient directly.
Refit generates a type-safe REST client from an interface at compile time. Define the SnapAPI interface and register it with AddRefitClient — no manual HTTP code required.
// dotnet add package Refit.HttpClientFactory
[Headers("Content-Type: application/json")]
public interface ISnapApi
{
[Post("/v1/screenshot")]
Task<ScreenshotResponse> ScreenshotAsync([Body] ScreenshotRequest request);
[Post("/v1/pdf")]
Task<PdfResponse> PdfAsync([Body] PdfRequest request);
}
// In Program.cs
builder.Services
.AddRefitClient<ISnapApi>()
.ConfigureHttpClient(c => {
c.BaseAddress = new Uri("https://api.snapapi.pics");
c.DefaultRequestHeaders.Add("X-Api-Key", builder.Configuration["SnapApi:Key"]);
});
Add resilience with Polly — the standard fault-tolerance library for .NET. Configure an exponential backoff retry that handles transient HTTP errors and 429 rate-limit responses.
// dotnet add package Microsoft.Extensions.Http.Polly
var retryPolicy = HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(r => r.StatusCode == HttpStatusCode.TooManyRequests)
.WaitAndRetryAsync(3, attempt =>
TimeSpan.FromSeconds(Math.Pow(2, attempt)));
builder.Services.AddHttpClient<SnapApiService>()
.AddPolicyHandler(retryPolicy);
The policy retries 3 times with 2s, 4s, and 8s delays. Combine with a CircuitBreaker policy to prevent cascade failures when SnapAPI is temporarily unreachable.
Generate PDFs on demand from your existing HTML views. Inject SnapApiService into your controller, build the invoice URL with a signed token for authenticated access, and stream the PDF response to the browser.
[HttpGet("invoices/{id}/pdf")]
public async Task<IActionResult> DownloadPdf(int id)
{
var invoice = await _db.Invoices.FindAsync(id);
if (invoice is null) return NotFound();
var token = _tokens.GenerateSignedToken(invoice.Id, expiry: TimeSpan.FromMinutes(5));
var url = Url.Action("Invoice", "Render", new { id, token }, Request.Scheme, Request.Host.Value);
var pdfBytes = await _snapApi.PdfAsync(url!, format: "A4");
return File(pdfBytes, "application/pdf", $"invoice-{invoice.Number}.pdf");
}The RenderController/Invoice action renders a minimal Razor view styled for print — no navigation, no sidebar, just the invoice content with your company branding. SnapAPI loads this URL in Chromium, applies print media CSS, and returns a clean PDF.
For batch PDF generation — monthly invoices, report exports, certificate issuance — use Hangfire to enqueue screenshot jobs in the background. The SnapApiService is injectable into Hangfire job classes via the built-in DI integration. Configure Hangfire with SQL Server or Redis persistence so jobs survive application restarts.
Store generated PDFs in Azure Blob Storage or AWS S3. Use a pre-signed URL with a short TTL to deliver the file to the end user — avoiding the need to stream large files through your ASP.NET process.
Blazor Server components can call SnapApiService directly from component code. Inject the service via @inject, call ScreenshotAsync in an async event handler, and bind the result to an img tag using a data URI. This pattern works for live preview features — show the user a screenshot of a URL they entered without leaving the Blazor app.
@inject SnapApiService SnapApi
<input @bind="url" placeholder="https://example.com" />
<button @onclick="Capture">Capture</button>
@if (previewDataUri != null)
{
<img src="@previewDataUri" style="max-width:100%;border-radius:8px" />
}
@code {
string url = "";
string? previewDataUri;
async Task Capture()
{
var bytes = await SnapApi.ScreenshotAsync(url);
previewDataUri = $"data:image/png;base64,{Convert.ToBase64String(bytes)}";
}
}.NET MAUI apps can also integrate with SnapAPI for generating PDF reports that users can share from mobile devices. Call the PDF endpoint via HttpClient in your MAUI app's service layer, save the result to the device's document directory using FileSystem.AppDataDirectory, and open it with the native PDF viewer using Launcher.OpenAsync.
Sign up at snapapi.pics for 200 free captures per month. No credit card required. The NuGet package SnapAPI.Client is available for .NET 6+.
Test your .NET SnapAPI integration without making real HTTP calls. Define an ISnapApiService interface and mock it in tests using Moq or NSubstitute.
public interface ISnapApiService
{
Task<byte[]> ScreenshotAsync(string url, bool fullPage = true);
Task<byte[]> PdfAsync(string url, string format = "A4");
}
// In your test
var mockSnap = new Mock<ISnapApiService>();
mockSnap.Setup(s => s.ScreenshotAsync(It.IsAny<string>(), It.IsAny<bool>()))
.ReturnsAsync(File.ReadAllBytes("fixtures/sample.png"));
var controller = new CaptureController(mockSnap.Object);
var result = await controller.Capture("https://example.com");
Assert.IsType<FileContentResult>(result);| Plan | Price | Monthly Calls | Best For |
|---|---|---|---|
| Free | $0 | 200 | Evaluation and prototyping |
| Starter | $19/mo | 5,000 | Small production apps |
| Pro | $79/mo | 50,000 | Growing SaaS products |
| Business | $299/mo | 500,000 | Enterprise and high-volume |
| Parameter | C# Type | Default | Description |
|---|---|---|---|
url | string | required | Page URL to capture |
format | string | "png" | Output format: png, jpeg, webp |
full_page | bool | false | Capture full scrollable page |
width | int | 1280 | Viewport width in pixels |
height | int | 720 | Viewport height in pixels |
delay | int | 0 | Milliseconds to wait before capture |
device | string? | null | Device preset for mobile emulation |
The .NET SDK provides strongly-typed ScreenshotRequest and ScreenshotResponse records with camelCase/snake_case JSON property naming handled automatically via JsonPropertyName attributes. Add the SDK via NuGet: dotnet add package SnapAPI.Client — supports .NET 6, 7, 8, and 9.
Source-generated JSON serialization (System.Text.Json source generators) is supported for AOT-compiled .NET 8 applications. The SDK includes a SnapApiJsonContext with all required type registrations for trimming-safe serialization.
A .NET Worker Service (Background Service) is ideal for processing screenshot jobs from a queue. Add a hosted service that dequeues URLs from Azure Service Bus, AWS SQS, or a local Channel, captures each screenshot using SnapApiService, and uploads the result to blob storage. The Worker Service runs continuously as a background process alongside your ASP.NET Core application or as a standalone deployment.
public class ScreenshotWorker : BackgroundService
{
private readonly ISnapApiService _snap;
private readonly IBlobStorage _storage;
private readonly IJobQueue _queue;
protected override async Task ExecuteAsync(CancellationToken ct)
{
await foreach (var job in _queue.DequeueAllAsync(ct))
{
try {
var bytes = await _snap.ScreenshotAsync(job.Url);
await _storage.UploadAsync($"screenshots/{job.Id}.png", bytes);
await _queue.CompleteAsync(job);
} catch (Exception ex) {
await _queue.AbandonAsync(job, ex);
}
}
}
}Configure the Worker Service to process a maximum of 5 concurrent jobs using SemaphoreSlim. This prevents overwhelming SnapAPI with too many concurrent requests while keeping throughput high. On the Pro plan (50K calls/month, up to 300 req/min), 5 concurrent workers can sustain approximately 150-200 screenshots per minute in steady state.
Add distributed tracing to your SnapAPI calls using OpenTelemetry. The HttpClient instrumentation package automatically traces all outbound HTTP requests, including SnapAPI calls, and exports spans to Jaeger, Zipkin, Azure Monitor, or Datadog. Set a correlation ID header on each SnapAPI request to correlate screenshot captures with the application traces that triggered them.
For structured logging, use Serilog or Microsoft.Extensions.Logging to log the URL, response status, elapsed time, and image size for every SnapAPI call. These logs are invaluable for debugging slow captures, identifying problematic URLs, and tracking quota consumption trends over time.
Sign up at snapapi.pics — free tier includes 200 captures per month with no credit card required. The .NET SDK (SnapAPI.Client on NuGet) supports .NET 6 through .NET 9, includes source-generated JSON serialization for AOT compilation, and has zero required third-party dependencies.
Packaging your SnapAPI integration for deployment is straightforward. Add your API key to environment variables or Azure Key Vault rather than appsettings.json to keep secrets out of source control. In GitHub Actions, inject it via a repository secret: SNAPAPI_KEY: ${{ secrets.SNAPAPI_KEY }}. For Azure App Service, set it under Configuration then Application Settings as SnapApi__ApiKey following the .NET double-underscore convention for nested config sections.
If you are using Docker, a multi-stage Dockerfile keeps the final image lean. Build with the .NET SDK image, publish to a self-contained binary, and copy to the ASP.NET runtime image. The resulting container needs no additional browser binaries since SnapAPI handles all rendering remotely via its cloud infrastructure.
Ready to start? Sign up at snapapi.pics for 200 free captures per month, no credit card required. Your first screenshot API call in .NET takes under five minutes from registration to response. Browse the full API reference at snapapi.pics/docs.html and explore the C# and .NET code samples for every endpoint.