How to get client’s IP address using JavaScript?

I would use a web service that can return JSON (along with jQuery to make things simpler). Below are all the active free IP lookup services I could find and the information they return. If you know of others, then please add a comment and I’ll update this answer.


Abstract

let apiKey = '1be9a6884abd4c3ea143b59ca317c6b2';
$.getJSON('https://ipgeolocation.abstractapi.com/v1/?api_key=' + apiKey, function(data) {
  console.log(JSON.stringify(data, null, 2));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>

 Run code snippetExpand snippet

Limitations:

  • 10,000 requests per month
  • Requires registration to get your API key

BigDataCloud

// Base
let apiKey = 'd9e53816d07345139c58d0ea733e3870';
$.getJSON('https://api.bigdatacloud.net/data/ip-geolocation?key=' + apiKey, function(data) {
  console.log(JSON.stringify(data, null, 2));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>

 Run code snippetExpand snippet

// Base + Confidence Area
let apiKey = 'd9e53816d07345139c58d0ea733e3870';
$.getJSON('https://api.bigdatacloud.net/data/ip-geolocation-with-confidence?key=' + apiKey, function(data) {
  console.log(JSON.stringify(data, null, 2));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>

 Run code snippetExpand snippet

// Base + Confidence Area + Hazard Report
let apiKey = 'd9e53816d07345139c58d0ea733e3870';
$.getJSON('https://api.bigdatacloud.net/data/ip-geolocation-full?key=' + apiKey, function(data) {
  console.log(JSON.stringify(data, null, 2));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>

 Run code snippetExpand snippet

Limitations:

  • 10,000 requests per month
  • Requires registration to get your API key

Cloudflare

$.get('https://www.cloudflare.com/cdn-cgi/trace', function(data) {
  // Convert key-value pairs to JSON
  // https://stackoverflow.com/a/39284735/452587
  data = data.trim().split('\n').reduce(function(obj, pair) {
    pair = pair.split('=');
    return obj[pair[0]] = pair[1], obj;
  }, {});
  console.log(data);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>

 Run code snippetExpand snippet

Limitations:

  • Returns plain text
  • Returns only IPv6 address if you have that

DB-IP

Try it: https://api.db-ip.com/v2/free/self

$.getJSON('https://api.db-ip.com/v2/free/self', function(data) {
  console.log(JSON.stringify(data, null, 2));
});

Returns:

{
  "ipAddress": "116.12.250.1",
  "continentCode": "AS",
  "continentName": "Asia",
  "countryCode": "SG",
  "countryName": "Singapore",
  "city": "Singapore (Queenstown Estate)"
}

Limitations:

  • 1,000 requests per day
  • Requires non-null Origin request header

Geobytes

Try it: http://gd.geobytes.com/GetCityDetails

$.getJSON('http://gd.geobytes.com/GetCityDetails?callback=?', function(data) {
  console.log(JSON.stringify(data, null, 2));
});

Returns:

{
  "geobytesforwarderfor": "",
  "geobytesremoteip": "116.12.250.1",
  "geobytesipaddress": "116.12.250.1",
  "geobytescertainty": "99",
  "geobytesinternet": "SA",
  "geobytescountry": "Saudi Arabia",
  "geobytesregionlocationcode": "SASH",
  "geobytesregion": "Ash Sharqiyah",
  "geobytescode": "SH",
  "geobyteslocationcode": "SASHJUBA",
  "geobytescity": "Jubail",
  "geobytescityid": "13793",
  "geobytesfqcn": "Jubail, SH, Saudi Arabia",
  "geobyteslatitude": "27.004999",
  "geobyteslongitude": "49.660999",
  "geobytescapital": "Riyadh ",
  "geobytestimezone": "+03:00",
  "geobytesnationalitysingular": "Saudi Arabian ",
  "geobytespopulation": "22757092",
  "geobytesnationalityplural": "Saudis",
  "geobytesmapreference": "Middle East ",
  "geobytescurrency": "Saudi Riyal",
  "geobytescurrencycode": "SAR",
  "geobytestitle": "Saudi Arabia"
}

Limitations:

  • 16,384 requests per hour
  • No SSL (https) with the free plan
  • Can return the wrong location

GeoIPLookup.io

$.getJSON('https://json.geoiplookup.io/?callback=?', function(data) {
  console.log(JSON.stringify(data, null, 2));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>

 Run code snippetExpand snippet

Limitations:

  • 10,000 requests per hour
  • Free plan only for non-commercial use
  • Returns only IPv6 address if you have that

geoPlugin

Try it: http://www.geoplugin.net/json.gp

$.getJSON('http://www.geoplugin.net/json.gp', function(data) {
  console.log(JSON.stringify(data, null, 2));
});

Returns:

{
  "geoplugin_request": "116.12.250.1",
  "geoplugin_status": 200,
  "geoplugin_credit": "Some of the returned data includes GeoLite data created by MaxMind, available from <a href=\\'http://www.maxmind.com\\'>http://www.maxmind.com</a>.",
  "geoplugin_city": "Singapore",
  "geoplugin_region": "Singapore (general)",
  "geoplugin_areaCode": "0",
  "geoplugin_dmaCode": "0",
  "geoplugin_countryCode": "SG",
  "geoplugin_countryName": "Singapore",
  "geoplugin_continentCode": "AS",
  "geoplugin_latitude": "1.2931",
  "geoplugin_longitude": "103.855797",
  "geoplugin_regionCode": "00",
  "geoplugin_regionName": "Singapore (general)",
  "geoplugin_currencyCode": "SGD",
  "geoplugin_currencySymbol": "&#36;",
  "geoplugin_currencySymbol_UTF8": "$",
  "geoplugin_currencyConverter": 1.4239
}

Limitations:

  • 120 requests per minute
  • No SSL (https) with the free plan

Hacker Target

$.get('https://api.hackertarget.com/geoip/?q=116.12.250.1', function(data) {
  // Convert key-value pairs to JSON
  // https://stackoverflow.com/a/39284735/452587
  data = data.trim().split('\n').reduce(function(obj, pair) {
    pair = pair.split(': ');
    return obj[pair[0]] = pair[1], obj;
  }, {});
  console.log(data);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>

 Run code snippetExpand snippet

Limitations:

  • 100 requests per day
  • Requires IP address parameter
  • Returns plain text

ipapi

Try it: https://ipapi.co/json/

$.getJSON('https://ipapi.co/json/', function(data) {
  console.log(JSON.stringify(data, null, 2));
});

Returns:

{
  "ip": "116.12.250.1",
  "city": "Singapore",
  "region": "Central Singapore Community Development Council",
  "country": "SG",
  "country_name": "Singapore",
  "postal": null,
  "latitude": 1.2855,
  "longitude": 103.8565,
  "timezone": "Asia/Singapore"
}

Limitations:

  • 1,000 requests per day
  • Requires SSL (https)
  • Requires non-null Origin request header
  • Returns only IPv6 address if you have that

IP-API

Try it: http://ip-api.com/json

$.getJSON('http://ip-api.com/json', function(data) {
  console.log(JSON.stringify(data, null, 2));
});

Returns:

{
  "as": "AS3758 SingNet",
  "city": "Singapore",
  "country": "Singapore",
  "countryCode": "SG",
  "isp": "SingNet Pte Ltd",
  "lat": 1.2931,
  "lon": 103.8558,
  "org": "Singapore Telecommunications",
  "query": "116.12.250.1",
  "region": "01",
  "regionName": "Central Singapore Community Development Council",
  "status": "success",
  "timezone": "Asia/Singapore",
  "zip": ""
}

Limitations:

  • 150 requests per minute
  • No SSL (https) with the free plan

ipdata

let apiKey = 'be0f755b93290b4c100445d77533d291763a417c75524e95e07819ad';
$.getJSON('https://api.ipdata.co?api-key=' + apiKey, function(data) {
  console.log(JSON.stringify(data, null, 2));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>

 Run code snippetExpand snippet

Limitations:

  • 1,500 requests per day
  • Requires registration to get your API key
  • Requires SSL (https)

IP Find

let apiKey = '50e887ce-e3bb-4f00-a9b9-667597db5539';
$.getJSON('https://ipfind.co/me?auth=' + apiKey, function(data) {
  console.log(JSON.stringify(data, null, 2));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>

 Run code snippetExpand snippet

Limitations:

  • 300 requests per day
  • Requires registration to get your API key

ipgeolocation

let apiKey = 'f8e0b361e8f4405c94613ab534959fdf';
$.getJSON('https://api.ipgeolocation.io/ipgeo?apiKey=' + apiKey, function(data) {
  console.log(JSON.stringify(data, null, 2));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>

 Run code snippetExpand snippet

Limitations:

  • 50,000 requests per month
  • Requires registration to get your API key
  • Returns only IPv6 address if you have that

ipify

$.getJSON('https://api.ipify.org?format=jsonp&callback=?', function(data) {
  console.log(JSON.stringify(data, null, 2));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>

 Run code snippetExpand snippet

Limitations:

  • None

IPInfoDB

let apiKey = '25864308b6a77fd90f8bf04b3021a48c1f2fb302a676dd3809054bc1b07f5b42';
$.getJSON('https://api.ipinfodb.com/v3/ip-city/?format=json&key=' + apiKey, function(data) {
  console.log(JSON.stringify(data, null, 2));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>

 Run code snippetExpand snippet

Limitations:

  • Two requests per second
  • Requires registration to get your API key

ipinfo.io

$.getJSON('https://ipinfo.io/json', function(data) {
  console.log(JSON.stringify(data, null, 2));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>

 Run code snippetExpand snippet

Limitations:

  • 50,000 requests per month

ipregistry

$.getJSON('https://api.ipregistry.co/?key=tryout', function(data) {
  console.log(JSON.stringify(data, null, 2));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>

 Run code snippetExpand snippet

Limitations:

  • Free plan includes 100,000 requests
  • Requires registration to get your API key
  • Returns only IPv6 address if you have that

ipstack (formerly freegeoip.net)

Try it: http://api.ipstack.com/<ip_address>?access_key=<your_api_key>

$.getJSON('http://api.ipstack.com/<ip_address>?access_key=<your_api_key>', function(data) {
  console.log(JSON.stringify(data, null, 2));
});

Returns:

{
  "ip": "116.12.250.1",
  "type": "ipv4",
  "continent_code": "AS",
  "continent_name": "Asia",
  "country_code": "SG",
  "country_name": "Singapore",
  "region_code": "01",
  "region_name": "Central Singapore Community Development Council",
  "city": "Singapore",
  "zip": null,
  "latitude": 1.2931,
  "longitude": 103.8558,
  "location": {
    "geoname_id": 1880252,
    "capital": "Singapore",
    "languages": [
      {
        "code": "en",
        "name": "English",
        "native": "English"
      },
      {
        "code": "ms",
        "name": "Malay",
        "native": "Bahasa Melayu"
      },
      {
        "code": "ta",
        "name": "Tamil",
        "native": "தமிழ்"
      },
      {
        "code": "zh",
        "name": "Chinese",
        "native": "中文"
      }
    ],
    "country_flag": "http://assets.ipstack.com/flags/sg.svg",
    "country_flag_emoji": "🇸🇬",
    "country_flag_emoji_unicode": "U+1F1F8 U+1F1EC",
    "calling_code": "65",
    "is_eu": false
  }
}

Limitations:

  • 10,000 requests per month
  • Requires IP address parameter
  • Requires registration to get your API key
  • No SSL (https) with the free plan

jsonip.com

$.getJSON('https://jsonip.com/', function(data) {
  console.log(JSON.stringify(data, null, 2));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>

 Run code snippetExpand snippet

Limitations:

  • Returns only IPv6 address if you have that

JSON Test

Try it: http://ip.jsontest.com/

$.getJSON('http://ip.jsontest.com/', function(data) {
  console.log(JSON.stringify(data, null, 2));
});

Returns:

{
  "ip": "116.12.250.1"
}

Limitations:

  • No SSL (https)
  • Returns only IPv6 address if you have that

Snoopi.io

let apiKey = 'ed5ebbeba257b8f262a6a9bbc0ec678e';
$.getJSON('https://api.snoopi.io/116.12.250.1?apikey=' + apiKey, function(data) {
  console.log(JSON.stringify(data, null, 2));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>

 Run code snippetExpand snippet

Limitations:

  • 10,000 requests per month
  • 1 request every 2 seconds
  • Requires IP address parameter
  • Requires registration to get your API key

VANILLA JAVASCRIPT

With modern browsers, you can use the native Fetch API instead of relying on jQuery’s $.getJSON(). Here’s an example:

let apiKey = '1be9a6884abd4c3ea143b59ca317c6b2';
// Make the request
fetch('https://ipgeolocation.abstractapi.com/v1/?api_key=' + apiKey)
  // Extract JSON body content from HTTP response
  .then(response => response.json())
  // Do something with the JSON data
  .then(data => {
    console.log(JSON.stringify(data, null, 2))
  });

 Run code snippetExpand snippet

NOTES

  • Since these are all free services, who knows when/if they will be taken offline down the road (exhibit A: Telize).
  • Most of these services also offer a paid tier in case you want more features and stability.
  • As @skobaljic noted in the comments below, the request quotas are mostly academic since calls are happening client-side and most end users will never exceed their quota.
  • Some services don’t have runnable snippets because they don’t allow SSL connections in the free plan or require a non-null Origin request header (StackOverflow snippets are forced to use https and have Origin: null in the request headers).

UPDATES

  • 2/1/2016: Removed Telize (no longer offers free plan)
  • 4/18/2016: Removed freegeoip.net (out of service)
  • 4/26/2016: Added DB-IP
  • 4/26/2016: Added Hacker Target
  • 7/6/2016: Reinstated freegeoip.net
  • 7/6/2016: Removed ip-json.rhcloud.com (dead link)
  • 12/21/2016: Removed Hacker Target (out of service)
  • 2/10/2017: Added Nekudo
  • 4/20/2017: Added ipapi (thanks Ahmad Awais)
  • 4/24/2017: Reinstated Hacker Target
  • 4/24/2017: Removed Snoopi.io (out of service)
  • 7/16/2017: Added limitation “No SSL (https) with the free plan”
  • 7/16/2017: Added IP Find (thanks JordanC)
  • 9/25/2017: Added Stupid Web Tools (thanks Cœur)
  • 3/16/2018: Added ipdata (thanks Jonathan)
  • 4/14/2018: Renamed freegeoip.net to ipstack (thanks MA-Maddin)
  • 4/16/2018: Added GeoIPLookup.io (thanks Rob Waa)
  • 6/11/2018: Added ipgeolocation (thanks Ejaz Ahmed)
  • 7/31/2019: Added ipregistry (thanks Laurent)
  • 8/16/2019: Added SmartIP.io (thanks kevinj)
  • 8/22/2019: Removed Stupid Web Tools (out of service)
  • 12/10/2019: Added Cloudflare
  • 1/9/2020: Removed SmartIP.io (out of service)
  • 11/6/2020: Added Abstract
  • 11/13/2020: Added AstroIP.co
  • 4/13/2021: Replaced code samples with snippets (was getting close to 30k character limit)
  • 4/13/2021: Added code to convert key-value pairs to JSON for plain text responses
  • 4/13/2021: Added limitation “Requires non-null Origin request header”
  • 4/13/2021: Added BigDataCloud
  • 4/13/2021: Reinstated Snoopi.io
  • 4/13/2021: Removed AstroIP.co (out of service)
  • 4/13/2021: Removed Nekudo (now part of ipapi)

Leave a Comment