Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get client's IP address using JavaScript?

I need to somehow retrieve the client's IP address using JavaScript; no server side code, not even SSI.

However, I'm not against using a free 3rd party script/service.

like image 260
FlySwat Avatar asked Dec 24 '08 18:12

FlySwat


People also ask

Can I get IP address from JavaScript?

To get the client's public IP address, JavaScript acts as a third-party server-side language. JavaScript can't do it alone, so, jQuery is added to do this. JavaScript works with third-party applications to fetch the IP addresses.

How do I get client IP from request?

In Java, you can use HttpServletRequest. getRemoteAddr() to get the client's IP address that's accessing your Java web application.

How do I get an IP address in HTML?

A solution could be: echo $_SERVER["REMOTE_ADDR"]; This actually gets the host ip, which would be your server. This correctly parses the HTTP_X_FORWARDED_FOR field as well as validating the IP to make sure it's of the right format, and not in a private block.


2 Answers

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>

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>

// 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>

// 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>

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>

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>

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>

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>

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>

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>

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>

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>

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>

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>

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>

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>

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))   });

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)
like image 171
thdoan Avatar answered Sep 23 '22 02:09

thdoan


UPDATE 2021:

As shown recently by a new Github repository, webrtc-ip, you can now leak a user's public IP address using WebRTC. Sadly, this leak does not work for private IPs, due to the gradual shift to mDNS (at least for WebRTC), completely explained here. However, here's a working demo:

getIPs().then(res => document.write(res.join('\n')))
<script src="https://cdn.jsdelivr.net/gh/joeymalvinni/webrtc-ip/dist/bundle.dev.js"></script>

The compiled source code for this repository can be found here.




(Previously) Final Update

This solution would not longer work because browsers are fixing webrtc leak: for more info on that read this other question: RTCIceCandidate no longer returning IP


Update: I always wanted to make a min/ uglified version of the code, so here is an ES6 Promise code:

var findIP = new Promise(r=>{var w=window,a=new (w.RTCPeerConnection||w.mozRTCPeerConnection||w.webkitRTCPeerConnection)({iceServers:[]}),b=()=>{};a.createDataChannel("");a.createOffer(c=>a.setLocalDescription(c,b,b),b);a.onicecandidate=c=>{try{c.candidate.candidate.match(/([0-9]{1,3}(\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/g).forEach(r)}catch(e){}}})  /*Usage example*/ findIP.then(ip => document.write('your ip: ', ip)).catch(e => console.error(e))

Note: This new minified code would return only single IP if you want all the IPs of the user( which might be more depending on his network), use the original code...


thanks to WebRTC, it is very easy to get local IP in WebRTC supported browsers( at least for now). I have modified the source code, reduced the lines, not making any stun requests since you only want Local IP, not the Public IP, the below code works in latest Firefox and Chrome, just run the snippet and check for yourself:

function findIP(onNewIP) { //  onNewIp - your listener function for new IPs   var myPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection; //compatibility for firefox and chrome   var pc = new myPeerConnection({iceServers: []}),     noop = function() {},     localIPs = {},     ipRegex = /([0-9]{1,3}(\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/g,     key;    function ipIterate(ip) {     if (!localIPs[ip]) onNewIP(ip);     localIPs[ip] = true;   }   pc.createDataChannel(""); //create a bogus data channel   pc.createOffer(function(sdp) {     sdp.sdp.split('\n').forEach(function(line) {       if (line.indexOf('candidate') < 0) return;       line.match(ipRegex).forEach(ipIterate);     });     pc.setLocalDescription(sdp, noop, noop);   }, noop); // create offer and set local description   pc.onicecandidate = function(ice) { //listen for candidate events     if (!ice || !ice.candidate || !ice.candidate.candidate || !ice.candidate.candidate.match(ipRegex)) return;     ice.candidate.candidate.match(ipRegex).forEach(ipIterate);   }; }    var ul = document.createElement('ul'); ul.textContent = 'Your IPs are: ' document.body.appendChild(ul);  function addIP(ip) {   console.log('got ip: ', ip);   var li = document.createElement('li');   li.textContent = ip;   ul.appendChild(li); }  findIP(addIP);
<h1> Demo retrieving Client IP using WebRTC </h1>

what is happening here is, we are creating a dummy peer connection, and for the remote peer to contact us, we generally exchange ice candidates with each other. And reading the ice candidates( from local session description and onIceCandidateEvent) we can tell the IP of the user.

where I took code from --> Source

like image 26
mido Avatar answered Sep 26 '22 02:09

mido