This is the official .NET client library for the Ipregistry IP geolocation and threat data API, allowing you to look up your own IP address or specified ones. Responses return multiple data points including carrier, company, currency, location, time zone, threat information, and more. The library can also parse raw User-Agent strings.
It works from any .NET language — C#, F#, and VB.NET — and is:
- Async end to end — every operation is a cancellable
Task. HttpClient-friendly — bring your ownHttpClient/IHttpClientFactory, or let the library manage one.- DI-ready — one-line registration with
services.AddIpregistry(...). - Resilient — automatic retries with exponential backoff and
Retry-Aftersupport. - Cacheable — optional in-memory LRU + TTL cache, or plug in your own.
- Trimming- and Native AOT-compatible — JSON handling is source-generated.
You'll need an Ipregistry API key, which you can get along with 100,000 free lookups by signing up for a free account at https://ipregistry.co.
dotnet add package IpregistryRequires .NET 8 or later.
using Ipregistry;
using var client = new IpregistryClient("YOUR_API_KEY");
// Look up data for a given IPv4 or IPv6 address.
// On the server side, retrieve the client IP from the request headers.
var info = await client.LookupAsync("54.85.132.205");
Console.WriteLine(info.Location.Country.Name);
Console.WriteLine(info.Connection.Asn);
Console.WriteLine(info.Security.IsVpn);Nested objects such as Location, Security, or Currency are always non-null, so drilling into them never throws
— fields the API did not return simply hold null (strings, Asn, Latitude, ...) or their default value.
To look up the IP address the request is sent from — no argument needed — use LookupOriginAsync. It returns a
RequesterIpInfo, which additionally carries parsed User-Agent data:
var origin = await client.LookupOriginAsync();
Console.WriteLine($"{origin.Ip} {origin.Location.Country.Name} {origin.UserAgent?.Name}");LookupBatchAsync resolves many IP addresses in one call. Each entry may independently succeed or fail (for example
on an invalid address), so results are inspected element by element:
var results = await client.LookupBatchAsync("8.8.8.8", "1.1.1.1", "not-an-ip");
foreach (var result in results)
{
if (result.IsSuccess)
Console.WriteLine($"{result.Value.Ip}: {result.Value.Location.Country.Name}");
else
Console.WriteLine($"failed: {result.Error.Message}");
}Inputs larger than the API limit (1024 addresses) are transparently split into several requests dispatched with bounded concurrency, and results come back in input order.
var agents = await client.ParseUserAgentsAsync(Request.Headers.UserAgent.ToString());
Console.WriteLine(agents[0].Value.Name); // e.g. "Chrome"There is also a lightweight local heuristic to skip lookups for automated traffic:
if (!UserAgents.IsBot(userAgentHeader)) { /* look up the IP */ }The library integrates with IHttpClientFactory and the options pattern:
builder.Services.AddIpregistry(options =>
{
options.ApiKey = builder.Configuration["Ipregistry:ApiKey"]!;
options.Cache = new InMemoryIpregistryCache();
});Then inject IIpregistryClient anywhere:
app.MapGet("/whois/{ip}", async (string ip, IIpregistryClient ipregistry) =>
{
var info = await ipregistry.LookupAsync(ip);
return new { info.Ip, Country = info.Location.Country.Name, info.Security.IsVpn };
});AddIpregistry returns an IHttpClientBuilder, so you can chain standard resilience or handler configuration
(for example .AddStandardResilienceHandler() from Microsoft.Extensions.Http.Resilience).
The API is task-friendly and null-annotated, so it composes naturally from F#:
open Ipregistry
use client = new IpregistryClient("YOUR_API_KEY")
task {
let! info = client.LookupAsync "54.85.132.205"
printfn $"{info.Location.Country.Name}"
let! results = client.LookupBatchAsync [ "8.8.8.8"; "1.1.1.1" ]
for result in results do
match result.Error with
| null -> printfn $"{result.Value.Ip} -> {result.Value.Location.Country.Name}"
| error -> printfn $"failed -> {error.Message}"
}Runnable C# and F# samples live in samples/.
All settings are optional except the API key:
using var client = new IpregistryClient(new IpregistryClientOptions
{
ApiKey = "YOUR_API_KEY",
Timeout = TimeSpan.FromSeconds(15), // per-request timeout (owned HttpClient only)
MaxRetries = 3, // retries in addition to the initial attempt
RetryInterval = TimeSpan.FromSeconds(1), // base backoff, doubled per attempt
RetryOnServerError = true, // retry 5xx and transient network errors
RetryOnTooManyRequests = false, // retry 429, honoring Retry-After
MaxBatchSize = 1024, // addresses per batch request (API max)
BatchConcurrency = 4, // concurrent chunk requests for large batches
Cache = new InMemoryIpregistryCache( // no caching by default
maxSize: 4096, timeToLive: TimeSpan.FromMinutes(10)),
});To control the HTTP layer yourself (proxy, TLS, pooling, instrumentation), pass your own HttpClient; the library
then never disposes it and your client's timeout applies:
var client = new IpregistryClient(options, httpClient);var info = await client.LookupAsync("8.8.8.8", new LookupOptions
{
// https://ipregistry.co/docs/filtering-selecting-fields
Fields = "location.country.name,security",
Hostname = true, // reverse-DNS resolution
});All failures derive from IpregistryException:
IpregistryApiException— the API reported an error. Branch on the typedErrorCode(for exampleIpregistryErrorCode.InvalidIpAddress,InsufficientCredits,TooManyRequests) or inspect the rawCode,Resolution, and HTTPStatusCode.IpregistryClientException— a client-side failure such as a network error or an undecodable response; the cause is inInnerException.
Cancellation is idiomatic: a canceled CancellationToken surfaces as OperationCanceledException, never wrapped.
try
{
var info = await client.LookupAsync(ip, cancellationToken: ct);
}
catch (IpregistryApiException e) when (e.ErrorCode == IpregistryErrorCode.InvalidIpAddress)
{
// handle bad input
}
catch (IpregistryException e)
{
// handle any other Ipregistry failure
}In batch lookups, per-entry failures are returned (never thrown) as IpregistryApiException values on
IpInfoResult.Error.
dotnet build Ipregistry.slnx
dotnet test tests/Ipregistry.Tests # unit tests, no network
IPREGISTRY_API_KEY=YOUR_API_KEY \
dotnet test tests/Ipregistry.SystemTests # system tests against the live API (consumes credits)System tests skip cleanly when IPREGISTRY_API_KEY is not set.
Official Ipregistry client libraries are also available for Go, Java, JavaScript/TypeScript, PHP, and Python.