I recently put together a small website, ipmutton.com. It does one thing: it shows you the connection the rest of the internet actually sees — your IPv4 and IPv6 address, approximate location, ISP / ASN, reverse DNS, the TLS/HTTP details of your request, and a live round-trip time to the server. That’s it. No login, no tracking, no clutter.

A reboot of an old project

IP Mutton isn’t new — I ran a simple little website under the same name years ago. This is a reboot of that project: same name, rebuilt from scratch with modern design principles and a fresh new look.

I wanted something I’d actually enjoy opening: it loads instantly, shows both address families side by side, and makes zero third-party requests — a strict Content-Security-Policy on the page makes that promise enforceable, not just a claim. The world map, the share image, everything is self-contained.

The IP Mutton page: IPv4 and IPv6 address cards, a dotted world map with an arc from the visitor to the server, and a connection-details panel.
The whole page — IPv4/IPv6 cards, the live map with a round-trip arc to the server, and the connection details. (Shown here with a simulated visitor in Mumbai; the addresses are documentation-range placeholders.)

A few things that fell out of that goal:

  • Real dual-stack. A single TCP connection is either IPv4 or IPv6, never both — so a normal page can only ever show you one. IP Mutton publishes two extra probe hostnames (v4.ipmutton.com, v6.ipmutton.com) that are forced onto each family, fetches both, and shows you each address (or tells you honestly that you don’t have one).
  • A genuine round-trip number. The probe hosts hit the origin server directly (no CDN in the path), so the latency you see is really you ↔ the server, pinned on a map with the great-circle distance.
  • Tiny and private. It’s a single ~12 MB Go service. Geolocation is a local, memory-mapped database, so your address isn’t shipped off to some third-party geo-IP API to look it up.

The part I’m most happy about: the JSON API

The pretty page is nice for humans, but the reason I reach for IP Mutton myself is the clean JSON API. The same endpoint serves a browser an HTML page, but hand it ?format=json (or hit /api) and you get a tidy, predictable snapshot — perfect for scripts, monitoring, and CI.

curl 'https://ipmutton.com/?format=json'
# or the alias:
curl 'https://ipmutton.com/api'

The output is a single flat-ish object with sensible keys and real types (numbers are numbers, missing values are null — not the empty strings or stringified numbers you often get elsewhere):

{
  "ipv4": "203.0.113.10",
  "ipv6": "2001:db8:42::1",
  "address_family": "IPv4",
  "reverse_dns": "cpe-203-0-113-10.example.net",
  "geolocation": {
    "city": "Austin",
    "region": "Texas",
    "country": "United States",
    "country_code": "US",
    "postal_code": "78701",
    "time_zone": "America/Chicago",
    "latitude": 30.27,
    "longitude": -97.74
  },
  "isp": {
    "name": "Example Broadband",
    "asn": 64500,
    "network": "203.0.113.0/24"
  },
  "server": {
    "location": "Tampa, Florida, United States",
    "latitude": 28.01,
    "longitude": -82.49
  },
  "http_version": "HTTP/2.0",
  "scheme": "https",
  "tls_version": "TLS 1.3",
  "tls_cipher": "TLS_AES_128_GCM_SHA256",
  "server_time_utc": "2026-06-23T11:26:54Z",
  "cloudflare": { "ray_id": "a10323…-MIA", "colo": "MIA", "country": "US" },
  "browser": { "language": "en-US", "platform": "macOS" },
  "user_agent": "Mozilla/5.0 …"
}

Because each probe host is locked to one address family, you can ask for exactly the one you want — and the unused family comes back null:

curl 'https://v4.ipmutton.com/?format=json'   # IPv4-only view
curl 'https://v6.ipmutton.com/?format=json'   # IPv6-only view

That makes the common one-liners trivial. Want just your public IPv4 for a script? Pipe it through jq:

# Your public IPv4, nothing else
curl -s 'https://v4.ipmutton.com/?format=json' | jq -r .ipv4
# 203.0.113.10

# Your ISP and ASN
curl -s 'https://ipmutton.com/api' | jq -r '.isp | "\(.name) (AS\(.asn))"'
# Example Broadband (AS64500)

# Are you reaching the internet over IPv6 right now?
curl -s 'https://ipmutton.com/api' | jq -r .address_family
# IPv4

And if you don’t even want JSON — just running curl against the site (with no flags) gives you a clean Unicode table, because the server notices the curl/ user-agent and formats accordingly:

┌───────────────┬─────────────────────────────────┐
│ FIELD         │ VALUE                           │
├───────────────┼─────────────────────────────────┤
│ IPv4          │ 203.0.113.10                    │
│ IPv6          │ 2001:db8:42::1                  │
│ Connected via │ IPv4                            │
│ Network CIDR  │ 203.0.113.0/24                  │
│ Reverse DNS   │ cpe-203-0-113-10.example.net    │
│ Location      │ Austin, Texas, United States    │
│ Server        │ Tampa, Florida, United States   │
│ ISP / Network │ Example Broadband (AS64500)     │
│ HTTP          │ https                           │
│ TLS           │ TLS 1.3                         │
│ Cloudflare    │ MIA · US · a10323…-MIA          │
│ Server Time   │ 2026-06-23T11:26:54Z            │
│ User Agent    │ curl/8.14.1                     │
└───────────────┴─────────────────────────────────┘

One URL, three audiences: a polished page for people, a clean table for the terminal, and structured JSON for machines — and not a single ad in sight.

Try it

Point a browser at ipmutton.com, or from a terminal:

curl ipmutton.com                       # the table
curl 'ipmutton.com/?format=json' | jq   # the JSON