Skip to content

Go

Get geolocation data in your Go application.

Prerequisites

Usage

Basic lookup

go
package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"os"
)

type GeoResponse struct {
	Success bool    `json:"success"`
	Data    GeoData `json:"data"`
}

type GeoData struct {
	IP       string      `json:"ip"`
	IPType   string      `json:"ip_type"`
	Location GeoLocation `json:"location"`
	Time     GeoTime     `json:"time"`
	Currency GeoCurrency `json:"currency"`
	Network  GeoNetwork  `json:"network"`
}

type GeoLocation struct {
	ContinentCode       string   `json:"continent_code"`
	ContinentName       string   `json:"continent_name"`
	CountryCode         string   `json:"country_code"`
	CountryCodeISO3     string   `json:"country_code_iso3"`
	CountryName         string   `json:"country_name"`
	CountryCapital      string   `json:"country_capital"`
	CountryTLD          string   `json:"country_tld"`
	CountryCallingCode  string   `json:"country_calling_code"`
	CountryFlagEmoji    string   `json:"country_flag_emoji"`
	CountryLanguages    []string `json:"country_languages"`
	CountryAreaKm2      int64    `json:"country_area_km2"`
	CountryPopulation   int64    `json:"country_population"`
	CountryNeighbors    []string `json:"country_neighbors"`
	CountryIsEU         bool     `json:"country_is_eu"`
	RegionCode          string   `json:"region_code"`
	RegionName          string   `json:"region_name"`
	CityName            string   `json:"city_name"`
	PostalCode          string   `json:"postal_code"`
	Latitude            float64  `json:"latitude"`
	Longitude           float64  `json:"longitude"`
	WeatherCode         string   `json:"weather_code"`
}

type GeoTime struct {
	Zone             string `json:"zone"`
	Abbr             string `json:"abbr"`
	UTCOffset        string `json:"utc_offset"`
	UTCOffsetSeconds int    `json:"utc_offset_seconds"`
	CurrentTime      string `json:"current_time"`
	CurrentTimestamp int64  `json:"current_timestamp"`
	IsDST            bool   `json:"is_dst"`
}

type GeoCurrency struct {
	Code   string `json:"code"`
	Name   string `json:"name"`
	Symbol string `json:"symbol"`
}

type GeoNetwork struct {
	ASN             *int   `json:"asn,omitempty"`
	ASNOrganization string `json:"asn_organization"`
	ISP             string `json:"isp"`
	Organization    string `json:"organization"`
	ConnectionType  string `json:"connection_type"`
	UserType        string `json:"user_type"`
}

func main() {
	client := &http.Client{}

	req, _ := http.NewRequest("GET",
		"https://api.hummingbirdapi.com/v1/geo/lookup?ip=8.8.8.8", nil)
	req.Header.Set("X-API-Key", os.Getenv("HUMMINGBIRD_API_KEY"))

	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	var result GeoResponse
	json.NewDecoder(resp.Body).Decode(&result)

	if result.Success {
		fmt.Printf("Location: %s, %s\n",
			result.Data.Location.CityName, result.Data.Location.CountryName)
		fmt.Printf("Timezone: %s (%s)\n",
			result.Data.Time.Zone, result.Data.Time.Abbr)
		fmt.Printf("Currency: %s %s\n",
			result.Data.Currency.Symbol, result.Data.Currency.Code)
		// Location: Mountain View, United States
		// Timezone: America/Los_Angeles (PST)
		// Currency: $ USD
	}
}

Look up visitor's IP

Omit the ip parameter to look up the caller's IP address:

go
req, _ := http.NewRequest("GET",
	"https://api.hummingbirdapi.com/v1/geo/lookup", nil)
req.Header.Set("X-API-Key", os.Getenv("HUMMINGBIRD_API_KEY"))

resp, _ := client.Do(req)
defer resp.Body.Close()

var result GeoResponse
json.NewDecoder(resp.Body).Decode(&result)
fmt.Printf("Your IP: %s\n", result.Data.IP)

HTTP handler example

go
package main

import (
	"encoding/json"
	"net/http"
	"os"
)

func locationHandler(w http.ResponseWriter, r *http.Request) {
	clientIP := r.Header.Get("X-Forwarded-For")
	if clientIP == "" {
		clientIP = r.RemoteAddr
	}

	client := &http.Client{}
	req, _ := http.NewRequest("GET",
		"https://api.hummingbirdapi.com/v1/geo/lookup?ip="+clientIP, nil)
	req.Header.Set("X-API-Key", os.Getenv("HUMMINGBIRD_API_KEY"))

	resp, err := client.Do(req)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	defer resp.Body.Close()

	var result GeoResponse
	json.NewDecoder(resp.Body).Decode(&result)

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(result)
}

func main() {
	http.HandleFunc("/api/location", locationHandler)
	http.ListenAndServe(":8080", nil)
}

Error handling

go
type ApiResponse struct {
	Success      bool     `json:"success"`
	Data         *GeoData `json:"data"`
	Error        bool     `json:"error"`
	ErrorCode    *int     `json:"error_code"`
	ErrorMessage *string  `json:"error_message"`
}

func lookup(ip string) (*GeoData, error) {
	client := &http.Client{}
	req, _ := http.NewRequest("GET",
		"https://api.hummingbirdapi.com/v1/geo/lookup?ip="+ip, nil)
	req.Header.Set("X-API-Key", os.Getenv("HUMMINGBIRD_API_KEY"))

	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	var result ApiResponse
	json.NewDecoder(resp.Body).Decode(&result)

	if !result.Success {
		return nil, fmt.Errorf("error %d: %s",
			*result.ErrorCode, *result.ErrorMessage)
	}

	return result.Data, nil
}

Response

All responses use the unified envelope format with fields in this order: success, data, error, error_code, error_message.

json
{
  "success": true,
  "data": {
    "ip": "8.8.8.8",
    "ip_type": "ipv4",

    "location": {
      "continent_code": "NA",
      "continent_name": "North America",
      "country_code": "US",
      "country_code_iso3": "USA",
      "country_name": "United States",
      "country_capital": "Washington",
      "country_tld": ".us",
      "country_calling_code": "+1",
      "country_flag_emoji": "🇺🇸",
      "country_languages": ["en", "es"],
      "country_area_km2": 9833520,
      "country_population": 331449281,
      "country_neighbors": ["CA", "MX"],
      "country_is_eu": false,
      "region_code": "CA",
      "region_name": "California",
      "city_name": "Mountain View",
      "postal_code": "94043",
      "latitude": 37.386,
      "longitude": -122.084,
      "weather_code": "USCA0746"
    },

    "time": {
      "zone": "America/Los_Angeles",
      "abbr": "PST",
      "utc_offset": "-08:00",
      "utc_offset_seconds": -28800,
      "current_time": "2026-01-26T10:30:00-08:00",
      "current_timestamp": 1737913800,
      "is_dst": false
    },

    "currency": {
      "code": "USD",
      "name": "US Dollar",
      "symbol": "$"
    },

    "network": {
      "asn": 15169,
      "asn_organization": "Google LLC",
      "isp": "Google LLC",
      "organization": "Google LLC",
      "connection_type": "Corporate",
      "user_type": "hosting"
    }
  },
  "error": false,
  "error_code": null,
  "error_message": null
}

Next steps

Built with VitePress