Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

pyinaturalist

Build Codecov Documentation

PyPI Conda PyPI - Python Versions

Run with Binder


Introduction

iNaturalist is a community science platform that helps people get involved in the natural world by observing and identifying the living things around them. Collectively, the community produces a rich source of global biodiversity data that can be valuable to anyone from hobbyists to scientists.

pyinaturalist is a client for the iNaturalist API that makes these data easily accessible in the python programming language.

Features

  • ➡️ Easier requests: Simplified request formats, easy pagination, and complete request parameter type annotations for better IDE integration
  • ⬅️ Convenient responses: Type conversions to the things you would expect in python, and typed model objects (Observation, Taxon, etc.) with full IDE autocompletion
  • 🔒 Security: Keyring integration for secure credential storage
  • 📗 Docs: Example requests, responses, scripts, and Jupyter notebooks to help get you started
  • 🧪 Testing: A dry-run testing mode to preview your requests before potentially modifying data
  • 💚 Responsible use: Follows the API Recommended Practices without extra configuration; caching and rate-limiting features reduce bandwidth usage, errors, and unexpected throttling

Supported Endpoints

Many of the most relevant API endpoints are supported, including:

  • 📝 Annotations and observation fields
  • 🆔 Identifications
  • 💬 Messages
  • 👀 Observations (multiple formats)
  • 📷 Observation photos + sounds
  • 📊 Observation histograms, observers, identifiers, life lists, and species counts
  • 📍 Places
  • 👥 Projects
  • 🐦 Species
  • 👤 Users

Quickstart

Here are usage examples for some of the most commonly used features.

First, install with pip:

pip install pyinaturalist

Then, import and create a client object. This will be our main interface to the API:

from pyinaturalist import *
client = iNatClient()

Note: If you are looking for the lower-level API functions (without the client class), see this page

Search observations

Let's start by searching for all your own observations. There are numerous fields you can search on, but we'll just use user_id for now:

>>> results = client.observations.search(user_id='my_username')

The full response consists of Observation objects with numerous attributes, but we can use pyinaturalist.pprint() to print out a condensed summary:

>>> pprint(results)
ID         Taxon                               Observed on   User     Location
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
117585709  Genus: Hyoscyamus (henbanes)        May 18, 2022  niconoe  Calvi, France
117464920  Genus: Omophlus                     May 17, 2022  niconoe  Galéria, France
117464393  Genus: Briza (Rattlesnake Grasses)  May 17, 2022  niconoe  Galéria, France
...

You can also get observation counts by species. On iNaturalist.org, this information can be found on the 'Species' tab of search results. For example, to get species counts of all your own research-grade observations:

>>> counts = client.observations.species_counts(user_id='my_username', quality_grade='research')
>>> pprint(counts)
 ID     Rank      Scientific name               Common name             Count
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
47934   species   🐛 Libellula luctuosa         Widow Skimmer           7
48627   species   🌻 Echinacea purpurea         Purple Coneflower       6
504060  species   🍄 Pleurotus citrinopileatus  Golden Oyster Mushroom  6
...

The data will be in the form of TaxonCount objects:

>>> counts[0]
TaxonCount(
    id=48662,
    name='Danaus plexippus',
    preferred_common_name='Monarch',
    rank='species',
    count=13,
    observations_count=458712,
    ...
)

Another useful format is the observation histogram, which shows the number of observations over a given time interval. The default is month_of_year:

>>> histogram = client.observations.histogram(user_id='my_username')
>>> pprint(histogram)
Month   Count
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Jan     8       ████
Feb     1       █
Mar     20      ██████████

The raw data will be a dict, with either int or datetime keys, depending on the interval:

>>> print(histogram.raw)
{
    1: 8,  # January
    2: 1,  # February
    3: 19, # March
    ...,   # etc.
}

Create and update observations: authentication

To create or modify observations, you will first need to log in. This requires creating an iNaturalist app, which will be used to get an access token.

creds = {
    'username': 'my_username',
    'password': 'my_password',
    'app_id': 'my_app_id',
    'app_secret': 'my_app_secret',
}
client = iNatClient(creds=creds)

See Authentication for more options including environment variables, keyrings, and password managers. A keyring is recommended, which does not require passing credentials directly:

client = iNatClient()
# Creds will be requested from the keyring when an authenticated request is made
client.observations.create(...)

Create and update observations

Now we can create a new observation:

from datetime import datetime

new_obs = client.observations.create(
    taxon_id=54327,  # Vespa Crabro
    observed_on_string=datetime.now(),
    time_zone='Brussels',
    description='This is a free text comment for the observation',
    tag_list='wasp, Belgium',
    latitude=50.647143,
    longitude=4.360216,
    positional_accuracy=50,  # GPS accuracy in meters
    photos=['~/observations/wasp1.jpg', '~/observations/wasp2.jpg'],
    sounds=['~/observations/recording.wav'],
)

We can then update the observation information, photos, or sounds:

client.observations.update(
    new_obs.id,  # Use the observation ID from the result above
    access_token=token,
    description='updated description !',
    photos='~/observations/wasp_nest.jpg',
    sounds='~/observations/wasp_nest.mp3',
)

Search species

There are many more resource types available besides observations. Taxonomy is another useful one.

Let's say you partially remember either a genus or family name that started with 'vespi'-something. The taxon search can be used to search by name, rank, and several other criteria:

>>> results = client.taxa.search(q='vespi', rank=['genus', 'family'])

As with observations, there is a lot of information available in the response (Taxon objects), but we'll print just a few basic details:

>>> pprint(results)
ID        Rank     Scientific name    Common name
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
52747     family   🐝 Vespidae        Hornets, Paper Wasps, Potter Wasps, and Allies
84737     genus    🦋 Vespina
646195    genus    🪰 Vespiodes
...

Next Steps

For more information, see:

  • User Guide: introduction and general features that apply to most endpoints
  • Endpoint Summary: a complete list of endpoints wrapped by pyinaturalist
  • Examples: data visualizations and other examples of things to do with iNaturalist data
  • Reference: Detailed API documentation
  • Contributing Guide: development details for anyone interested in contributing to pyinaturalist
  • History: details on past and current releases
  • Issues: planned & proposed features

Feedback

If you have any problems, suggestions, or questions about pyinaturalist, you are welcome to create an issue or discussion. Also, PRs are welcome!

Note: pyinaturalist is developed by members of the iNaturalist community, and is not endorsed by iNaturalist.org or the California Academy of Sciences. If you have non-python-specific questions about the iNaturalist API or iNaturalist in general, the iNaturalist Community Forum is the best place to start.

Related Projects

Other python projects related to iNaturalist:

  • naturtag: A desktop application for tagging image files with iNaturalist taxonomy & observation metadata
  • pyinaturalist-convert: Tools to convert observation data to and from a variety of useful formats
  • pyinaturalist-notebook: Jupyter notebook Docker image for pyinaturalist
  • dronefly: A Discord bot with iNaturalist integration, used by the iNaturalist Discord server.

Metadata

Release files for pyinaturalist 1.0.0.dev2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pyinaturalist 1.0.0.dev2
File Size Uploaded
pyinaturalist-1.0.0.dev2.tar.gz 113.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pyinaturalist 1.0.0.dev2
File Interpreter ABI Platform
pyinaturalist-1.0.0.dev2-py3-none-any.whl Python 3 none any Details

Total release size: 268.1 kB

Release files / pyinaturalist-1.0.0.dev2.tar.gz

Download URL pyinaturalist-1.0.0.dev2.tar.gz
Size 113.2 kB
Tags Source
SHA-256 checksum
How to use checksums
b66573c0213bd80b45400a01871bee1a07a7e1f6fe121a892177c93a097dd2d4
BLAKE2b-256 checksum
How to use checksums
5b105795acde16ec3348ba8a8148f2ab2a167e2d76b533be0d25a8129b7aabd8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 6, 2026.

Transparency log

Release files / pyinaturalist-1.0.0.dev2-py3-none-any.whl

Download URL pyinaturalist-1.0.0.dev2-py3-none-any.whl
Size 154.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6f1efdb2b19bbaffd598d0d35788f7d8cdd0133bce6950c46fcf900ba5a2319e
BLAKE2b-256 checksum
How to use checksums
8cd11807ac95198292e1f3e28fe539d8d4248f1e2a63da2c29b044c4209b4cc6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 6, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.0.0.dev2 This release

2 release files

0.21.1

2 release files

0.21.0

2 release files

0.20.2

2 release files

0.20.1

2 release files

0.19.0

2 release files

0.18.0

2 release files

0.17.4

2 release files

0.17.3

2 release files

0.17.2

2 release files

0.17.1

2 release files

0.17.0

2 release files

0.16.0

2 release files

0.14.1

2 release files

0.14.0

2 release files

0.13.0

2 release files

0.10.0

2 release files

0.9.1

2 release files

0.9.0

2 release files

0.8.0

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page