GeoSnoop API
Send a photo, get back where it was likely taken, as data: the same answer a paid search shows on the website, minus the photo breakdown. Version 1.
Quick start
curl -H "Authorization: Bearer $GEOSNOOP_KEY" -F photos=@street.jpg https://geosnoop.com/api/v1/submissions
# {"api_version": "1", "id": "4f0c...", "status": "queued", "cost": 1}
curl -H "Authorization: Bearer $GEOSNOOP_KEY" https://geosnoop.com/api/v1/submissions/4f0c...
# repeat until "status" is "done" (or "failed")Request
POST /api/v1/submissions with Authorization: Bearer <key> and a multipart form: one or more photos files (JPEG, PNG, WebP or HEIC; up to 20 pictures of one place). One picture is a single-photo search; more are a set. Answer 202: {"api_version": "1", "id", "status": "queued", "cost"}.
Then GET /api/v1/submissions/{id} (same header). While waiting: {"api_version", "id", "status": "queued" | "working", "position", "eta_s"}. Failed: {"api_version", "id", "status": "failed", "error"}.
Response
The same chances the website shows (capped at 0.99), in the same order. The photo breakdown (which parts of the picture point where) and the heat map are on the website only: the API never computes or returns them.
headline: the answer the website puts on top:levelcity(the top city's chance is at least 0.5), elsecountry(the top country's chance is at least 0.5), elseregion(a world region's countries together at least 0.5), elseunknown;name,country,cc,chance(for a city: the chance the picture was taken within 25 km of it)cities: up to 5{city, country, cc, lat, lon, chance}(the website's City Matches: the top one, then those of at least 1%);countries: up to 5{country, cc, chance}exact_location:{lat, lon, chance, radius_m}, the chance the picture was taken withinradius_mof that spot; only when the website shows its exact spot (under a city headline, when GeoSnoop is sure enough), elsenullregion:{outline, r68_km}, the area the picture was taken in with a 68% chance, as a GeoJSON MultiPolygon ([lon, lat], the sea cut out);nullwhen nothing points to a placeno_location: true when nothing in the picture points to a placephotos: for a set or a video, every picture's own result with the same fields; empty for one photocredits:{charged, remaining}
Example (one photo):
{"api_version": "1", "id": "4f0c...", "status": "done", "kind": "photo",
"headline": {"level": "city", "name": "Torrance", "country": "United States", "cc": "us", "chance": 0.62},
"cities": [{"city": "Torrance", "country": "United States", "cc": "us", "lat": 33.8358, "lon": -118.3406, "chance": 0.62},
{"city": "Carson", "country": "United States", "cc": "us", "lat": 33.8317, "lon": -118.282, "chance": 0.09}],
"countries": [{"country": "United States", "cc": "us", "chance": 0.99}],
"exact_location": null,
"region": {"outline": {"type": "MultiPolygon", "coordinates": [[[[-118.41, 33.70], [-118.25, 33.71], ..., [-118.41, 33.70]]]]}, "r68_km": 14.2},
"no_location": false, "photos": [], "credits": {"charged": 1, "remaining": 49}}Errors
401 bad_api_key, 402 no_credits, 403 consent_required (the Terms changed: agree again on your account page), 400 unreadable_photo, 413 too_large / too_many_photos, 415 video_not_accepted (pictures only), 429 busy.
Credits and limits
A photo costs 1 credit, a set 3, charged only when the result names at least a country. Fields may be added within version 1; none are removed or renamed without a new version.
Getting a key
Create one on your account page (an account with credits; making a key records your agreement to the Terms for every upload sent with it). Plans · high volume or reselling: request a quote.