Geo-restricted content

A licence that names a country means where the viewer actually is

Tor exits, commercial VPNs, hosting and residential proxies are each reported separately, so you decide which of them breaks your licence rather than us.

The problem

Licensing is written in terms of territories, and a territory stops matching an address the moment a viewer can rent an exit node anywhere in the world for a few euros a month.

Not every relocation matters equally, and that is the part most APIs get wrong. A rights holder auditing you cares about commercial VPNs. A security team cares about Tor. Collapsing the two into a single anonymous flag forces the strictest reading of your contract onto everybody.

What to read in the response

Field Why it matters here
vpn, tor, proxy, hosting Four separate booleans rather than one. This is the case they exist for: block commercial VPNs and allow Tor, or the reverse, without having to ask us which we think matters to your contract.
location.country_code ISO 3166-1 alpha-2, which is the form to compare against a card's issuing country. The full country name is a separate field, so you branch on the code and show the name to whoever reviews the decision.
network.cloud Names the cloud provider announcing the range, where the range belongs to one. Useful when your policy is about datacentres specifically rather than about anonymity.

Write the policy per flag and keep the score as a tiebreaker rather than as the rule. An auditor will ask what you enforce, and "commercial VPNs and datacentre ranges" is a far easier answer to defend than "anything above 0.7".

Wiring it up

# The policy, written where the contract can be read next to it rather than
# buried in a threshold. Each line is a clause somebody agreed to.
BLOCKED = {"vpn", "hosting"}   # commercial VPNs and datacentre ranges
ALLOWED = {"tor"}              # privacy tools are not a licensing problem

def may_stream(check, licensed_countries):
    if check["location"]["country_code"] not in licensed_countries:
        return False

    return not any(check[flag] for flag in BLOCKED)

Where to draw the line

Decide the flags with whoever signed the contract, not in code review. Then log the response alongside every refusal, because the question you will eventually be asked is why one specific viewer was blocked on one specific evening.

What happens on an address nobody has seen

An address the database holds nothing on answers 404, not a low score. That is deliberate: there is no country, no operator and no ASN to return either, so a result would be a row of nulls dressed up as an answer. Treat it as no opinion rather than as clean, and decide for your own case whether to let the request through. The address goes into the scan queue and usually resolves within minutes, and the call is free on a paid plan.

Every field, every error code and the exact billing rules are in the documentation. Endpoints

Other things people use it for

Try it against your own traffic.

The free tier is a plan, not a trial. Sign up, copy your key, and make the first call before you decide anything.

Get started