Go SDK

github.com/netloc8/netloc8-go — Zero-dependency, context-native IP geolocation client for Go.

Installation

Bash
go get github.com/netloc8/netloc8-go

Requires Go 1.22+. Zero external dependencies — only the Go standard library.

Quick Start

go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/netloc8/netloc8-go"
)

func main() {
    client := netloc8.NewClient( "sk_your_secret_key" )

    geo, err := client.LookupIP( context.Background(), "8.8.8.8" )
    if err != nil {
        log.Fatal( err )
    }

    fmt.Println( geo.CountryCode() )  // "US"
    fmt.Println( geo.CityName() )     // "Mountain View"
    fmt.Println( geo.TZ() )           // "America/Los_Angeles"
    fmt.Println( geo.ASN() )          // "AS15169"
    fmt.Println( geo.Org() )          // "Google LLC"
}

Client Methods

MethodDescription
LookupIP( ctx, ip )Look up geolocation for a specific IP address
LookupMe( ctx )Look up geolocation for the caller's own IP

Both methods accept context.Context for cancellation, timeouts, and tracing. They return (*Geo, error).

LookupMe — Discover Exit IP

LookupMe calls GET /v1/ip/me to geolocate the IP the API sees. With a proxy transport, this discovers the exit IP of the proxy:

go
import (
    "net/http"
    "net/url"

    "github.com/netloc8/netloc8-go"
)

proxyURL, _ := url.Parse( "socks5://proxy.example.com:1080" )
transport := &http.Transport{ Proxy: http.ProxyURL( proxyURL ) }

client := netloc8.NewClient( "sk_your_key",
    netloc8.WithHTTPClient( &http.Client{ Transport: transport } ),
)

geo, err := client.LookupMe( ctx )
if err != nil {
    log.Fatal( err )
}
fmt.Println( geo.IP() )           // the proxy's exit IP
fmt.Println( geo.CountryCode() )  // country of the exit node

Nil-Safe Accessors

All accessor methods on *Geo are nil-safe — they never panic, even on partial or empty responses. Returns the zero value when the underlying field is absent.

AccessorReturnsExample
geo.IP()string"8.8.8.8"
geo.CountryCode()string"US"
geo.CountryName()string"United States"
geo.RegionCode()string"CA"
geo.RegionName()string"California"
geo.CityName()string"Mountain View"
geo.TZ()string"America/Los_Angeles"
geo.ASN()string"AS15169"
geo.Org()string"Google LLC"
geo.Lat()float6437.386
geo.Lng()float64-122.084

You can also access the full struct directly: geo.Location.Country.Unions, geo.Location.District, geo.Meta.Precision, etc.

Helper Functions

FunctionDescription
netloc8.IsEU( geo )Check if geolocation is in the EU (checks unions for "EU")
netloc8.IsPublicIP( ip )Check whether an IP is publicly routable
netloc8.GetClientIP( r )Extract the real client IP from HTTP request headers
netloc8.NormalizeIP( ip )Normalize an IP address string (trim, strip zone ID)
netloc8.Subnet( ip )Derive the /24 (v4) or /48 (v6) subnet from an IP
go
// EU compliance check
if netloc8.IsEU( geo ) {
    // show cookie consent banner, apply GDPR rules, etc.
}

// Extract client IP behind proxies
ip := netloc8.GetClientIP( r )  // checks X-Forwarded-For, CF-Connecting-IP, etc.

// Derive subnet for IP rotation
subnet := netloc8.Subnet( geo.IP() )  // "203.0.113.0/24"

GetClientIP header priority

GetClientIP checks headers in order: X-Forwarded-For (first public IP), CF-Connecting-IP, True-Client-IP, X-Real-IP, X-Client-IP, Fastly-Client-IP, Fly-Client-IP.

Error Handling

API errors are returned as *netloc8.APIError with machine-readable codes. Use errors.As for typed error handling:

go
import "errors"

geo, err := client.LookupIP( ctx, "not-an-ip" )
if err != nil {
    var apiErr *netloc8.APIError
    if errors.As( err, &apiErr ) {
        fmt.Println( apiErr.Code )       // "INVALID_IP"
        fmt.Println( apiErr.Message )    // "Invalid IP address format"
        fmt.Println( apiErr.Status )     // 400
        fmt.Println( apiErr.RequestID )  // "550e8400-..."
    }
}

Configuration Options

OptionDefaultDescription
WithBaseURL( url )https://api.netloc8.comOverride the API base URL (for proxies or self-hosted)
WithHTTPClient( hc )http.DefaultClientCustom http.Client for proxy transports, custom TLS, etc.
WithTimeout( d )10sRequest timeout for API calls
WithOrigin( origin )Origin header for publishable key (pk_) authentication
WithUserAgent( ua )Custom User-Agent string (SDK version is appended)
go
client := netloc8.NewClient( "sk_your_key",
    netloc8.WithTimeout( 5 * time.Second ),
    netloc8.WithBaseURL( "https://geo-proxy.internal" ),
    netloc8.WithHTTPClient( &http.Client{
        Transport: &http.Transport{
            Proxy: http.ProxyURL( proxyURL ),
        },
    }),
)

Concurrency safe

Client is safe for concurrent use across goroutines. Create one client and reuse it for the lifetime of your application.