Cannot fetch photo pages programmatically, even with "Authorization" header

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:

  1. Use the API to retrieve a list of my observations.
  2. Parse the results to get a list the photo IDs from those observations.
  3. 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!

I have no solution. But look at https://forum.inaturalist.org/t/cant-access-photo-pages-from-bplant-server-403-forbidden/77168 . Looks similar for me.

1 Like

It’s similar but not identical, because he’s getting a 403 Forbidden error. I’m not getting 403, I’m getting a JavaScript/cookies challenge.

His problem might have started at the same time though.

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.
2 Likes

it is possible to get the original filename using an authorized request to GET /observations. see https://forum.inaturalist.org/t/api-return-original-filename-when-fetching-photos-or-sounds/69322/6.

also note that generally you should exchange your oauth token for a jwt and use the jwt when you make such requests.

1 Like

The original filename, yes, but not any of the other metadata that’s available to authorized users on the /photos/12345 page.

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.

1 Like

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.)

without knowing your exact process, i would think that that matching could be done on file name, too, or worst case, observation day + file name.

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.)

you could save the original file name in a metadata tag in your final file.