MCPcopy Index your code
hub / github.com/oschwald/geoip2-golang

github.com/oschwald/geoip2-golang @v2.2.0 sqlite

repository ↗ · DeepWiki ↗ · release v2.2.0 ↗
104 symbols 333 edges 4 files 79 documented · 76% 6 cross-repo links
README

GeoIP2 Reader for Go

PkgGoDev

This library reads MaxMind GeoLite2 and GeoIP2 databases.

This library is built using the Go maxminddb reader. All data for the database record is decoded using this library. Version 2.0 provides significant performance improvements with 56% fewer allocations and 34% less memory usage compared to v1. Version 2.0 also adds Network and IPAddress fields to all result structs, and includes a HasData() method to easily check if data was found. If you only need several fields, you may get superior performance by using maxminddb's Lookup directly with a result struct that only contains the required fields. (See example_test.go in the maxminddb repository for an example of this.)

Installation

go get github.com/oschwald/geoip2-golang/v2

New in v2

Version 2.0 includes several major improvements:

  • Performance: 56% fewer allocations and 34% less memory usage
  • Modern API: Uses netip.Addr instead of net.IP for better performance
  • Network Information: All result structs now include Network and IPAddress fields
  • Data Validation: New HasData() method to easily check if data was found
  • Structured Names: Replaced map[string]string with typed Names struct for better performance

Migration

See MIGRATION.md for step-by-step guidance on upgrading from v1.

Usage

See GoDoc for documentation and examples.

Example

package main

import (
    "fmt"
    "log"
    "net/netip"

    "github.com/oschwald/geoip2-golang/v2"
)

func main() {
    db, err := geoip2.Open("GeoIP2-City.mmdb")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()
    // If you are using strings that may be invalid, use netip.ParseAddr and check for errors
    ip, err := netip.ParseAddr("81.2.69.142")
    if err != nil {
        log.Fatal(err)
    }
    record, err := db.City(ip)
    if err != nil {
        log.Fatal(err)
    }
    if !record.HasData() {
        fmt.Println("No data found for this IP")
        return
    }
    fmt.Printf("Portuguese (BR) city name: %v\n", record.City.Names.BrazilianPortuguese)
    if len(record.Subdivisions) > 0 {
        fmt.Printf("English subdivision name: %v\n", record.Subdivisions[0].Names.English)
    }
    fmt.Printf("Russian country name: %v\n", record.Country.Names.Russian)
    fmt.Printf("ISO country code: %v\n", record.Country.ISOCode)
    fmt.Printf("Time zone: %v\n", record.Location.TimeZone)
    if record.Location.HasCoordinates() {
        fmt.Printf("Coordinates: %v, %v\n", *record.Location.Latitude, *record.Location.Longitude)
    }
    // Output:
    // Portuguese (BR) city name: Londres
    // English subdivision name: England
    // Russian country name: Великобритания
    // ISO country code: GB
    // Time zone: Europe/London
    // Coordinates: 51.5142, -0.0931
}

Requirements

  • Go 1.25 or later
  • MaxMind GeoIP2 or GeoLite2 database files (.mmdb format)

Getting Database Files

GeoLite2 (Free)

Download free GeoLite2 databases from MaxMind's website. Registration required.

GeoIP2 (Commercial)

Purchase GeoIP2 databases from MaxMind for enhanced accuracy and additional features.

Database Examples

This library supports all MaxMind GeoIP2 and GeoLite2 database types. Below are examples for each database type:

City Database

The City database provides the most comprehensive geolocation data, including city, subdivision, country, and precise location information.

package main

import (
    "fmt"
    "log"
    "net/netip"

    "github.com/oschwald/geoip2-golang/v2"
)

func main() {
    db, err := geoip2.Open("GeoIP2-City.mmdb")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    ip, err := netip.ParseAddr("128.101.101.101")
    if err != nil {
        log.Fatal(err)
    }

    record, err := db.City(ip)
    if err != nil {
        log.Fatal(err)
    }

    if !record.HasData() {
        fmt.Println("No data found for this IP")
        return
    }

    fmt.Printf("City: %v\n", record.City.Names.English)
    fmt.Printf("Subdivision: %v\n", record.Subdivisions[0].Names.English)
    fmt.Printf("Country: %v (%v)\n", record.Country.Names.English, record.Country.ISOCode)
    fmt.Printf("Continent: %v (%v)\n", record.Continent.Names.English, record.Continent.Code)
    fmt.Printf("Postal Code: %v\n", record.Postal.Code)
    if record.Location.HasCoordinates() {
        fmt.Printf("Location: %v, %v\n", *record.Location.Latitude, *record.Location.Longitude)
    }
    fmt.Printf("Time Zone: %v\n", record.Location.TimeZone)
    fmt.Printf("Network: %v\n", record.Traits.Network)
    fmt.Printf("IP Address: %v\n", record.Traits.IPAddress)
}

Country Database

The Country database provides country-level geolocation data.

package main

import (
    "fmt"
    "log"
    "net/netip"

    "github.com/oschwald/geoip2-golang/v2"
)

func main() {
    db, err := geoip2.Open("GeoIP2-Country.mmdb")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    ip, err := netip.ParseAddr("81.2.69.142")
    if err != nil {
        log.Fatal(err)
    }

    record, err := db.Country(ip)
    if err != nil {
        log.Fatal(err)
    }

    if !record.HasData() {
        fmt.Println("No data found for this IP")
        return
    }

    fmt.Printf("Country: %v (%v)\n", record.Country.Names.English, record.Country.ISOCode)
    fmt.Printf("Continent: %v (%v)\n", record.Continent.Names.English, record.Continent.Code)
    fmt.Printf("Is in EU: %v\n", record.Country.IsInEuropeanUnion)
    fmt.Printf("Network: %v\n", record.Traits.Network)
    fmt.Printf("IP Address: %v\n", record.Traits.IPAddress)

    if record.RegisteredCountry.Names.English != "" {
        fmt.Printf("Registered Country: %v (%v)\n",
            record.RegisteredCountry.Names.English, record.RegisteredCountry.ISOCode)
    }
}

ASN Database

The ASN database provides Autonomous System Number and organization information.

package main

import (
    "fmt"
    "log"
    "net/netip"

    "github.com/oschwald/geoip2-golang/v2"
)

func main() {
    db, err := geoip2.Open("GeoLite2-ASN.mmdb")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    ip, err := netip.ParseAddr("1.128.0.0")
    if err != nil {
        log.Fatal(err)
    }

    record, err := db.ASN(ip)
    if err != nil {
        log.Fatal(err)
    }

    if !record.HasData() {
        fmt.Println("No data found for this IP")
        return
    }

    fmt.Printf("ASN: %v\n", record.AutonomousSystemNumber)
    fmt.Printf("Organization: %v\n", record.AutonomousSystemOrganization)
    fmt.Printf("Network: %v\n", record.Network)
    fmt.Printf("IP Address: %v\n", record.IPAddress)
}

Anonymous IP Database

The Anonymous IP database identifies various types of anonymous and proxy networks.

package main

import (
    "fmt"
    "log"
    "net/netip"

    "github.com/oschwald/geoip2-golang/v2"
)

func main() {
    db, err := geoip2.Open("GeoIP2-Anonymous-IP.mmdb")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    ip, err := netip.ParseAddr("81.2.69.142")
    if err != nil {
        log.Fatal(err)
    }

    record, err := db.AnonymousIP(ip)
    if err != nil {
        log.Fatal(err)
    }

    if !record.HasData() {
        fmt.Println("No data found for this IP")
        return
    }

    fmt.Printf("Is Anonymous: %v\n", record.IsAnonymous)
    fmt.Printf("Is Anonymous VPN: %v\n", record.IsAnonymousVPN)
    fmt.Printf("Is Hosting Provider: %v\n", record.IsHostingProvider)
    fmt.Printf("Is Public Proxy: %v\n", record.IsPublicProxy)
    fmt.Printf("Is Residential Proxy: %v\n", record.IsResidentialProxy)
    fmt.Printf("Is Tor Exit Node: %v\n", record.IsTorExitNode)
    fmt.Printf("Network: %v\n", record.Network)
    fmt.Printf("IP Address: %v\n", record.IPAddress)
}

Anonymous Plus Database

The Anonymous Plus database extends the Anonymous IP database with additional fields for confidence scoring, provider identification, and temporal tracking.

package main

import (
    "fmt"
    "log"
    "net/netip"

    "github.com/oschwald/geoip2-golang/v2"
)

func main() {
    db, err := geoip2.Open("GeoIP-Anonymous-Plus.mmdb")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    ip, err := netip.ParseAddr("1.2.0.1")
    if err != nil {
        log.Fatal(err)
    }

    record, err := db.AnonymousPlus(ip)
    if err != nil {
        log.Fatal(err)
    }

    if !record.HasData() {
        fmt.Println("No data found for this IP")
        return
    }

    // Standard anonymous IP flags
    fmt.Printf("Is Anonymous: %v\n", record.IsAnonymous)
    fmt.Printf("Is Anonymous VPN: %v\n", record.IsAnonymousVPN)
    fmt.Printf("Is Hosting Provider: %v\n", record.IsHostingProvider)
    fmt.Printf("Is Public Proxy: %v\n", record.IsPublicProxy)
    fmt.Printf("Is Residential Proxy: %v\n", record.IsResidentialProxy)
    fmt.Printf("Is Tor Exit Node: %v\n", record.IsTorExitNode)

    // Anonymous Plus specific fields
    fmt.Printf("Anonymizer Confidence: %v\n", record.AnonymizerConfidence)
    fmt.Printf("Provider Name: %v\n", record.ProviderName)
    if !record.NetworkLastSeen.IsZero() {
        fmt.Printf("Network Last Seen: %v\n", record.NetworkLastSeen.Format("2006-01-02"))
    }

    fmt.Printf("Network: %v\n", record.Network)
    fmt.Printf("IP Address: %v\n", record.IPAddress)
}

Enterprise Database

The Enterprise database provides the most comprehensive data, including all City database fields plus additional enterprise features.

package main

import (
    "fmt"
    "log"
    "net/netip"

    "github.com/oschwald/geoip2-golang/v2"
)

func main() {
    db, err := geoip2.Open("GeoIP2-Enterprise.mmdb")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    ip, err := netip.ParseAddr("128.101.101.101")
    if err != nil {
        log.Fatal(err)
    }

    record, err := db.Enterprise(ip)
    if err != nil {
        log.Fatal(err)
    }

    if !record.HasData() {
        fmt.Println("No data found for this IP")
        return
    }

    // Basic location information
    fmt.Printf("City: %v\n", record.City.Names.English)
    fmt.Printf("Country: %v (%v)\n", record.Country.Names.English, record.Country.ISOCode)
    if record.Location.HasCoordinates() {
        fmt.Printf("Location: %v, %v\n", *record.Location.Latitude, *record.Location.Longitude)
    }

    // Enterprise-specific fields
    fmt.Printf("ISP: %v\n", record.Traits.ISP)
    fmt.Printf("Organization: %v\n", record.Traits.Organization)
    fmt.Printf("ASN: %v (%v)\n", record.Traits.AutonomousSystemNumber,
        record.Traits.AutonomousSystemOrganization)
    fmt.Printf("Connection Type: %v\n", record.Traits.ConnectionType)
    fmt.Printf("Domain: %v\n", record.Traits.Domain)
    fmt.Printf("User Type: %v\n", record.Traits.UserType)
    fmt.Printf("Is Anycast: %v\n", record.Traits.IsAnycast)

    // Mobile carrier information (if available)
    if record.Traits.MobileCountryCode != "" {
        fmt.Printf("Mobile Country Code: %v\n", record.Traits.MobileCountryCode)
        fmt.Printf("Mobile Network Code: %v\n", record.Traits.MobileNetworkCode)
    }

    fmt.Printf("Network: %v\n", record.Traits.Network)
    fmt.Printf("IP Address: %v\n", record.Traits.IPAddress)
}

ISP Database

The ISP database provides ISP, organization, and ASN information.

package main

import (
    "fmt"
    "log"
    "net/netip"

    "github.com/oschwald/geoip2-golang/v2"
)

func main() {
    db, err := geoip2.Open("GeoIP2-ISP.mmdb")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    ip, err := netip.ParseAddr("1.128.0.0")
    if err != nil {
        log.Fatal(err)
    }

    record, err := db.ISP(ip)
    if err != nil {
        log.Fatal(err)
    }

    if !record.HasData() {
        fmt.Println("No data found for this IP")
        return
    }

    fmt.Printf("ISP: %v\n", record.ISP)
    fmt.Printf("Organization: %v\n", record.Organization)
    fmt.Printf("ASN: %v (%v)\n", record.AutonomousSystemNumber,
        record.AutonomousSystemOrganization)

    // Mobile carrier information (if available)
    if record.MobileCountryCode != "" {
        fmt.Printf("Mobile Country Code: %v\n", record.MobileCountryCode)
        fmt.Printf("Mobile Network Code: %v\n", record.MobileNetworkCode)
    }

    fmt.Printf("Network: %v\n", record.Network)
    fmt.Printf("IP Address: %v\n", record.IPAddress)
}

Domain Database

The Domain database provides the second-level domain associated with an IP address.

package main

import (
    "fmt"
    "log"
    "net/netip"

    "github.com/oschwald/geoip2-golang/v2"
)

func main() {
    db, err := geoip2.Open("GeoIP2-Domain.mmdb")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    ip, err := netip.ParseAddr("1.2.0.0")
    if err != nil {
        log.Fatal(err)
    }

    record, err := db.Domain(ip)
    if err != nil {
        log.Fatal(err)
    }

    if !record.HasData() {
        fmt.Println("No data found for this IP")
        return
    }

    fmt.Printf("Domain: %v\n", record.Domain)
    fmt.Printf("Network: %v\n", record.Network)
    fmt.Printf("IP Address: %v\n", record.IPAddress)
}

Connection Type Database

The Connection Type database identifies the connection type of an IP address.

package main

import (
    "fmt"
    "log"
    "net/netip"

    "github.com/oschwald/geoip2-golang/v2"
)

func main() {
    db, err := geoip2.Open("GeoIP2-Connection-Type.mmdb")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    ip, err := netip.ParseAddr("1.0.128.0")
    if err != nil {
        log.Fatal(err)
    }

    record, err := db.ConnectionType(ip)
    if err != nil {
        log.Fatal(err)
    }

    if !record.HasData() {
        fmt.Println("No data found for this IP")
        return
    }

    fmt.Printf("Connection Type: %v\n", record.ConnectionType)
    fmt.Printf("Network: %v\n", record.Network)
    fmt.Printf("IP Address: %v\n", record.IPAddress)
}

Error Handling

All database lookups can return errors and should be handled appropriately:

```go package main

import ( "fmt" "log" "net/netip"

"github.com/oschwald/geoip2-golang/v2"

)

func main() { db, err := geoip2.Open("GeoIP2-City.mmdb") if err != nil { log.Fatal(err) } defer db.Close()

ip, err := netip.ParseAddr("10.0.0.1") // Private IP
if err != nil {
    log.Fatal(err)
}

record, err := db.City(ip)
if err != nil {
    log.Fatal(err)
}

//

Extension points exported contracts — how you extend this code

Option (FuncType)
Option configures Reader behavior.
reader.go

Core symbols most depended-on inside this repo

HasData
called by 40
models.go
Open
called by 25
reader.go
Close
called by 25
reader.go
Metadata
called by 10
reader.go
City
called by 8
reader.go
ASN
called by 5
reader.go
AnonymousPlus
called by 4
reader.go
HasData
called by 3
models.go

Shape

Method 42
Function 31
Struct 29
FuncType 1
TypeAlias 1

Languages

Go100%

Modules by API surface

models.go54 symbols
reader.go23 symbols
reader_test.go17 symbols
example_test.go10 symbols

Dependencies from manifests, versioned

github.com/oschwald/maxminddb-golang/v2v2.3.0 · 1×
github.com/pmezard/go-difflibv1.0.0 · 1×
golang.org/x/sysv0.44.0 · 1×
gopkg.in/yaml.v3v3.0.1 · 1×

For agents

$ claude mcp add geoip2-golang \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact