.NET SDK

ip-api.io .NET SDK
dotnet add package IpApiIo

IpApiIo is the official async client for C# and .NET — built on HttpClient and System.Text.Json with zero package dependencies. One IpApiClient wraps IP geolocation, VPN/proxy/Tor detection, email validation, and fraud risk scoring, returning strongly-typed objects with typed exceptions and batch helpers, so you write the call, not the plumbing.

Location
Mountain View, US
Threat signals
No VPN or proxy
Runtime
Async — Task<T>
await client.LookupAsync("8.8.8.8")
{
"ip": "8.8.8.8",
"isp": "Google LLC",
"location": {
"country": "United States",
"city": "Mountain View",
"timezone": "America/Los_Angeles"
},
"suspicious_factors": {
"is_vpn": false,
"is_datacenter": true
}
}

What you'll build

  • Add the package and construct one async client
  • Look up any IP — or the caller's IP — with one call
  • Detect VPN, proxy, Tor, and threats; batch up to 100 IPs
  • Catch the typed exceptions the production-ready way
Trusted by thousands of businesses
Fast JSON API responses
Real-time validation
Simple integration, SDKs & examples

Prerequisites

  • The .NET 6 SDK or later
  • A C# project (dotnet new console works for trying it out)
  • An ip-api.io API key — get one free
1

Add the package

Add the official IpApiIo package from NuGet. It has zero package dependencies — it's built on the framework's own HttpClient and System.Text.Json.

dotnet add package IpApiIo

# ...or add to your .csproj:
# &lt;PackageReference Include=&quot;IpApiIo&quot; Version=&quot;1.*&quot; /&gt;
2

Construct the client

Bring the namespace into scope and build one IpApiClient with your API key. Read the key from an environment variable — never hardcode it. The API rejects keyless requests with 401.

using IpApiIo;

var apiKey = Environment.GetEnvironmentVariable("IP_API_IO_KEY")!;
var client = new IpApiClient(apiKey);

// ... use the client ...

IpApiClient wraps a single HttpClient and is thread-safe — register it as a singleton (or reuse one instance) instead of creating one per request. In ASP.NET Core, add it once in Program.cs:

builder.Services.AddSingleton(
    new IpApiClient(builder.Configuration["IpApiIo:Key"]!));
3

Look up an IP address

Call LookupAsync(ip) for any IPv4 or IPv6 address, or LookupAsync() to resolve the caller's own IP. Responses are strongly-typed objects; nullable fields are string? / double? — null-check before use.

var info = await client.LookupAsync("8.8.8.8");

Console.WriteLine(info.Ip);                          // "8.8.8.8"
Console.WriteLine(info.Isp);                         // "Google LLC"
Console.WriteLine(info.Location.Country);            // "United States"
Console.WriteLine(info.SuspiciousFactors.IsDatacenter); // True

// Resolve the caller's own IP:
var me = await client.LookupAsync();
Console.WriteLine(me.Ip);
Nullable reference types: location fields like Country and City are string? because they're absent for private ranges or unrecognized addresses — use the null-coalescing operator (info.Location.Country ?? "Unknown"). Boolean flags such as info.SuspiciousFactors.IsVpn are plain bool values.
4

Detect VPN, proxy, Tor & batch lookups

The SuspiciousFactors object carries seven boolean fields on every lookup — this is what sets ip-api.io apart from plain geolocation APIs. You get security intelligence in the same call, at no extra cost.

var info = await client.LookupAsync("185.220.101.45"); // example Tor exit node
var f = info.SuspiciousFactors;

if (f.IsVpn || f.IsProxy || f.IsTorNode)
    Console.WriteLine("Anonymized traffic — consider a CAPTCHA or block");
if (f.IsDatacenter)
    Console.WriteLine("Cloud/datacenter IP — likely automated");
if (f.IsThreat)
    Console.WriteLine("Active threat signal — block this request");

var risky = f.IsVpn || f.IsProxy || f.IsTorNode || f.IsThreat;

Need to check many IPs at once? LookupBatchAsync takes up to 100 addresses in a single request:

var batch = await client.LookupBatchAsync(
    new[] { "8.8.8.8", "1.1.1.1", "9.9.9.9" });

Console.WriteLine($"{batch.TotalProcessed} {batch.SuccessfulLookups}");

foreach (var (ip, result) in batch.Results)
    Console.WriteLine($"{ip} {result.SuspiciousFactors.IsVpn}");
Tip: want a single block / review / allow decision instead of raw flags? Use await client.RiskScoreAsync(ip) for a combined fraud risk score from 0 to 100.
5

Production-ready error handling

The client throws typed exceptions that all derive from IpApiException and never retries on its own, so on a rate limit RateLimitException.Reset tells you exactly when to try again.

using IpApiIo;
using IpApiIo.Exceptions;

try
{
    var info = await client.LookupAsync("8.8.8.8");
    Console.WriteLine(info.Ip);
}
catch (RateLimitException ex)
{
    Console.WriteLine($"Rate limited. Remaining: {ex.Remaining}. Resets at {ex.Reset}");
}
catch (AuthenticationException)
{
    Console.WriteLine("Invalid or missing API key — get one free at https://ip-api.io");
}
catch (IpApiException ex)
{
    // Invalid request, server error, or transport failure
    Console.WriteLine($"ip-api.io error: {ex.Message}");
}
No automatic retries: wrap calls in your own retry/backoff (e.g. Polly) and use RateLimitException.Reset (a Unix timestamp) to schedule the next attempt. Every method also accepts a CancellationToken so you can wire in request timeouts.

In an ASP.NET Core minimal API, run the lookup server-side and pass the real client IP from the X-Forwarded-For header:

app.MapGet("/check", async (HttpContext ctx, IpApiClient client) =>
{
    var clientIp = ctx.Request.Headers["X-Forwarded-For"]
        .FirstOrDefault()?.Split(',')[0].Trim()
        ?? ctx.Connection.RemoteIpAddress?.ToString()
        ?? "0.0.0.0";

    try
    {
        var info = await client.LookupAsync(clientIp);
        return Results.Ok(new
        {
            ip = info.Ip,
            country = info.Location.Country,
            isVpn = info.SuspiciousFactors.IsVpn,
            isThreat = info.SuspiciousFactors.IsThreat
        });
    }
    catch (IpApiException)
    {
        // Treat ip-api.io as a non-critical dependency
        return Results.Ok(new { ip = clientIp, country = (string?)null });
    }
});
Reference

Response & method reference

LookupAsync resolves to a typed IpInfo with three parts: the top-level Ip/Isp/Asn, a SuspiciousFactors object, and a Location object. Nullable fields are string? / double?null for private ranges or unrecognized addresses.

await client .LookupAsync("78.55.53.58")
{
  "ip": "78.55.53.58",
  "isp": "Deutsche Telekom AG",
  "asn": "AS3320",
  "suspicious_factors": {
    "is_proxy":      false,
    "is_tor_node":   false,
    "is_spam":       false,
    "is_crawler":    false,
    "is_datacenter": false,
    "is_vpn":        false,
    "is_threat":     false
  },
  "location": {
    "country":           "Germany",
    "country_code":      "DE",
    "city":              "Berlin",
    "latitude":          52.5694,
    "longitude":         13.3753,
    "zip":               "13409",
    "timezone":          "Europe/Berlin",
    "local_time":        "2024-05-20T22:16:52+02:00",
    "local_time_unix":   1716236212,
    "is_daylight_savings": true
  }
}

SuspiciousFactors — security signals (all bool)

PropertyDescription
IsVpnVPN service, corporate gateway, or self-hosted VPN detected
IsProxyHTTP, HTTPS, or SOCKS proxy (~99.5% accuracy)
IsTorNodeTor exit node, relay, or bridge (updated in real time)
IsDatacenterCloud provider (AWS, GCP, Azure), VPS, or hosting facility
IsThreatActive security threat — malware C&C, botnet, or DDoS source
IsSpamAssociated with spam, phishing, or malware email campaigns
IsCrawlerKnown web crawler, scraper, or bot

Location — geographic and timezone data

PropertyTypeDescription
Countrystring?Full country name in English (ISO 3166-1)
CountryCodestring?ISO 3166-1 alpha-2 code (e.g. "DE", "US")
Citystring?City or municipality name (85–95% accuracy)
Latitudedouble?Decimal degrees, WGS84 — ~50 km median accuracy radius
Longitudedouble?Decimal degrees, WGS84 — ~50 km median accuracy radius
Zipstring?Postal or ZIP code in country-specific format
Timezonestring?IANA timezone identifier (e.g. "America/Los_Angeles")
LocalTimestring?Current local time in ISO 8601 with UTC offset
LocalTimeUnixlong?Unix timestamp (seconds) in local timezone
IsDaylightSavingsbool?True if currently observing DST; null if not applicable

Client methods

MethodReturnsWhat it does
LookupAsync() / LookupAsync(ip)Task<IpInfo>Geolocate the caller's IP, or a specific IP
LookupBatchAsync(ips)Task<BatchIpLookup>Geolocate up to 100 IPs in one call
RiskScoreAsync() / RiskScoreAsync(ip)Task<RiskScore>Fraud risk score (0–100) for an IP
TorCheckAsync(ip)Task<TorDetection>Check whether an IP is a Tor node
EmailInfoAsync(email)Task<EmailInfo>Basic email validation (syntax, MX, disposable)
ValidateEmailAsync(email)Task<AdvancedEmailValidation>Full validation incl. SMTP deliverability
AsnAsync(ip)Task<AsnLookup>Autonomous System Number lookup
WhoisAsync(domain)Task<Whois>WHOIS domain registration info
DomainAgeAsync(domain)Task<DomainAge>Domain registration date and age in days
RateLimitAsync()Task<RateLimitInfo>Remaining quota and plan limits
Full surface: the client also exposes ValidateEmailBatchAsync, EmailRiskScoreAsync, IpReputationAsync, ReverseDnsAsync, ForwardDnsAsync, MxRecordsAsync, DomainAgeBatchAsync, and UsageSummaryAsync. See the README and per-feature guides.
FAQ

Frequently asked questions

Common questions about the ip-api.io .NET SDK.

Is the IpApiIo package official?

Yes. IpApiIo is the official .NET client for ip-api.io, maintained by the ip-api.io team and published to NuGet from github.com/ip-api-io/ipapi-dotnet. It is MIT licensed and not affiliated with ip-api.com or ipapi.com.

How do I install the ip-api.io .NET SDK?

Run dotnet add package IpApiIo (or add it from the NuGet Package Manager), then bring the namespace into scope and construct the client:

// dotnet add package IpApiIo
using IpApiIo;

var client = new IpApiClient(Environment.GetEnvironmentVariable("IP_API_IO_KEY")!);

It targets .NET 6 and later with zero package dependencies — built on HttpClient and System.Text.Json.

Is the client async?

Yes. Every method is async and returns a Task<T>, so you await each call. Each method also accepts an optional CancellationToken. IpApiClient wraps a single HttpClient and is thread-safe — register it as a singleton and reuse it instead of constructing one per request.

How are nullable fields represented?

Responses are strongly-typed objects. Nullable fields are C# nullable reference/value types such as string? and double? — null-check before use, e.g. info.Location.Country ?? "Unknown". Boolean flags such as info.SuspiciousFactors.IsVpn are plain bool.

How do I handle rate limits?

The client throws typed exceptions and never retries automatically. Catch RateLimitException — it exposes Limit, Remaining, and Reset from the response headers — and schedule your retry after Reset. Invalid keys throw AuthenticationException.

Pricing

Pricing

Start using IP-API.io to make your website safer and more user-friendly. Keep out unwanted bots, show visitors content that's relevant to where they are, and spot risky IP addresses quickly. It's perfect for making online shopping more personal and keeping your site secure. Get started today with one of the plans!

Small
€10 /mo
100,000 geo ip requests
10,000 advanced email validation requests
Location data
Email validation
Risk score calculation
Currency data
Time zone data
Threat data
Unlimited support
HTTPS encryption
Create Account to Subscribe
Medium
€20 /mo
300,000 geo ip requests
25,000 advanced email validation requests
Location data
Email validation
Risk score calculation
Currency data
Time zone data
Threat data
Unlimited support
HTTPS encryption
Create Account to Subscribe

Need support?

Explore how IP-API.io can enhance your security, provide robust bot protection, and improve IP geolocation accuracy for your applications.

Contact Support

Found a bug in the SDK?

The IpApiIo package is open source. Open an issue or pull request on GitHub and we'll take a look.

Open on GitHub