ScreenshotNeo

BlogHow-to

How to Find Your IP Address Using Python (2026 Guide)

Learn how to resolve hostnames, inspect local addresses, and understand public IPs in Python with runnable IPv4 and IPv6 examples.

By the ScreenshotNeo team30 September 20268 min read

How to Find Your IP Address Using Python (2026 Guide)

There is no single Python call that means “my IP address.” You may need to resolve a remote hostname, find an address assigned to the machine running your code, or learn which public-facing address an outside service sees. These are different operations and can return different values.

For a hostname, use socket.getaddrinfo(); it supports IPv4 and IPv6 results. For the local machine, Python’s standard library can identify the hostname and resolve it, but that is not a guaranteed inventory of every network interface. For a public address, an external service must observe your request; this is separate from local interface discovery.

Choose the right meaning of “IP address”

Goal Python approach What it returns Main limitation
Resolve a website or host socket.getaddrinfo() One or more IPv4/IPv6 socket addresses Depends on DNS, OS resolver settings, and available network support
Print this computer’s name socket.gethostname() A hostname string It is not an IP address and may not be fully qualified
Resolve the local hostname socket.getaddrinfo(socket.gethostname(), ...) Addresses associated with that name May omit interfaces, VPN addresses, container addresses, or preferred routes
Inspect every local interface Operating-system APIs or a platform-specific package An interface inventory No single cross-platform standard-library recipe is guaranteed
Find the public-facing address Make a request to an external “what is my IP” service The address observed outside your network Requires an external dependency and may reflect NAT, a proxy, or VPN

The Python documentation defines gethostname() as returning “the hostname of the machine where the Python interpreter is currently executing.” It also notes that it does not always return a fully qualified domain name; use socket.getfqdn() when that distinction matters. See the official socket documentation.

Resolve a hostname with IPv4 and IPv6

Use this when the question is “Which addresses does example.com resolve to?” getaddrinfo() returns records suitable for creating sockets. Restricting the type to stream sockets avoids unrelated datagram records in the output.

Hostname resolution can produce multiple IPv4 and IPv6 records.
Hostname resolution can produce multiple IPv4 and IPv6 records.
import socket

host = "example.com"

try:
    results = socket.getaddrinfo(host, None, type=socket.SOCK_STREAM)
except socket.gaierror as exc:
    raise SystemExit(f"Could not resolve {host}: {exc}")

seen = set()
for family, socktype, proto, canonname, sockaddr in results:
    address = sockaddr[0]
    if (family, address) in seen:
        continue
    seen.add((family, address))
    print(f"{family.name}: {address}")

The list can contain IPv4 (AF_INET) and IPv6 (AF_INET6) addresses, but there is no promise that both families are available. Results depend on the operating system, configured resolvers, DNS records, and network support. The Python reference recommends getaddrinfo() for dual-stack resolution; gethostbyname() is IPv4-only.

Resolve a service port as well

If you are going to connect, pass a service such as 443 and inspect the complete socket address. IPv6 records include a four-item tuple containing the flow and scope fields.

import socket

for result in socket.getaddrinfo(
    "example.com", 443, type=socket.SOCK_STREAM
):
    family, socktype, proto, canonname, sockaddr = result
    print(family.name, sockaddr)

Get the local hostname (and understand what it is not)

import socket

print(socket.gethostname())
print(socket.getfqdn())

The first line is a name, not an address. The second asks the resolver for a fully qualified name, which can still depend on local configuration. Avoid presenting either value as a definitive way to enumerate every local IP address.

Resolve addresses associated with the local hostname

This short program is useful for a quick diagnostic, but it is only a hostname lookup. It may return loopback, one preferred interface, or several records depending on the machine.

import socket

hostname = socket.gethostname()
print("hostname:", hostname)

try:
    records = socket.getaddrinfo(hostname, None, type=socket.SOCK_STREAM)
except socket.gaierror as exc:
    print("hostname could not be resolved:", exc)
else:
    seen = set()
    for family, _, _, _, sockaddr in records:
        address = sockaddr[0]
        if address not in seen:
            print(f"{family.name}: {address}")
            seen.add(address)

On a laptop with Wi-Fi, Ethernet, a VPN, and containers, this output may not match the address used for a particular connection. If your application needs a complete interface inventory, use the operating system’s network APIs or a dependency selected for your supported platforms, then document that platform requirement.

Use the IPv4-only shortcut when that is intentional

import socket

try:
    address = socket.gethostbyname("example.com")
except socket.gaierror as exc:
    raise SystemExit(f"IPv4 lookup failed: {exc}")

print(address)

gethostbyname() does not support IPv6 name resolution. The Python documentation explicitly recommends getaddrinfo() for IPv4/IPv6 dual-stack support. Keep this shortcut for code that explicitly requires an IPv4 result.

Local address versus public address

A local interface address belongs to an interface on your machine or private network. A public-facing address is what an observer beyond a router, NAT gateway, VPN, proxy, or hosting boundary sees. They are often different. For example, IANA lists 10.0.0.0/8 as private-use IPv4 space that is not globally reachable.

Python cannot infer the public address without contacting something outside your network. An external service can report the source address it observes, but the choice of service, its API, privacy policy, availability, and response format are application decisions. Do not hard-code an unverified endpoint into production. Treat the returned value as “observed public address,” not as a local interface listing.

Classify an address with ipaddress

import ipaddress

for text in ("192.168.1.20", "8.8.8.8", "2001:db8::1"):
    address = ipaddress.ip_address(text)
    print({
        "address": str(address),
        "version": address.version,
        "is_private": address.is_private,
        "is_global": address.is_global,
    })

is_private and is_global are registry-based classifications, not reachability tests. They are not perfect opposites: shared IPv4 space 100.64.0.0/10 has both properties set to False. Python 3.13 changed some special-range classifications, so pin your Python version or test the exact ranges your policy depends on. Consult the official ipaddress documentation and IANA’s IPv4 Special-Purpose Address Registry.

Local interface addresses and externally observed public addresses are different values.
Local interface addresses and externally observed public addresses are different values.

Build a reusable resolver

from __future__ import annotations

import socket
from dataclasses import dataclass

@dataclass(frozen=True)
class ResolvedAddress:
    family: str
    address: str


def resolve(host: str, port: int | None = None) -> list[ResolvedAddress]:
    results = socket.getaddrinfo(host, port, type=socket.SOCK_STREAM)
    output: list[ResolvedAddress] = []
    seen: set[tuple[str, str]] = set()

    for family, _, _, _, sockaddr in results:
        key = (family.name, sockaddr[0])
        if key not in seen:
            seen.add(key)
            output.append(ResolvedAddress(*key))
    return output

if __name__ == "__main__":
    import sys

    target = sys.argv[1] if len(sys.argv) > 1 else "example.com"
    try:
        for item in resolve(target, 443):
            print(item.family, item.address)
    except socket.gaierror as exc:
        raise SystemExit(f"DNS resolution failed for {target}: {exc}")

Run it with python resolve.py example.com. The function keeps both address families, removes duplicate records, and surfaces resolver failures as socket.gaierror.

Errors and troubleshooting

Symptom Likely cause Fix
socket.gaierror: [Errno -2] Name or service not known Typo, unavailable DNS, or broken resolver configuration Check the hostname, DNS settings, and whether other programs can resolve it.
Only 127.0.0.1 appears The local hostname maps to loopback Do not treat hostname resolution as interface enumeration; inspect platform network APIs.
No IPv6 result No AAAA record, disabled IPv6, or resolver policy Request AF_INET6 explicitly for diagnostics and verify the host and network support it.
The address changes between runs DNS rotation, DHCP, VPN changes, or multiple interfaces Cache only for a documented period and select addresses according to connection policy.
Public address differs from local address NAT, proxy, VPN, or cloud egress That is expected; label the values by where they were observed.
Connection works for one family but not another Broken route, firewall, or service binding Attempt connections with explicit family handling and apply a timeout.

Performance, reliability, and cost

  • Performance: DNS lookups can involve network latency. Reuse your application’s resolver behavior and avoid resolving the same stable hostname repeatedly in a tight loop.
  • Reliability: Resolver output is environment-dependent. Handle empty results, duplicate addresses, timeouts at the connection layer, and gaierror without assuming one canonical address.
  • IPv6: Keep address-family information instead of converting everything to an IPv4 string. An IPv6 socket address has a different tuple shape.
  • Privacy: A public-IP check sends a request to a third party. Review retention and logging policies before using one in an application.
  • Cost: Standard-library hostname resolution has no API fee, but it consumes DNS and network resources. External public-IP services may impose limits or terms.

Or skip the browser setup

If your real task is capturing a page that displays an IP address, ScreenshotNeo can return the rendered result with one request. It accepts a URL and returns PNG, JPEG, WebP, or PDF. Before capture it accepts consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the page verdict and billing state with X-Page-Verdict and X-Billed headers. Its MCP server provides take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients.

See the ScreenshotNeo API documentation for all 63 options, including full-page capture, element selectors, device presets, custom headers and cookies, JavaScript, waits, request blocking, caching, signed links, asynchronous jobs, bulk capture, and usage reporting.

curl -G "https://api.screenshotneo.com/v1/shot" \
  -d access_key=YOUR_API_KEY \
  --data-urlencode url=https://stripe.com \
  -o shot.webp
import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
    timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({
  access_key: 'YOUR_API_KEY',
  url: 'https://stripe.com'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const image = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', image));

There are 1,000 screenshots per month on the free plan with no card. Paid plans start at $5 for 3,000 shots; yearly billing gives two months free, and every feature is included on every plan. Create a free ScreenshotNeo account.

FAQ

Does socket.gethostname() return my IP?

No. It returns the machine’s hostname. Resolve that name only as a diagnostic, not as a complete interface inventory.

Which function should new code use?

Use getaddrinfo() when IPv4/IPv6 support matters. Use gethostbyname() only when an IPv4-only result is an explicit requirement.

Can Python discover my public IP without the internet?

No. A public address is defined by what an external observer sees, so an external observation is required.

Is is_global proof that an address is reachable?

No. It is a standards-based classification. Firewalls, routing, NAT, and service configuration still determine reachability.

Why do two computers on the same network show different public-IP results?

They may use different VPNs, proxies, gateways, or network paths. Compare the observation point and route before treating the values as contradictory.