Detect · Starlink & satellite
Satellite users move fast. That's not fraud.
Starlink and other satellite links jump between ground stations, so an
honest user can look like impossible travel. GeoQ reports
connection_type === "satellite" as a benign network
kind that caps the risk score at 20 — frame the movement as benign
velocity, not account takeover.
Fact + limit: satellite ASNs can carry mixed traffic. We set the value only
for ranges we can attribute, and use "unknown" rather than guess.
The false positive it fixes
Satellite routing sends traffic through gateways that can be far from the subscriber, and the egress can shift between requests. Distance-over-time ("impossible travel") and geo-mismatch rules read that as a hijacked session. The signal you need isn't "this looks far" — it's "this is a satellite link, so distance jumps are expected."
When connection_type reads satellite, the score is capped at 20 and benign_network_kind lands in reasons[]. You can relax the velocity check for that one case while keeping it strict everywhere else.
In your code
const res = await fetch("https://api.geoq.io/v1/check?ip=98.97.0.1", { headers: { "x-api-key": process.env.GEOQ_KEY }, }); const { signals, risk } = await res.json(); // Starlink user — apparent location jumps are normal, not takeover. if (signals.connection_type === "satellite") { relaxImpossibleTravelCheck(); // benign velocity, score already capped at 20 }
Honest about ASN ambiguity
A satellite operator's ASN can announce more than subscriber access — uplinks, corporate ranges, infrastructure. We classify an IP as satellite only for ranges we can attribute to satellite access; everything we can't attribute is connection_type === "unknown", never a fabricated satellite or datacenter value. That keeps the benign-velocity reducer from firing where it shouldn't.
What sets the value
| Field | Meaning |
|---|---|
connection_type | "satellite" for attributed satellite access; also datacenter / unknown. |
network.asn / as_org | The announcing network (e.g. SpaceX Starlink) for context. |
risk.reasons[] | Includes benign_network_kind when satellite caps the score. |
evidence.connection_type | authoritative for ranges we can attribute. |
FAQ
Starlink & satellite detection — FAQ
How do you detect Starlink and satellite IPs?
connection_type is set to "satellite". Satellite is a value of connection_type, not a separate boolean. Ranges are refreshed daily. Why do satellite users trip fraud rules?
connection_type === "satellite" lets you treat that movement as benign velocity rather than a takeover signal. Is satellite ASN detection always certain?
connection_type === "satellite" only when the IP matches a range we can attribute to satellite access, and we label it authoritative only for those ranges — we never guess satellite to fill a gap. When we can't attribute it, connection_type is "unknown", not a fabricated value. Does satellite raise or lower the risk score?
connection_type === "satellite", the risk score is capped at 20 and benign_network_kind is added to reasons[]. A Starlink user on the move comes back low, not high. See the risk-score methodology. What replaced the is_datacenter boolean?
connection_type field replaces the old is_datacenter boolean. It reports datacenter (with a datacenter_provider), satellite, or unknown — so one field carries the network kind instead of stacking booleans. See the migration notes. How often is the satellite data refreshed?
Related
Get a free key — 5,000 lookups/day, no card.
Every signal and the same risk score as every paid plan. Upgrade only when you outgrow it.