I keep a database of all of my digital photos, and one of the fields in that database is the iNaturalist photo ID. The only way I can match up my files to iNat’s IDs is via the timestamp of the original file that I uploaded. Unfortunately, the API does not provide a way to retrieve details about photos (please correct me if I’m wrong). So here’s what I have to do if I want to fetch the timestamps of my own photos on iNat:
Use the API to retrieve a list of my observations.
Parse the results to get a list the photo IDs from those observations.
Fetch each photo’s Web page — e.g., /photos/12345678 — and parse the HTML to extract the timestamp. When I do this, I transmit an “Authorization: Bearer” header with an access token that I got from https://www.inaturalist.org/oauth/token.
Obviously step 3 is a little weird, but with the lack of a “get photos” API, it seems to be my only option.
However, starting around 3/26/26, step 3 stopped working. Instead of a normal photo page, my program gets a pile of JavaScript (with “Enable JavaScript and cookies to continue” in the <noscript>tag) that I assume is there to thwart bots. I understand very well the need to combat the renegade crawlers out there, but I’m sending a valid Authorization header!
So I’m begging iNaturalist to please do one of two things: either tweak the bot filter to allow programmatic HTTP requests that have a valid access token, or finally give us a way to fetch photo information via the API!
The “Just a moment…” browser challenge (CloudFlare protection) is a 403 error page; depending on the piece of software making the request, you may get to view a page (full of Javascript indeed) or just the corresponding “403” code.
Example:
$wget -O- "https://www.inaturalist.org/photos/598865021" --content-on-error
--2026-03-31 09:59:15-- https://www.inaturalist.org/photos/598865021
Resolving www.inaturalist.org (www.inaturalist.org)... 104.20.24.172, 172.66.151.8, 2606:4700:10::ac42:9708, ...
Connecting to www.inaturalist.org (www.inaturalist.org)|104.20.24.172|:443... connected.
HTTP request sent, awaiting response... 403 Forbidden
Saving to: ‘STDOUT’
- [<=> ] 0 --.-KB/s
<!DOCTYPE html><html lang="en-US"><head><title>Just a moment...</title><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
[blahblahblah full of Javascript and whatnot]
</script></body- [ <=> ] 4.70K --.-KB/s in 0s
2026-03-31 09:59:15 ERROR 403: Forbidden.
well, there is an existing request for a GET /photos endpoint: https://forum.inaturalist.org/t/photo-detail-endpoint-for-api/40481. you can add your support for it there if you haven’t already. or since you have some coding aptitude, you could do what the other person in the thread i referenced earlier did and just add the functionality you’re looking for. you can see exactly what changes they made and start from there.
Since you have access to your digital photos, can’t you get the photo metadata yourself, and then merge the metadata with the iNaturalist observation data?
I have enough “coding aptitude” to fetch information from the API, but I don’t know the first thing about programming the API itself. I added a comment to that thread.
I have the metadata, yes, but I need to know which observation is associated with which photo. So I need iNat’s record of the timestamp. It’s about 100 times easier to do it in a batch after the fact than one-by-one as I upload them. (Besides, the photos are often sent to iNat before they even have a local database entry associated with them.)
The files come out of my camera as IMG_1234.JPG. Occasionally I save phone photos, and they use their own naming scheme. Once I’ve culled and sorted, all of them get renamed as YYYYMMDD-HHMMSS.jpg, so each one is unique at that point. If I were to make sure I only uploaded to iNat after renaming the file, then yes, that might work, in theory.
But there still ought to be an API for this stuff!
(Meanwhile, I was able to get some behind-the-scenes assistance from an iNat staff member on how to make my authorized queries work again.)