Metadata-Version: 2.5
Name: vpndetection
Version: 5.1.0
Summary: Official Python client library for the VPNDetection API. Detect VPNs, proxies, Tor, hosting and CDN IPs.
Project-URL: Homepage, https://vpndetection.io
Project-URL: Documentation, https://docs.vpndetection.io
Project-URL: Source, https://github.com/vpndetection-io/sdk-python
Project-URL: Issues, https://github.com/vpndetection-io/sdk-python/issues
Author-email: Mslm Dev <support@vpndetection.io>
License-Expression: MIT
License-File: LICENSE
Keywords: cdn,datacenter-proxy,fraud-prevention,hosting,ip-geolocation,ip-intelligence,mobile-proxy,proxy-detection,relay,residential-proxy,tor,vpn,vpn-detection
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Topic :: Internet
Classifier: Topic :: Security
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: attrs>=22.2.0
Requires-Dist: cachetools>=5.3
Requires-Dist: httpx<1,>=0.27
Provides-Extra: dev
Requires-Dist: mypy>=1.11; extra == 'dev'
Requires-Dist: openapi-python-client<0.30,>=0.29; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Description-Content-Type: text/markdown

# [<img src="https://s3.vpndetection.io/vpndetection-public/brand/mark.svg" alt="VPNDetection" width="24"/>](https://vpndetection.io/) VPNDetection Python Client Library

[![PyPI](https://img.shields.io/pypi/v/vpndetection.svg)](https://pypi.org/project/vpndetection/)
[![license](https://img.shields.io/pypi/l/vpndetection.svg)](LICENSE)

The official Python client library for the [VPNDetection](https://vpndetection.io) API.

The library helps you query VPNDetection's APIs for anonymity detection including VPNs, residential proxies, Tor nodes, hosting servers, CDNs, relays and more.

## Getting Started

```bash
pip install vpndetection
```

Requires Python 3.11 or newer. Type hints are included, and the package ships `py.typed`.

## Usage

**No API key needed to start.** The free tier answers `ip` and `is_vpn`, and allows 1000 requests per day per source address.

```python
from vpndetection import VPNDetection

client = VPNDetection()

result = client.lookup("45.83.91.1")
print(result.is_vpn)   # True
```

The client holds an HTTP connection pool, so use it as a context manager, or call `client.close()` when you are done with it:

```python
with VPNDetection() as client:
    print(client.lookup("45.83.91.1").is_vpn)
```

### With an API key

An API key raises your quota, and raises your features on a paid plan. Create one in the [console](https://app.vpndetection.io), then pass it in:

```python
import os

client = VPNDetection(os.environ["VPNDETECTION_API_KEY"])

result = client.lookup("45.83.91.1")
print(result.is_vpn)          # True
print(result.vpn.provider)    # 'mullvad'
print(result.is_hosting)      # True
print(result.hosting.provider)
```

### Async

Everything above works the same way under asyncio, with `AsyncVPNDetection`:

```python
import asyncio
from vpndetection import AsyncVPNDetection

async def main():
    async with AsyncVPNDetection() as client:
        result = await client.lookup("45.83.91.1")
        print(result.is_vpn)   # True

asyncio.run(main())
```

### Your own address

```python
result = client.my_ip()
print(result.ip)   # the address we saw this call come from
```

Same answer `lookup` would give for that address, and the same cost against your allowance. It is deliberately not cached: which address you are is the whole question, and a machine that moves between networks would otherwise be told where it used to be.

### Your plan and usage

```python
acct = client.my_entitlement()
print(acct.plan.key)          # max
print(acct.usage.requests)    # 580
print(acct.usage.window_end)  # when the allowance resets
```

Usage counts against the anniversary of your subscription, not the calendar month and not the billing period, and it is the same number a lookup is gated on. `hard_limit` is `None` on an uncapped plan, which is not the same as zero.

Both are on the async client too: `await client.my_ip()` and `await client.my_entitlement()`.

### Batch lookup

Look up many addresses at once. Bogons and cached answers are handled locally, and everything else goes to the batch endpoint in chunks of up to 1000 addresses, in parallel:

```python
results = client.lookup_batch(["45.83.91.1", "8.8.8.8", "1.1.1.1"])

for ip, result in results.items():
    if isinstance(result, Exception):
        print(f"{ip}: {result}")
        continue
    print(f"{ip}: {result.is_vpn}")
```

Results are keyed by address, in the order you first listed each one, so duplicates in your list collapse into a single entry and one address failing never loses the rest: it carries its error as its value, with the status the API would have given that address on its own.

How many chunks are in flight at once, and how many times a failed chunk is retried, are configurable per call:

```python
results = client.lookup_batch(many_ips, concurrency=4, retries=4)
```

### Caching

Answers are cached by default, so repeat lookups of the same address are free:

```python
client = VPNDetection()

result = client.lookup("45.83.91.1")
print(result.is_vpn)    # True, API request

result2 = client.lookup("45.83.91.1")
print(result2.is_vpn)   # True, no API request, result was cached
```

You can change the default cache variables (max size, TTL in seconds, etc) on initialization, or even disable it:

```python
client = VPNDetection(cache_max_size=50_000, cache_ttl=6 * 60 * 60)
client_no_cache = VPNDetection(cache=False)
```

### Private and reserved addresses

Private, loopback, link-local, documentation and multicast addresses (and their IPv6 equivalents, including the 6to4 and Teredo ranges) can never be VPN or proxy infrastructure. The library answers them locally, so they cost no request and no quota:

```python
result = client.lookup("192.168.1.1")
result.is_bogon   # True, this answer was computed rather than served
result.is_vpn     # False
```

The check is available on the client, which is handy when your inputs are addresses anyway:

```python
client.is_bogon("10.0.0.1")   # True
client.is_bogon("8.8.8.8")    # False
```

It is also importable on its own, if you want it without a client:

```python
from vpndetection import is_bogon

is_bogon("10.0.0.1")   # True
```

### Errors

Failures raise a `VPNDetectionError` carrying a `kind` and a `retryable` flag:

```python
from vpndetection import VPNDetectionError

try:
    client.lookup("1.1.1.1")
except VPNDetectionError as err:
    print(err.kind, err.retryable)
```

`kind` is one of `bad_request`, `unauthorized`, `forbidden`, `rate_limited`, `quota_exceeded`, `server_error` or `network`.

Note that `rate_limited` and `quota_exceeded` both arrive as HTTP 429 and are not the same thing. A rate limit is when the API faces extreme traffic bursts and so retrying later works; but a spent quota needs your allowance raised or the window to roll over. The library retries rate limits for you, but not if your quota is exceeded.

### Database downloads

If your key carries the `db.download` scope, the licensed databases are available through `client.database`. `list` answers database families, and the ids the other calls take come from each family's `versions`. There are three ways to get a database: the time-limited link, the bytes, or straight to a file, which streams so nothing bigger than a chunk is ever held in memory:

```python
databases = client.database.list()

url = client.database.download_url("vpn_ip_extended_v1", "mmdb")
raw = client.database.download_bytes("cdn_ip_v1", "csvgz")
written = client.database.download("vpn_ip_extended_v1", "mmdb", "./vpn_ip_extended_v1.mmdb")
```

`download_bytes` holds the whole file in memory, and the catalog runs from `cdn_ip_v1` at 10 KB to `resproxy_ip_90d_v1` at 1.79 GB, so use `download` for anything you have not measured.

### Fields your plan does not include

Only `ip` and `is_vpn` come back on every plan. The rest are `None` when your plan does not include them, which means "not in your plan" rather than "checked, and no".

```python
result.flagged("is_hosting")   # False rather than None on a plan without it
result.is_hosting is None      # True when hosting is not in your plan
```

## Other Libraries

There are official VPNDetection client libraries available for many languages including PHP, Python, Go, Java, Ruby, and many popular frameworks such as Django, Rails, and Laravel. See our GitHub at https://github.com/vpndetection-io for more.

## About VPNDetection

VPN Detection API: Accurate anonymity detection identifying VPNs, residential proxies, hosting servers, Tor nodes, CDNs, relays and more.

[<img src="https://s3.vpndetection.io/vpndetection-public/brand/mark.svg" alt="VPNDetection" width="96"/>](https://vpndetection.io/)

## License

This project is licensed under the [MIT License](LICENSE).
