Docs
Writes latitude and longitude into a JPEG and returns the file. No accounts. Use the website, or send the same job from your code with the URLs below.
Limits
- No cap on how many images you process.
- Each file, or each image downloaded from a URL, must be 5MB or smaller.
- Tagging allows 10 POST requests per 60 seconds per IP, shared by both tagging URLs.
- Inspect allows 20 POST requests per 60 seconds per IP.
- Naming a location allows 30 POST requests per 60 seconds per IP.
- Over the limit, the response is HTTP 429 with an
errorstring. HTTP 429 means too many requests. Wait, then retry. - GET pages,
/docs/,/static/, and/media/are not limited. - Enforced by nginx across workers. Django does not throttle.
Storage
- If you keep the file, it lasts 30 days, then cleanup removes it.
- If you send
delete_after=true, the image is returned asimage_base64and then deleted. There is no URL. - Oldest-first deletion when the disk fills is not implemented.
Output
By default, JPEGs are tagged without re-encoding the pixels. PNG, WebP, HEIC, and GIF convert to JPEG first, and the file you get is a .jpg.
Send keep_format=true to keep PNG or WebP in that format. JPEG is unchanged either way. GIF and HEIC cannot keep their format; sending keep_format=true for those returns an error instead of converting. Omit keep_format, or send false, to convert those to JPEG.
JPEG GPS is still what most maps and apps read. PNG eXIf support in consumers is uneven.
Tag an image
These two URLs do the same job. Send a POST to either one.
https://geotagger.binaryplane.com/
https://geotagger.binaryplane.com/api/geotag/
Use a multipart request to upload a file. Multipart is a file upload form, the same kind a browser sends when you choose a file. Use JSON to send an image URL as text. JSON here means a text body with a Content-Type of application/json.
Fields
| Field | What it does |
|---|---|
image |
The file to tag. Send it in a multipart request. Required unless you send url. Do not send both. Maximum 5MB. |
url |
A public image URL. Send it as JSON text, or in a multipart form. Required unless you send image. Do not send both. The downloaded file must be 5MB or smaller. |
latitude |
Required. North-south coordinate from -90 to 90. |
longitude |
Required. East-west coordinate from -180 to 180. |
filename |
Optional. Stored as that name with an extension that matches the output: .jpg by default, or .png or .webp when keep_format keeps those formats. |
delete_after |
Optional. Omit it and the default is false: the file is kept and a URL is returned. The website checkbox defaults to on, so the UI usually sends true. When true, the image is returned as image_base64 and then deleted. |
keep_format |
Optional. Omit it and the default is false, so non-JPEG files convert to JPEG. true keeps PNG or WebP. true on GIF or HEIC returns an error. It does not silently convert. |
Example: upload a file
This curl -F command sends a multipart file upload with coordinates.
curl -F "image=@photo.jpg" -F "latitude=40.7128" -F "longitude=-74.006" https://geotagger.binaryplane.com/api/geotag/
Example: pass an image URL
POST this JSON to either tagging URL. Set the request header Content-Type to application/json.
{
"url": "https://example.com/photo.jpg",
"latitude": 40.7128,
"longitude": -74.006
}
Success (keep the file)
HTTP 200 means the request succeeded. geotagged_image is an absolute URL you can fetch. Extra keys can be ignored.
{
"geotagged_image": "https://geotagger.binaryplane.com/media/photo.jpg",
"filename": "photo.jpg",
"content_type": "image/jpeg",
"coordinates": { "latitude": 40.7128, "longitude": -74.006, "latitude_ref": "N", "longitude_ref": "W" },
"maps_url": "https://www.google.com/maps/search/?api=1&query=40.712800,-74.006000",
"previous_coordinates": null,
"converted_to_jpeg": false,
"source": "file",
"deleted_after_processing": false,
"geotag_count": 12
}
Success (delete after)
HTTP 200 means the request succeeded. geotagged_image is null. The image bytes are in image_base64. content_type is image/jpeg, or image/png or image/webp when keep_format kept those formats.
{
"geotagged_image": null,
"image_base64": "<base64 JPEG bytes>",
"content_type": "image/jpeg",
"filename": "photo.jpg",
"deleted_after_processing": true
}
Errors
Failed requests return JSON with an error string. Read that string. HTTP 400 means the request was rejected, which is what the website and every /api/ URL use for bad input. HTTP 200 on POST / can still contain an error body, so Zapier can read it. Rate limits are always HTTP 429.
Inspect
Read GPS that is already on an image. This does not tag the file and nothing is stored. Send a POST to this URL.
https://geotagger.binaryplane.com/api/inspect/
Fields
| Field | What it does |
|---|---|
image |
The file to read. Send it in a multipart request. Required unless you send url. Do not send both. Maximum 5MB. Do not send latitude or longitude. |
url |
A public image URL. Send it as JSON text, or in a multipart form. Required unless you send image. Do not send both. The downloaded file must be 5MB or smaller. |
Response
| Field | What it does |
|---|---|
filename |
The source filename. Nothing is stored. |
source |
file or url, matching how you sent the image. |
format |
Detected format, such as JPEG, PNG, WEBP, or HEIC. |
can_keep_format |
true for PNG and WebP. false for JPEG, GIF, and HEIC. |
coordinates |
Existing GPS when present, otherwise null. |
maps_url |
A Google Maps link for the coordinates found, otherwise null. Open it to check the location is right. |
datetime |
EXIF datetime when present, otherwise null. |
camera |
Make and model when present, otherwise null. |
has_gps |
true when coordinates were found. |
Example: upload a file
curl -F "image=@photo.jpg" https://geotagger.binaryplane.com/api/inspect/
Example: pass an image URL
POST this JSON with Content-Type: application/json.
{
"url": "https://example.com/photo.jpg"
}
Success
{
"filename": "photo.jpg",
"source": "file",
"format": "JPEG",
"can_keep_format": false,
"coordinates": { "latitude": 40.7128, "longitude": -74.006, "latitude_ref": "N", "longitude_ref": "W" },
"maps_url": "https://www.google.com/maps/search/?api=1&query=40.712800,-74.006000",
"datetime": "2024:08:14 12:00:00",
"camera": "Apple iPhone",
"has_gps": true
}
Bad input returns HTTP 400 with an error string. Over the inspect limit is HTTP 429.
Name a location
Turn coordinates into a place name a person can read, plus a Google Maps link. No image is involved and nothing is stored. Send a POST to this URL.
https://geotagger.binaryplane.com/api/location/
Fields
| Field | What it does |
|---|---|
latitude |
Required. North-south coordinate from -90 to 90. |
longitude |
Required. East-west coordinate from -180 to 180. |
Response
| Field | What it does |
|---|---|
place |
A short name such as Lahore, Punjab, Pakistan. It is null when the lookup finds nothing or the name service is unreachable. Treat a name as a convenience, not a guarantee. |
maps_url |
A Google Maps link for the coordinates. Always present, because building it needs no lookup. |
latitude, longitude |
The coordinates you sent, echoed back. |
Example
{
"latitude": 31.5204,
"longitude": 74.3587
}
Success
{
"latitude": 31.5204,
"longitude": 74.3587,
"place": "Lahore, Punjab, Pakistan",
"maps_url": "https://www.google.com/maps/search/?api=1&query=31.520400,74.358700"
}
Names come from OpenStreetMap Nominatim and are cached for 30 days. Bad input returns HTTP 400 with an error string. Over the limit is HTTP 429.