Scalable IP address API
Multi vendor support in IPv4 or IPv6. Deploy anywhere.
Your IP
loading...
IPv4
checking…
IPv6
checking…
Endpoints
The subdomain picks IPv4 or IPv6. The path picks the format.
| Host | Forces |
|---|---|
api.ipme.sh | IPv4 or IPv6 (whichever the client uses) |
ipv4.api.ipme.sh | IPv4 only (DNS has no AAAA record) |
ipv6.api.ipme.sh | IPv6 only (DNS has no A record) |
| Path | Content-Type | Example body |
|---|---|---|
/ or /ip |
text/plain |
203.0.113.42 |
/json |
application/json |
{"ip":"203.0.113.42"} |
/jsonp?callback=cb |
application/javascript |
cb({"ip":"203.0.113.42"}) |
/healthz |
(none) | 200 OK |
JSONP callbacks should be valid JavaScript identifiers. Anything else comes back as a 400.
Examples
cURL
# Default (whichever family resolves first)
curl https://api.ipme.sh
# Force IPv4 / IPv6 via DNS-only subdomains
curl https://ipv4.api.ipme.sh
curl https://ipv6.api.ipme.sh
# JSON
curl https://api.ipme.sh/json
JavaScript (browser fetch)
const r = await fetch('https://api.ipme.sh/json');
const { ip } = await r.json();
console.log(ip);
Python
import urllib.request, json
with urllib.request.urlopen('https://api.ipme.sh/json') as r:
print(json.load(r)['ip'])
# or with requests
import requests
print(requests.get('https://api.ipme.sh').text.strip())
Go
package main
import (
"encoding/json"
"fmt"
"net/http"
)
func main() {
r, _ := http.Get("https://api.ipme.sh/json")
defer r.Body.Close()
var out struct{ IP string }
json.NewDecoder(r.Body).Decode(&out)
fmt.Println(out.IP)
}
Node.js
const r = await fetch('https://api.ipme.sh/json');
const { ip } = await r.json();
console.log(ip);
Bash (dynamic DNS pattern)
#!/usr/bin/env bash
# Update record only when public IP changes.
set -euo pipefail
STATE=/var/lib/ipme/last-ip
mkdir -p "$(dirname "$STATE")"
NOW=$(curl -fsS https://api.ipme.sh)
LAST=$(cat "$STATE" 2>/dev/null || true)
if [[ "$NOW" != "$LAST" ]]; then
echo "IP changed: $LAST -> $NOW"
# update_dns_record "$NOW"
echo "$NOW" > "$STATE"
fi
PHP
$ip = trim(file_get_contents('https://api.ipme.sh'));
echo $ip;
// JSON
$data = json_decode(file_get_contents('https://api.ipme.sh/json'), true);
echo $data['ip'];
Ruby
require 'net/http'
require 'json'
ip = Net::HTTP.get(URI('https://api.ipme.sh')).strip
puts ip
data = JSON.parse(Net::HTTP.get(URI('https://api.ipme.sh/json')))
puts data['ip']
Rust (ureq)
let ip: String = ureq::get("https://api.ipme.sh")
.call()?
.into_string()?
.trim()
.to_string();
println!("{ip}");
Java
// Java 11+
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class IpMe {
public static void main(String[] args) throws Exception {
var client = HttpClient.newHttpClient();
var req = HttpRequest.newBuilder(URI.create("https://api.ipme.sh")).build();
var res = client.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(res.body().trim());
}
}
Kotlin (OkHttp)
// build.gradle.kts: implementation("com.squareup.okhttp3:okhttp:4.12.0")
import okhttp3.OkHttpClient
import okhttp3.Request
val client = OkHttpClient()
val req = Request.Builder().url("https://api.ipme.sh").build()
client.newCall(req).execute().use { res ->
println(res.body!!.string().trim())
}
For server-side Kotlin on JVM 11+, the stdlib java.net.http.HttpClient works without OkHttp. See the Java example above.
Swift (URLSession)
// iOS 15+ / macOS 12+, Swift 5.5+ (async/await)
import Foundation
struct IpResponse: Decodable { let ip: String }
let url = URL(string: "https://api.ipme.sh/json")!
let (data, _) = try await URLSession.shared.data(from: url)
let ip = try JSONDecoder().decode(IpResponse.self, from: data).ip
print(ip)
C# / .NET
// .NET 6+ (top-level statements)
using System.Text.Json;
using var http = new HttpClient();
// Text
var ip = (await http.GetStringAsync("https://api.ipme.sh")).Trim();
Console.WriteLine(ip);
// JSON
using var stream = await http.GetStreamAsync("https://api.ipme.sh/json");
var doc = await JsonDocument.ParseAsync(stream);
Console.WriteLine(doc.RootElement.GetProperty("ip").GetString());
PowerShell
# Text
(Invoke-WebRequest https://api.ipme.sh).Content.Trim()
# JSON (Invoke-RestMethod auto-parses)
(Invoke-RestMethod https://api.ipme.sh/json).ip
# Force IPv4 / IPv6 via DNS-only subdomains
(Invoke-RestMethod https://ipv4.api.ipme.sh/json).ip
(Invoke-RestMethod https://ipv6.api.ipme.sh/json).ip
Elixir (Req)
# mix.exs: {:req, "~> 0.5"}
# or one-off: Mix.install([:req])
# Text
Req.get!("https://api.ipme.sh").body |> String.trim() |> IO.puts()
# JSON (Req auto-decodes application/json)
Req.get!("https://api.ipme.sh/json").body["ip"] |> IO.puts()
JSONP (legacy cross-origin)
<script src="https://api.ipme.sh/jsonp?callback=showIP"></script>
<script>
function showIP(data) { console.log(data.ip); }
</script>
For anything new, fetch is a better fit. JSONP is mostly for older clients.