Get Your Public IP with curl
Copy a working command to print your public IP from curl, wget, HTTPie, PowerShell or Python, in plain text or JSON.
Try it, with your own connection
The outputs below are not samples. They are what these commands return for you right now, rendered on the server. Your address is 216.73.216.7, seen from Columbus, Ohio, United States on Anthropic, PBC (AS16509).
curl whatsmyip.fyi216.73.216.7Content negotiation at the apex. curl gets text, a browser gets the page.
curl -s https://whatsmyip.fyi/ip216.73.216.7The explicit endpoint. Use this one in scripts.
curl -s https://whatsmyip.fyi/json | jq -r '.ip, .country, .isp'216.73.216.7 US Anthropic, PBCThe JSON record, three fields of it.
curl -s https://whatsmyip.fyi/ip.md# Your public IP IP: 216.73.216.7 (IPv4) Location: Columbus, Ohio, US (approximate) ISP: Anthropic, PBC (AS16509) Source: https://whatsmyip.fyi/ip.mdSmall enough to paste into a prompt, and it carries its own source URL.
The short version
curl whatsmyip.fyi
Prints your public address and a newline. Nothing else.
Plain text
# the apex, using content negotiation
curl whatsmyip.fyi
# the explicit endpoint, better in scripts
curl -s https://whatsmyip.fyi/ip
Use /ip in a script. It does not depend on your HTTP library sending a User-Agent the server recognises.
Forcing one address family
# IPv4 only
curl -4 v4.whatsmyip.fyi
# IPv6 only
curl -6 v6.whatsmyip.fyi
v4. has an A record only and v6. has an AAAA record only, so a success proves that family works end to end. Running curl -4 against the dual-stack apex only tells curl which family to prefer; it does not prove the other one is missing.
If curl -6 v6.whatsmyip.fyi fails with “Could not resolve host” or “Network is unreachable”, you have no working IPv6. See /ipv6-test for the diagnosis.
JSON
# the full record
curl -s https://whatsmyip.fyi/json
# just the address
curl -s https://whatsmyip.fyi/json | jq -r .ip
# a few fields
curl -s https://whatsmyip.fyi/json | jq -r '.ip, .country, .isp'
# with reverse DNS and privacy flags
curl -s 'https://whatsmyip.fyi/json?full=1' | jq .
# force JSON from any client
curl -s 'https://whatsmyip.fyi/?format=json' | jq .
# or ask for it with a header
curl -s -H 'Accept: application/json' https://whatsmyip.fyi
?full=1 adds hostname and the privacy object, both null otherwise. It costs a provider lookup, so it is slower and separately rate limited.
Markdown for agents
curl -s https://whatsmyip.fyi/ip.md
# Your public IP
IP: 203.0.113.45 (IPv4)
Location: Tallinn, Harju, EE (approximate)
ISP: Telia Eesti (AS3249)
Source: https://whatsmyip.fyi/ip.md
Short enough to paste into a prompt, and it carries its own source URL.
Other tools
# Wget
wget -qO- https://whatsmyip.fyi/ip
# Wget, IPv6 only
wget -6 -qO- https://v6.whatsmyip.fyi/ip
# HTTPie
http --body whatsmyip.fyi/ip
http --body whatsmyip.fyi/json
# Python
python3 -c "import urllib.request;print(urllib.request.urlopen('https://whatsmyip.fyi/ip').read().decode().strip())"
PowerShell, on Windows or anywhere else:
# plain text
(Invoke-RestMethod https://whatsmyip.fyi/ip).Trim()
# JSON, as an object
$r = Invoke-RestMethod https://whatsmyip.fyi/json
$r.ip
$r.isp
# IPv4 only
(Invoke-RestMethod https://v4.whatsmyip.fyi/ip).Trim()
Invoke-RestMethod parses JSON automatically. Use Invoke-WebRequest and read .Content if you want the raw body.
Using it in a script
The single-line version is fine interactively and bad in a cron job. This version sets timeouts, retries with backoff, fails loudly, and validates what it got back:
#!/usr/bin/env bash
set -euo pipefail
get_public_ip() {
curl --silent --show-error --fail \
--connect-timeout 5 --max-time 10 \
--retry 3 --retry-delay 2 --retry-max-time 30 \
--retry-all-errors \
https://whatsmyip.fyi/ip
}
ip="$(get_public_ip | tr -d '[:space:]')"
if [[ ! "$ip" =~ ^[0-9a-fA-F:.]+$ ]]; then
echo "unexpected response: $ip" >&2
exit 1
fi
echo "$ip"
What each part is for:
--failmakes curl exit non-zero on an HTTP error instead of writing the error body to stdout. Without it, a 429 page ends up in your variable and your script carries on with garbage.--connect-timeoutand--max-timestop a hung connection from stalling a scheduled job indefinitely.--retrywith--retry-all-errorsretries transient failures. curl honours aRetry-Afterheader when it retries a 429, so it waits the time the server asked for rather than hammering.- The regex check catches the case where something in the path, a captive portal for instance, returned an HTML page with a 200 status.
For a dual-stack script, query both and treat a failure of either as informational rather than fatal:
v4="$(curl -s --max-time 5 https://v4.whatsmyip.fyi/ip || echo none)"
v6="$(curl -s --max-time 5 https://v6.whatsmyip.fyi/ip || echo none)"
printf 'IPv4: %s\nIPv6: %s\n' "$v4" "$v6"
Rate limits
| Endpoint | Limit | Over the limit |
|---|---|---|
/ip, /json, /ip.md, /api/v1/ip |
1,000 per day, 60 per minute | 429 with Retry-After |
| Lookup endpoints | 200 per day, 20 per minute | 429, a bot challenge after 50 per day |
Limits are per source address and need no key. Every response carries the remaining quota in its headers, so a well-behaved client can slow down before it is refused.
When you get a 429, read Retry-After. It is a number of seconds, and it is not advisory:
resp="$(curl -s -D /tmp/h -o /tmp/b -w '%{http_code}' https://whatsmyip.fyi/ip)"
if [[ "$resp" == "429" ]]; then
wait="$(grep -i '^retry-after:' /tmp/h | tr -d '\r' | awk '{print $2}')"
echo "rate limited, waiting ${wait}s" >&2
sleep "${wait:-60}"
fi
A script that checks once a minute makes 1,440 requests a day, which is over the daily limit. Cache the value and re-check when the network changes rather than on a timer. Your public address does not change every minute.
About this tool
One short command in a terminal returns your public address, and every command on this page works as written. It covers the plain text endpoint, JSON with and without enrichment, forcing IPv4 or IPv6, parsing with jq, the Markdown payload meant for agents, and the equivalents in wget, HTTPie, PowerShell, and Python. It ends with the rate limits and how to write a script that behaves when it reaches them.
How to read the result
- curl whatsmyip.fyi
- The short command. It returns your address and a trailing newline as text/plain, because the server reads the User-Agent and Accept headers and sends plain text to a known CLI tool.
- /ip
- The explicit plain text endpoint, and the one to use in scripts. Asking for it directly keeps the behaviour independent of whatever User-Agent your HTTP library sends.
- /json and ?full=1
- The full record as structured data, in the documented schema. Without full=1 the hostname and privacy fields are null and no external provider is called, and with it you get reverse DNS and privacy flags, and a slower response.
- /ip.md
- A small Markdown document with the address, location, ISP, and a source URL. It is meant for agents and language models that handle Markdown better than JSON, and it is small enough to paste into a prompt.
- v4. and v6. hostnames
- v4.whatsmyip.fyi publishes an A record only, and v6.whatsmyip.fyi an AAAA record only. Neither can fall back to the other family, so a successful request proves that family works, which curl -4 against a dual-stack host does not.
- Rate limit headers and 429
- Every response carries the quota you have left. Going over 1,000 per day or 60 per minute returns HTTP 429 with a Retry-After header in seconds, and a client that ignores it keeps getting 429.
Questions people ask
- Why does curl get plain text while my browser gets a web page?
- The server checks the User-Agent and the Accept header. Requests from curl, wget, HTTPie, PowerShell, python-requests, and Go's HTTP client, or any request whose Accept header does not include text/html, get text/plain. Everything else gets HTML. Add ?format=json to force JSON from any client.
- How do I get only the IP in a shell variable?
- Use the plain endpoint, which returns nothing else - IP=$(curl -s https://whatsmyip.fyi/ip). Add --fail so a 429 or 500 does not silently put an HTML error page into the variable, and add a timeout so a hung connection does not stall the script.
- What are the rate limits?
- 1,000 requests per day and 60 per minute per source address for /ip, /json, /ip.md, and /api/v1/ip. Lookup endpoints are 200 per day and 20 per minute. No key is needed for any of it. Over the limit you get 429 with a Retry-After header.
- Can I use this in production?
- Yes, within the limits, with no key. Handle 429 by honouring Retry-After, set a timeout, and have a fallback, which is sensible against any free service including this one. If you need higher volume, the keyed tier exists for that.
- Does it support IPv6?
- Yes. The apex is dual-stack, so curl picks a family. v6.whatsmyip.fyi is IPv6-only and v4.whatsmyip.fyi is IPv4-only, which is how you test one family specifically rather than asking curl to prefer one.
Related
Last reviewed 2026-09-05.