net.info API

v3.6.6

Enable location-based experiences, security and analytics with city-level ip geolocation information, including latitude, longitude, time zone, postal code, and more.

Free IP geolocation. No API key is required. Legacy API-key headers are ignored.

Sources and Licenses explains the data providers, attribution requirements, and our work on geo-db.org.

To learn more about this service visit net.info

Server
https://net.info

ip address

Responses
200 Successfully got user IP info
ip string
type string `private` for private and other special-purpose addresses, which have no public location; otherwise `public`.
location object
{
  "ip": "string",
  "type": "private",
  "location": {
    "country": "string",
    "region": "string",
    "city": "string",
    "lat": 0,
    "lng": 0,
    "postalCode": "string",
    "timezone": "string",
    "geonameId": 0
  }
}
400 Bad Request
statusCode number
error string
message string The error message.
{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "Invalid IP Address"
}
404 Not Found
statusCode number
error string
message string The error message.
{
  "statusCode": 404,
  "error": "Not Found",
  "message": "IP Address not found: ::1"
}
429 Too Many Requests: the caller's budget cannot afford it
statusCode number
error string
message string The error message.
{
  "statusCode": 429,
  "error": "Too Many Requests",
  "message": "Lookup quota exceeded: the request costs 3; retry after 2s"
}
500 Internal Server Error
statusCode number
error string
message string The error message.
{
  "statusCode": 500,
  "error": "Internal Server Error",
  "message": "Unable to lookup Ip: ::1"
}
503 Service Unavailable: the lookup quota cannot be checked
statusCode number
error string
message string The error message.
{
  "statusCode": 503,
  "error": "Service Unavailable",
  "message": "The lookup quota is unavailable"
}
curl -X GET "https://net.info/ip"
const response = await fetch('https://net.info/ip', {
  method: 'GET'
});
const data = await response.json();
import requests

response = requests.get('https://net.info/ip')
data = response.json()
Test Request
GET
/ip
Request Body application/json
(items) string The IP address.
[
  "string"
]
Responses
200 Successfully get bulk IP info
data array(any)
{
  "data": [
    null
  ]
}
400 Bad Request
statusCode number
error string
message string The error message.
{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "Invalid IP Address"
}
429 Too Many Requests: the caller's budget cannot afford it
statusCode number
error string
message string The error message.
{
  "statusCode": 429,
  "error": "Too Many Requests",
  "message": "Lookup quota exceeded: the request costs 3; retry after 2s"
}
503 Service Unavailable: the lookup quota cannot be checked
statusCode number
error string
message string The error message.
{
  "statusCode": 503,
  "error": "Service Unavailable",
  "message": "The lookup quota is unavailable"
}
curl -X POST "https://net.info/ip" \
  -H "Content-Type: application/json" \
  -d '[  "string"]'
const response = await fetch('https://net.info/ip', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify([  "string"])
});
const data = await response.json();
import requests

response = requests.post(
    'https://net.info/ip',
    headers={
        'Content-Type': 'application/json'
    },
    json=[  "string"]
)
data = response.json()
Test Request
POST
/ip
Parameters
Name Type In Description
ipAddress * string path The IP address.
Responses
200 Successfully got IP info
ip string
type string `private` for private and other special-purpose addresses, which have no public location; otherwise `public`.
location object
{
  "ip": "string",
  "type": "private",
  "location": {
    "country": "string",
    "region": "string",
    "city": "string",
    "lat": 0,
    "lng": 0,
    "postalCode": "string",
    "timezone": "string",
    "geonameId": 0
  }
}
400 Bad Request
statusCode number
error string
message string The error message.
{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "Invalid IP Address"
}
404 Not Found
statusCode number
error string
message string The error message.
{
  "statusCode": 404,
  "error": "Not Found",
  "message": "IP Address not found: ::1"
}
429 Too Many Requests: the caller's budget cannot afford it
statusCode number
error string
message string The error message.
{
  "statusCode": 429,
  "error": "Too Many Requests",
  "message": "Lookup quota exceeded: the request costs 3; retry after 2s"
}
500 Internal Server Error
statusCode number
error string
message string The error message.
{
  "statusCode": 500,
  "error": "Internal Server Error",
  "message": "Unable to lookup Ip: ::1"
}
503 Service Unavailable: the lookup quota cannot be checked
statusCode number
error string
message string The error message.
{
  "statusCode": 503,
  "error": "Service Unavailable",
  "message": "The lookup quota is unavailable"
}
curl -X GET "https://net.info/ip/{ipAddress}"
const response = await fetch('https://net.info/ip/{ipAddress}', {
  method: 'GET'
});
const data = await response.json();
import requests

response = requests.get('https://net.info/ip/{ipAddress}')
data = response.json()
Test Request
GET
/ip/{ipAddress}
ipAddress path *

speed test

Lightweight endpoint for measuring latency and jitter, at rest and while a transfer loads the link. A failed probe is a failed HTTP request, not a lost packet.

Responses
200 Default Response
t number Server epoch time in milliseconds.
{
  "t": 0
}
curl -X GET "https://net.info/speedtest/ping"
const response = await fetch('https://net.info/speedtest/ping', {
  method: 'GET'
});
const data = await response.json();
import requests

response = requests.get('https://net.info/speedtest/ping')
data = response.json()
Test Request
GET
/speedtest/ping

Streams incompressible random data for measuring download throughput.

Parameters
Name Type In Description
bytes integer query Number of bytes to stream.
Responses
200 Default Response
curl -X GET "https://net.info/speedtest/download?bytes={bytes}"
const response = await fetch('https://net.info/speedtest/download?bytes={bytes}', {
  method: 'GET'
});
const data = await response.json();
import requests

response = requests.get(
    'https://net.info/speedtest/download',
    params={
    'bytes': '{bytes}'
    }
)
data = response.json()
Test Request
GET
/speedtest/download
bytes query

Accepts and discards an octet-stream body, returning the number of bytes received.

Responses
200 Default Response
bytes number Number of bytes received.
{
  "bytes": 0
}
curl -X POST "https://net.info/speedtest/upload"
const response = await fetch('https://net.info/speedtest/upload', {
  method: 'POST'
});
const data = await response.json();
import requests

response = requests.post('https://net.info/speedtest/upload')
data = response.json()
Test Request
POST
/speedtest/upload

Returns the caller's own IP geolocation and ISP/ASN for the speed test UI.

Responses
200 Default Response
ip string
type string
location object
dataVersion string
confirmations object
isp object
{
  "ip": "string",
  "type": "private",
  "location": {
    "country": "string",
    "region": "string",
    "city": "string",
    "lat": 0,
    "lng": 0,
    "postalCode": "string",
    "timezone": "string"
  },
  "dataVersion": "string",
  "confirmations": {
    "retentionDays": 0
  },
  "isp": {
    "asn": 0,
    "asnOrg": "string"
  }
}
curl -X GET "https://net.info/speedtest/whoami"
const response = await fetch('https://net.info/speedtest/whoami', {
  method: 'GET'
});
const data = await response.json();
import requests

response = requests.get('https://net.info/speedtest/whoami')
data = response.json()
Test Request
GET
/speedtest/whoami

Records a user-suggested correction to their detected location.

Request Body application/json
detected* object
suggested* object
browserLocation object
{
  "detected": {
    "country": "string",
    "region": "string",
    "city": "string",
    "lat": 0,
    "lng": 0,
    "postalCode": "string"
  },
  "suggested": {
    "country": "string",
    "region": "string",
    "city": "string",
    "lat": 0,
    "lng": 0,
    "postalCode": "string"
  },
  "browserLocation": {
    "lat": 0,
    "lng": 0,
    "accuracy": 0
  }
}
Responses
200 Default Response
id string
status string
{
  "id": "string",
  "status": "string"
}
curl -X POST "https://net.info/speedtest/location-suggestion" \
  -H "Content-Type: application/json" \
  -d '{  "detected": {    "country": "string",    "region": "string",    "city": "string",    "lat": 0,    "lng": 0,    "postalCode": "string"  },  "suggested": {    "country": "string",    "region": "string",    "city": "string",    "lat": 0,    "lng": 0,    "postalCode": "string"  },  "browserLocation": {    "lat": 0,    "lng": 0,    "accuracy": 0  }}'
const response = await fetch('https://net.info/speedtest/location-suggestion', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({  "detected": {    "country": "string",    "region": "string",    "city": "string",    "lat": 0,    "lng": 0,    "postalCode": "string"  },  "suggested": {    "country": "string",    "region": "string",    "city": "string",    "lat": 0,    "lng": 0,    "postalCode": "string"  },  "browserLocation": {    "lat": 0,    "lng": 0,    "accuracy": 0  }})
});
const data = await response.json();
import requests

response = requests.post(
    'https://net.info/speedtest/location-suggestion',
    headers={
        'Content-Type': 'application/json'
    },
    json={  "detected": {    "country": "string",    "region": "string",    "city": "string",    "lat": 0,    "lng": 0,    "postalCode": "string"  },  "suggested": {    "country": "string",    "region": "string",    "city": "string",    "lat": 0,    "lng": 0,    "postalCode": "string"  },  "browserLocation": {    "lat": 0,    "lng": 0,    "accuracy": 0  }}
)
data = response.json()
Test Request
POST
/speedtest/location-suggestion

Records that the location detected for the caller's address is right. The service detects the location again and records it with the version of the data it came from, keeping the record for the number of days whoami reports. If that location or data version no longer matches the one confirmed, nothing is recorded and the answer is 409. While confirmations are not recorded, the answer is 404.

Request Body application/json
id* string
dataVersion* string
purposeVersion* string
detected* object
browserLocation object
{
  "id": "string",
  "dataVersion": "string",
  "purposeVersion": "string",
  "detected": {
    "country": "string",
    "region": "string",
    "city": "string"
  },
  "browserLocation": {
    "lat": 0,
    "lng": 0,
    "accuracy": 0
  }
}
Responses
200 Default Response
id string
status string
{
  "id": "string",
  "status": "string"
}
curl -X POST "https://net.info/speedtest/location-confirmation" \
  -H "Content-Type: application/json" \
  -d '{  "id": "string",  "dataVersion": "string",  "purposeVersion": "string",  "detected": {    "country": "string",    "region": "string",    "city": "string"  },  "browserLocation": {    "lat": 0,    "lng": 0,    "accuracy": 0  }}'
const response = await fetch('https://net.info/speedtest/location-confirmation', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({  "id": "string",  "dataVersion": "string",  "purposeVersion": "string",  "detected": {    "country": "string",    "region": "string",    "city": "string"  },  "browserLocation": {    "lat": 0,    "lng": 0,    "accuracy": 0  }})
});
const data = await response.json();
import requests

response = requests.post(
    'https://net.info/speedtest/location-confirmation',
    headers={
        'Content-Type': 'application/json'
    },
    json={  "id": "string",  "dataVersion": "string",  "purposeVersion": "string",  "detected": {    "country": "string",    "region": "string",    "city": "string"  },  "browserLocation": {    "lat": 0,    "lng": 0,    "accuracy": 0  }}
)
data = response.json()
Test Request
POST
/speedtest/location-confirmation