See which country GeoIP databases, popular platforms, CDNs and AI services think your server is in, over IPv4 and IPv6.
- Features
- Dependencies
- Output
- Usage
- Docker
- Options
- How the checks work
- JSON
- Country codes
- Contributing
- Shows how GeoIP databases, popular platforms, CDNs and AI services see the host, side by side for IPv4 and IPv6
- Verdict - the country most services agree on - and an Attention list of services that see another country or failed to answer
- Groups: Platforms (YouTube, Netflix, ChatGPT, ...), Availability (YouTube Premium, Google Search, ...), AI (Gemini, OpenAI, Anthropic, Chinese providers), CDN edge nodes, GeoIP databases
- SOCKS5 proxy, custom network interface, JSON output
- Installs missing dependencies automatically on Debian, Ubuntu, Fedora, RHEL, Rocky, Alma, Arch, openSUSE, Alpine, Void and Termux
- bash 4.4+ (on macOS:
brew install bash) - curl
- jq
Note
Country flags and group icons are shown with --emoji. Emoji rendering differs between terminals: some show flags as two letters or shift the columns
- Attention lists services that see another country or failed to answer; blocks stay in their cards
- GeoIP shows a summary;
--geoip-breakdownlists every service - Colors are used only on a terminal and are disabled by
NO_COLOR
wget -O ipregion.sh https://ipregion.vrnt.xyz
chmod +x ipregion.shwget -qO- https://ipregion.vrnt.xyz | bashWithout wget:
curl -fsSL https://ipregion.vrnt.xyz | bashOptions go after bash -s --:
wget -qO- https://ipregion.vrnt.xyz | bash -s -- --group ai --ipv4If direct access to GitHub is unreliable or slow for you, use the mirror domain. It fetches the script through the server instead of redirecting you to GitHub:
# Download and run locally
wget -O ipregion.sh https://ipregion.mirror.vrnt.xyz
chmod +x ipregion.sh
# Run directly
wget -qO- https://ipregion.mirror.vrnt.xyz | bashNote
Unlike ipregion.vrnt.xyz, which simply redirects to GitHub, ipregion.mirror.vrnt.xyz proxies the request through the server (client -> server -> GitHub). Use it when the primary domain works poorly due to GitHub connectivity issues
This runs your IP geolocation check using IPv4 only, without requiring host network mode:
docker run --rm vernette/ipregion:latestYou can append additional script options as needed, for example:
docker run --rm vernette/ipregion:latest --group geoip
To access both IPv4 and IPv6 on the host real network interfaces, or to specify a custom network interface (e.g., eth1), use Docker host network mode:
docker run --rm --network=host vernette/ipregion:latestdocker run --rm --network=host vernette/ipregion:latest --interface eth1Note
When using --network=host, the container shares the host network stack, which reduces network isolation but enables full access to interfaces. Without --network=host, the container uses Docker bridge network, which may not expose IPv6 or allow interface selection
./ipregion.sh --help # Show all options
./ipregion.sh --group platforms,ai # Only these groups: platforms cdn availability ai geoip
./ipregion.sh --service steam,geoip/ripe # Only these services, names from --list-services
./ipregion.sh --group ai --service chatgpt # A whole group plus single services from other groups
./ipregion.sh --ipv4 # IPv4 only
./ipregion.sh --ipv6 # IPv6 only
./ipregion.sh --proxy 127.0.0.1:1080 # Use a SOCKS5 proxy, it picks IPv4 or IPv6 itself
./ipregion.sh --interface eth1 # Use a network interface
./ipregion.sh --timeout 10 # Request timeout in seconds
./ipregion.sh --emoji # Country flags and group icons
./ipregion.sh --geoip-breakdown # Every GeoIP service instead of the summary
./ipregion.sh --no-attention # Hide the Attention card
./ipregion.sh --youtube-lang en # YouTube interface language for YouTube No Ads (default: ru)
./ipregion.sh --json # JSON output
./ipregion.sh --verbose # Log every request to stderr
./ipregion.sh --debug # Save a masked trace and offer to upload it
./ipregion.sh --yes # Install dependencies and upload the debug log without askingAll options can be combined. A service that exists in several groups needs the group prefix: platforms/netflix or cdn/netflix.
Every check is one or two plain HTTP requests from the host itself (or through --proxy / --interface), the same requests a browser or an app would make. No accounts or API keys are needed. Each check runs separately over IPv4 and IPv6, because a host often looks like a different country on each protocol.
The verdict at the top is the country most Platforms and GeoIP services agree on. Attention lists every service that sees another country, is blocked or failed; the counter shows how many checks look normal.
| Symbol | Meaning |
|---|---|
β |
Works (in Availability: good for you) |
β |
Blocked for the country of this IP |
β |
Blocked for this IP itself (datacenter or VPN ranges, captcha) |
? |
No answer or an unexpected one - the reason is in Attention |
- |
Not checked: the host or the service has no IPv6 |
| Row | β means |
How it is checked |
|---|---|---|
| YouTube Premium | Premium can be bought | The Premium purchase page of the YouTube API has a buy button |
| YouTube No Ads RU | No video ads in videos | See below |
| Google Search | No captcha | A search is not redirected to the /sorry/ captcha page |
| Spotify Signup | Sign-up is open | Spotify's sign-up validation reports the country as launched |
| Disney+ | Disney+ serves the country | Disney's device registration reports a supported location |
| Reddit Guest | Reddit opens without login | The front page is not answered with 403 |
| Gemini Web / Gemini API | Gemini is available | The Google country of the IP is in Google's official list of Gemini regions |
| OpenAI / Anthropic / Grok API | The API serves the region | A request without a key gets "unauthorized" (β) instead of the provider's "unsupported country" error (β); another 403 is β |
| Chinese AI APIs (Qwen, Kimi, GLM, ...) | The API is reachable | They do not block regions, so only reachability is checked |
Whether YouTube plays video ads (before and inside videos) depends on the IP and on the language of the YouTube interface. The same server can show video ads to one viewer and none to another: for example, on a Swedish VPS we tested a viewer with the Russian interface gets no video ads, while the English interface gets them. On a German VPS both get them. The check is only about ads in videos: YouTube shows banner ads in its interface (home page, search, next to the player) anyway, including on the Swedish VPS that plays no ads in videos.
The check opens a monetized video page twice with the chosen interface language (--youtube-lang, ru by default, shown in the row name). The first visit only receives the visitor cookies - YouTube does not assign ads to a visitor without them - and the second one looks for a video ad slot in the page. β means no video ad slot, β means video ads (reason video ads in Attention). Run with your own language to see what you will get:
./ipregion.sh --service youtube_no_ads --youtube-lang en--json prints a report described by the schema schema/ipregion-v2.schema.json:
{
"$schema": "https://raw.githubusercontent.com/vernette/ipregion/master/schema/ipregion-v2.schema.json",
"version": 2,
"ipv4": {
"ip": "203.0.113.10",
"asn": 64496,
"org": "Example Hosting",
"registered": "NL",
"maxmind_failure": null
},
"ipv6": null,
"verdict": {
"country": "SE",
"tied": []
},
"attention": [
{
"services": ["JetBrains"],
"ip_version": "4",
"country": "SI",
"access": null,
"reason": "different country"
}
],
"results": {
"platforms": [
{
"id": "google",
"service": "Google",
"ipv4": {
"country": "SE",
"access": null,
"reason": null
},
"ipv6": null,
"proxy": null
}
],
"cdn": [
{
"id": "cloudflare",
"service": "Cloudflare",
"ipv4": {
"country": "SE",
"access": null,
"reason": null,
"iata": "ARN",
"node": null
},
"ipv6": null,
"proxy": null
}
],
"availability": [
{
"id": "youtube_premium",
"service": "YouTube Premium",
"ipv4": {
"country": null,
"access": "yes",
"reason": null
},
"ipv6": null,
"proxy": null
}
],
"ai": [],
"geoip": []
}
}ipv4/ipv6-nullwhen the protocol is not available or not selectedverdict.country-nullon a tie, then the tied countries are inverdict.tiedaccess-yes,no(region blocked) oripblockin Availability and AI, alwaysnullin the other groups. Foryoutube_no_adsnomeans video ads (reason: "video ads"); itsservicecarries the language, e.g.YouTube No Ads RUproxy- set only through a proxy that exits over both IPv4 and IPv6. Such a proxy picks the protocol of each connection itself, so Platforms, Availability, AI and CDN are checked once: the result is underproxy,ipv4/ipv6arenull. GeoIP stays per protocol, because its services are asked about each exit IP explicitly; Cloudflare reports the address it saw, so the other protocol getsreason: "proxy picked IPv4"or"proxy picked IPv6". Through a proxy with one protocol everything stays underipv4oripv6ip_versionin Attention -4,6,bothorproxy
The script outputs country codes in ISO 3166-1 alpha-2 format (e.g., RU, US, DE).
You can look up the meaning of any country code at the official ISO website: https://www.iso.org/obp/ui/#search/code/
Just enter the code in the search box to get the full country name.
Contributions are welcome! Feel free to submit pull requests to add new services or improve the script's functionality.
