Screenshot -- C# / .NET Code Examples
HTTP-based examples for integrating the Nodium Screenshot API with C# usingHttpClientandSystem.Text.Json. Targets .NET 6+ and ASP.NET Core.
Basic Screenshot (GET)
The simplest way to capture a screenshot using query parameters.
csharp
using System.Web;
const string ApiKey = "YOUR_API_KEY";
const string BaseUrl = "https://api.nodium.io/api/v1/screenshot/take";
var query = HttpUtility.ParseQueryString(string.Empty);
query["url"] = "https://example.com";
query["format"] = "png";
query["viewport_width"] = "1280";
query["viewport_height"] = "1024";
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-Access-Key", ApiKey);
var response = await client.GetAsync($"{BaseUrl}?{query}");
if (response.IsSuccessStatusCode)
{
var bytes = await response.Content.ReadAsByteArrayAsync();
await File.WriteAllBytesAsync("screenshot.png", bytes);
Console.WriteLine($"Screenshot saved ({bytes.Length} bytes)");
}
else
{
var error = await response.Content.ReadAsStringAsync();
Console.Error.WriteLine($"API error ({(int)response.StatusCode}): {error}");
}POST with JSON Body
Use POST for complex configurations with a JSON request body.
csharp
using System.Net.Http.Json;
using System.Text.Json;
using System.Text.Json.Serialization;
const string ApiKey = "YOUR_API_KEY";
const string BaseUrl = "https://api.nodium.io/api/v1/screenshot/take";
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-Access-Key", ApiKey);
client.Timeout = TimeSpan.FromSeconds(60);
var payload = new
{
url = "https://example.com",
format = "png",
viewport_width = 1440,
viewport_height = 900,
full_page = true,
image_quality = 90,
block_ads = true,
delay = 1000
};
var response = await client.PostAsJsonAsync(BaseUrl, payload);
if (response.IsSuccessStatusCode)
{
var bytes = await response.Content.ReadAsByteArrayAsync();
await File.WriteAllBytesAsync("screenshot.png", bytes);
Console.WriteLine("Screenshot saved");
if (response.Headers.TryGetValues("x-nodium-rendering-seconds", out var renderTime))
Console.WriteLine($"Rendering time: {renderTime.First()}s");
if (response.Headers.TryGetValues("x-nodium-size-bytes", out var sizeBytes))
Console.WriteLine($"File size: {sizeBytes.First()} bytes");
}
else
{
var error = await response.Content.ReadAsStringAsync();
Console.Error.WriteLine($"API error ({(int)response.StatusCode}): {error}");
}Reusable Screenshot Client
A helper class that wraps the API with typed models, error handling, and retries.
csharp
using System.Net.Http.Json;
using System.Text.Json;
using System.Text.Json.Serialization;
public class NodiumClient : IDisposable
{
private const string BaseUrl = "https://api.nodium.io/api/v1/screenshot";
private readonly HttpClient _httpClient;
private readonly int _maxRetries;
public NodiumClient(string apiKey, int maxRetries = 3, int timeoutSeconds = 60)
{
_maxRetries = maxRetries;
_httpClient = new HttpClient
{
Timeout = TimeSpan.FromSeconds(timeoutSeconds)
};
_httpClient.DefaultRequestHeaders.Add("X-Access-Key", apiKey);
}
public Task<byte[]> TakeAsync(object parameters)
=> RequestWithRetryAsync($"{BaseUrl}/take", parameters);
public Task<byte[]> AnimateAsync(object parameters)
=> RequestWithRetryAsync($"{BaseUrl}/animate", parameters);
private async Task<byte[]> RequestWithRetryAsync(string url, object parameters)
{
for (int attempt = 0; attempt <= _maxRetries; attempt++)
{
var response = await _httpClient.PostAsJsonAsync(url, parameters);
if (response.IsSuccessStatusCode)
{
return await response.Content.ReadAsByteArrayAsync();
}
var errorBody = await response.Content.ReadAsStringAsync();
// Do not retry client errors (4xx)
if ((int)response.StatusCode >= 400 && (int)response.StatusCode < 500)
{
var apiError = JsonSerializer.Deserialize<ApiError>(errorBody);
throw new NodiumApiException(
apiError?.ErrorCode ?? "unknown",
apiError?.Message ?? errorBody,
(int)response.StatusCode
);
}
// Retry server errors (5xx) with exponential backoff
if (attempt < _maxRetries)
{
var delay = (int)Math.Pow(2, attempt) * 1000;
Console.WriteLine($"Retry {attempt + 1}/{_maxRetries} after {delay}ms...");
await Task.Delay(delay);
}
}
throw new NodiumApiException("max_retries_exceeded",
$"Max retries ({_maxRetries}) exceeded", 500);
}
public void Dispose() => _httpClient.Dispose();
}
public record ApiError(
[property: JsonPropertyName("error_code")] string ErrorCode,
[property: JsonPropertyName("message")] string Message,
[property: JsonPropertyName("http_status_code")] int HttpStatusCode
);
public class NodiumApiException : Exception
{
public string ErrorCode { get; }
public int HttpStatus { get; }
public bool IsRetryable => HttpStatus >= 500;
public NodiumApiException(string errorCode, string message, int httpStatus)
: base(message)
{
ErrorCode = errorCode;
HttpStatus = httpStatus;
}
}Using the Client
csharp
using var client = new NodiumClient("YOUR_API_KEY");
try
{
var screenshot = await client.TakeAsync(new
{
url = "https://example.com",
format = "png",
viewport_width = 1280,
viewport_height = 1024,
full_page = true
});
await File.WriteAllBytesAsync("screenshot.png", screenshot);
Console.WriteLine($"Screenshot saved ({screenshot.Length} bytes)");
}
catch (NodiumApiException ex)
{
Console.Error.WriteLine($"API error [{ex.ErrorCode}]: {ex.Message}");
Console.Error.WriteLine($"Retryable: {ex.IsRetryable}");
}Error Handling
Handle specific error codes to take appropriate action.
csharp
try
{
var screenshot = await client.TakeAsync(new
{
url = "https://example.com",
format = "png"
});
await File.WriteAllBytesAsync("screenshot.png", screenshot);
}
catch (NodiumApiException ex) when (ex.ErrorCode == "screenshots_limit_reached")
{
Console.Error.WriteLine("Monthly quota exceeded. Upgrade your plan.");
}
catch (NodiumApiException ex) when (ex.ErrorCode == "concurrency_limit_reached")
{
Console.Error.WriteLine("Too many simultaneous requests. Try again shortly.");
}
catch (NodiumApiException ex) when (ex.ErrorCode is "access_key_required" or "access_key_invalid")
{
Console.Error.WriteLine($"Authentication failed: {ex.Message}");
}
catch (NodiumApiException ex) when (ex.IsRetryable)
{
Console.Error.WriteLine($"Server error (retryable): {ex.Message}");
}
catch (NodiumApiException ex)
{
Console.Error.WriteLine($"API error [{ex.ErrorCode}]: {ex.Message}");
}
catch (TaskCanceledException)
{
Console.Error.WriteLine("Request timed out.");
}
catch (HttpRequestException ex)
{
Console.Error.WriteLine($"Network error: {ex.Message}");
}ASP.NET Core Integration
Configuration
json
// appsettings.json
{
"Nodium": {
"ApiKey": "YOUR_API_KEY",
"Timeout": 60,
"MaxRetries": 3
}
}Settings Class
csharp
public class NodiumSettings
{
public string ApiKey { get; set; } = string.Empty;
public int Timeout { get; set; } = 60;
public int MaxRetries { get; set; } = 3;
}Dependency Injection Setup
Register NodiumClient as a singleton service in Program.cs:
csharp
// Program.cs
var builder = WebApplication.CreateBuilder(args);
var nodiumSettings = builder.Configuration
.GetSection("Nodium")
.Get<NodiumSettings>()!;
builder.Services.AddSingleton(
new NodiumClient(nodiumSettings.ApiKey, nodiumSettings.MaxRetries, nodiumSettings.Timeout)
);
builder.Services.AddControllers();
var app = builder.Build();
app.MapControllers();
app.Run();Controller
csharp
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/[controller]")]
public class ScreenshotsController : ControllerBase
{
private readonly NodiumClient _nodium;
public ScreenshotsController(NodiumClient nodium)
{
_nodium = nodium;
}
[HttpGet("capture")]
public async Task<IActionResult> Capture([FromQuery] string url)
{
if (string.IsNullOrWhiteSpace(url))
return BadRequest(new { error = "url parameter is required" });
try
{
var screenshot = await _nodium.TakeAsync(new
{
url,
format = "png",
viewport_width = 1280,
viewport_height = 1024,
});
return File(screenshot, "image/png", "screenshot.png");
}
catch (NodiumApiException ex)
{
return StatusCode(ex.HttpStatus, new
{
error = ex.ErrorCode,
message = ex.Message,
});
}
}
[HttpPost("capture")]
public async Task<IActionResult> CapturePost([FromBody] CaptureRequest request)
{
try
{
var screenshot = await _nodium.TakeAsync(new
{
url = request.Url,
format = request.Format ?? "png",
viewport_width = request.ViewportWidth ?? 1280,
viewport_height = request.ViewportHeight ?? 1024,
full_page = request.FullPage ?? false,
});
var contentType = request.Format switch
{
"jpeg" => "image/jpeg",
"webp" => "image/webp",
"pdf" => "application/pdf",
_ => "image/png",
};
return File(screenshot, contentType, $"screenshot.{request.Format ?? "png"}");
}
catch (NodiumApiException ex)
{
return StatusCode(ex.HttpStatus, new
{
error = ex.ErrorCode,
message = ex.Message,
});
}
}
}
public record CaptureRequest
{
public string Url { get; init; } = string.Empty;
public string? Format { get; init; }
public int? ViewportWidth { get; init; }
public int? ViewportHeight { get; init; }
public bool? FullPage { get; init; }
}Signed URL Generation
Generate a signed URL by computing an HMAC-SHA256 signature over the query parameters.
csharp
using System.Security.Cryptography;
using System.Text;
using System.Web;
static string GenerateSignedUrl(
string apiKey,
string secretKey,
Dictionary<string, string> parameters,
TimeSpan expiresIn)
{
var expires = DateTimeOffset.UtcNow.Add(expiresIn).ToUnixTimeSeconds();
parameters["access_key"] = apiKey;
parameters["expires"] = expires.ToString();
// Sort parameters for consistent signing
var sorted = parameters.OrderBy(p => p.Key).ToList();
var stringToSign = string.Join("&", sorted.Select(p => $"{p.Key}={p.Value}"));
// Compute HMAC-SHA256 signature
using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secretKey));
var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign));
var signature = Convert.ToHexString(hash).ToLower();
// Build the final URL
var query = HttpUtility.ParseQueryString(string.Empty);
foreach (var (key, value) in sorted)
query[key] = value;
query["signature"] = signature;
return $"https://api.nodium.io/api/v1/screenshot/take?{query}";
}
// Usage
var signedUrl = GenerateSignedUrl(
"YOUR_API_KEY",
"YOUR_SECRET_KEY",
new Dictionary<string, string>
{
["url"] = "https://example.com",
["format"] = "png",
["viewport_width"] = "1280",
["viewport_height"] = "1024",
},
TimeSpan.FromHours(1)
);
Console.WriteLine(signedUrl);Next Steps
- API Reference -- Complete reference for all 145+ parameters
- Guides -- Practical guides for common use cases
- Getting Started -- Quick intro and cURL examples