# iNaturalist Scraper — Observations, Taxa & Species (`logiover/inaturalist-scraper`) Actor

Scrape iNaturalist by taxon name, place, or keyword. Extract species, location, photo, observer, quality grade, and taxonomy for biodiversity research, conservation, and wildlife monitoring. No API key, no login.

- **URL**: https://apify.com/logiover/inaturalist-scraper.md
- **Developed by:** [Logiover](https://apify.com/logiover) (community)
- **Categories:** Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## iNaturalist Scraper — Observations, Taxa & Species Data

Scrape millions of biodiversity observations from iNaturalist by species, location, or keyword — no API key, no login, fully automated.

### What does iNaturalist Scraper do?

iNaturalist Scraper connects to the official iNaturalist open API (`https://api.inaturalist.org/v1/`) to extract wildlife observation data at scale. The actor operates in three modes: **observations** (paginate through thousands of citizen science records filtered by taxon name, place ID, or free-text query), **taxa** (search the iNaturalist species catalog), and **observationDetail** (fetch a single observation by ID with full metadata).

The engine uses keyless HTTP GET requests against the `/observations`, `/taxa`, and `/observations/{id}` endpoints, paginating with `page` and `per_page=200` parameters until your `maxResults` cap is reached. Each observation includes the species identification, GPS coordinates, coordinate accuracy, observer username, identification-agreement count, photo URL, quality grade, and CC license — structured and ready to export to CSV, JSON, or Excel. A single run can pull thousands of research-grade wildlife records across any taxonomic group: birds, mammals, insects, plants, fungi, and more.

### Who is it for?

- **Ecologists and conservation researchers** needing bulk georeferenced species occurrence data for distribution modeling or habitat analysis.
- **Wildlife NGOs and park managers** tracking species presence in specific regions without manual portal downloads.
- **Academic institutions** building datasets for biodiversity informatics, machine learning, or phylogenetics research.
- **Data journalists and science communicators** exploring species invasion fronts, climate-linked range shifts, or endangered species trends.
- **Developers and data engineers** integrating citizen science biodiversity data into dashboards, apps, or GIS pipelines.

### Use cases

- Download all research-grade lion (*Panthera leo*) observations in Africa to map current range and density hotspots.
- Extract bird observations by place ID for a national park to power a visitor species checklist app.
- Search the taxa endpoint for all Panthera species to get taxonomy, photos, and observation counts.
- Pull recent insect observations tagged with a specific keyword to monitor pollinator activity across a region.
- Fetch individual observation details including photos and identifications for a curated species gallery or species alert system.

### Why use iNaturalist Scraper?

- **Completely keyless** — the iNaturalist API is public and open; no registration or API key required.
- **18 structured fields** per observation: observation/taxon IDs, species guess, common/scientific names, rank, iconic taxon, date, place, GPS coordinates + accuracy, observer, quality grade, identification agreements, photo, URL, and license.
- **Bulk pagination** — fetches up to 10,000 records per run with automatic page cycling.
- **Three modes** — observations search, taxa/species catalog lookup, and single observation detail.
- **Flexible filters** — filter by taxon name, place ID, quality grade (`research`, `needs_id`, `casual`), or free-text query.
- **Export to CSV, JSON, Excel, or XML** via Apify platform; integrate with Google Sheets, Zapier, or Make in one click.

### What data can you extract?

The actor extracts the following fields per observation or taxon record:

| Field | Type | Description |
|---|---|---|
| `id` | integer | Unique iNaturalist observation or taxon ID |
| `speciesGuess` | string | Common name or species guess by the observer |
| `commonName` | string | Preferred common name from iNaturalist taxonomy |
| `taxonName` | string | Scientific name of the identified taxon |
| `taxonId` | integer | Numeric iNaturalist taxon ID |
| `taxonRank` | string | Taxonomic rank (species, genus, family, etc.) |
| `iconicTaxon` | string | High-level group (Mammalia, Aves, Insecta, Plantae, etc.) |
| `observedOn` | string | Date the observation was recorded (YYYY-MM-DD) |
| `placeGuess` | string | Human-readable location text provided by the observer |
| `latitude` | number | GPS latitude of the observation |
| `longitude` | number | GPS longitude of the observation |
| `positionalAccuracy` | integer | Coordinate accuracy in metres, when supplied |
| `user` | string | iNaturalist username of the observer |
| `qualityGrade` | string | Quality grade: `research`, `needs_id`, or `casual` |
| `numIdentificationAgreements` | integer | Agreeing identifications (or observation count for taxa rows) |
| `photoUrl` | string | Direct URL to the observation photo (medium size) |
| `uri` | string | Canonical URL of the observation on iNaturalist.org |
| `license` | string | Creative Commons license code (e.g., `cc-by-nc`) |

**Example JSON output:**

```json
{
  "id": 123456789,
  "speciesGuess": "African Lion",
  "taxonName": "Panthera leo",
  "taxonRank": "species",
  "iconicTaxon": "Mammalia",
  "observedOn": "2024-03-15",
  "placeGuess": "Maasai Mara, Kenya",
  "latitude": -1.5033,
  "longitude": 35.1433,
  "user": "wildlife_observer",
  "qualityGrade": "research",
  "photoUrl": "https://inaturalist-open-data.s3.amazonaws.com/photos/12345/medium.jpg",
  "uri": "https://www.inaturalist.org/observations/123456789",
  "license": "cc-by-nc"
}
```

### How to use

#### Option A — Search observations by taxon name or keyword

Set `mode` to `observations` and provide a `taxonName` (scientific or common name) or `query` (free text). Optionally filter by `placeId` and `qualityGrade`.

```json
{
  "mode": "observations",
  "taxonName": "Panthera leo",
  "qualityGrade": "research",
  "maxResults": 500
}
```

#### Option B — Search species catalog (taxa)

Set `mode` to `taxa` to search the iNaturalist species catalog. Returns taxonomy, photos, and observation counts for matching species.

```json
{
  "mode": "taxa",
  "query": "Panthera",
  "maxResults": 50
}
```

#### Option C — Fetch a single observation by ID

Set `mode` to `observationDetail` and provide the `observationId` for a specific iNaturalist observation.

```json
{
  "mode": "observationDetail",
  "observationId": 12345678
}
```

### Input parameters

| Parameter | Type | Default | Description |
|---|---|---|---|
| `mode` | string | `observations` | Scraping mode: `observations`, `taxa`, or `observationDetail` |
| `query` | string | — | Free-text search query (works in `observations` and `taxa` modes) |
| `taxonName` | string | — | Scientific or common taxon name filter (e.g., `Panthera leo`) |
| `placeId` | integer | — | iNaturalist place ID to filter geographically (e.g., `1` for USA) |
| `qualityGrade` | string | `research` | Quality filter: `research`, `needs_id`, `casual`, or empty for all |
| `observationId` | integer | — | Specific observation ID for `observationDetail` mode |
| `maxResults` | integer | `200` | Maximum number of records to extract (max 10,000) |
| `proxyConfig` | object | Apify Datacenter | Proxy configuration — datacenter proxies work fine |

**Full input example:**

```json
{
  "mode": "observations",
  "taxonName": "Aquila chrysaetos",
  "placeId": 1,
  "qualityGrade": "research",
  "maxResults": 1000,
  "proxyConfig": { "useApifyProxy": true }
}
```

### Output example

```json
{
  "id": 987654321,
  "speciesGuess": "Golden Eagle",
  "taxonName": "Aquila chrysaetos",
  "taxonRank": "species",
  "iconicTaxon": "Aves",
  "observedOn": "2024-06-01",
  "placeGuess": "Rocky Mountain National Park, Colorado, USA",
  "latitude": 40.3428,
  "longitude": -105.6836,
  "user": "raptor_watcher",
  "qualityGrade": "research",
  "photoUrl": "https://inaturalist-open-data.s3.amazonaws.com/photos/99887/medium.jpg",
  "uri": "https://www.inaturalist.org/observations/987654321",
  "license": "cc-by-nc"
}
```

### Tips for best results

- **Use scientific names in `taxonName`** for precise filtering — `Panthera leo` returns only lion records, while `query=lion` may match unrelated results.
- **Set `qualityGrade=research`** to get verified, community-validated observations with two or more matching identifications.
- **Find place IDs** by browsing iNaturalist.org — navigate to a region's page and extract the numeric ID from the URL (e.g., `inaturalist.org/places/6986` → place ID 6986 for Kenya).
- **Combine taxonName + placeId** to map species distribution within a specific country or protected area.
- **Use `taxa` mode first** to discover the correct scientific name before running a large `observations` scrape.
- **Set `maxResults` conservatively** for testing — start with 200, then scale up to 5,000–10,000 for full datasets.
- **iNaturalist's API is rate-limited** to ~60 requests/minute per IP — the actor includes automatic retries for 429 responses.
- **null fields are expected** — some observations lack GPS coordinates (geoprivacy=obscured) or photos; these fields will be `null`.
- **Use `observationDetail` mode** to fetch one known observation ID as the same normalized 18-field record used by observation search.
- **Schedule runs** on Apify to capture new research-grade observations weekly for ongoing species monitoring projects.

### Integrations

- **Google Sheets** — export datasets directly to Google Sheets via Apify's built-in integration; update your biodiversity tracking spreadsheet automatically.
- **Slack** — configure Apify webhooks to post new observation counts to a Slack channel when a scheduled run completes.
- **Zapier / Make** — trigger downstream workflows (email alerts, database inserts, GIS updates) when the actor finishes.
- **Webhooks** — call any HTTP endpoint with run metadata and dataset URL on completion.
- **Apify Scheduler** — run daily or weekly to capture newly submitted research-grade observations.

### API usage

**cURL:**

```bash
curl -X POST "https://api.apify.com/v2/acts/logiover~inaturalist-scraper/runs?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"mode":"observations","taxonName":"Panthera leo","qualityGrade":"research","maxResults":500}'
```

**Node.js:**

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_TOKEN' });
const run = await client.actor('logiover/inaturalist-scraper').call({
  mode: 'observations',
  taxonName: 'Panthera leo',
  qualityGrade: 'research',
  maxResults: 500,
});
const items = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.items);
```

**Python:**

```python
from apify_client import ApifyClient
client = ApifyClient('YOUR_TOKEN')
run = client.actor('logiover/inaturalist-scraper').call(run_input={
    'mode': 'observations',
    'taxonName': 'Panthera leo',
    'qualityGrade': 'research',
    'maxResults': 500,
})
for item in client.dataset(run['defaultDatasetId']).iterate_items():
    print(item)
```

### Use with AI agents (MCP)

This actor is available as an MCP tool for AI agents. When connected to Claude or another MCP-compatible agent, you can instruct it: *"Use the iNaturalist scraper to pull 1,000 research-grade owl observations in Europe and summarize the species distribution by country."* The agent calls the actor, retrieves the dataset, and processes the results autonomously — no manual data download required.

### FAQ

#### Does this actor require an API key or iNaturalist account?

No. The iNaturalist API is publicly accessible without any authentication. The actor makes standard GET requests to `api.inaturalist.org/v1/` — no API key, no account, no login needed.

#### How many observations can I extract?

The iNaturalist database contains over 200 million observations. Each actor run can pull up to 10,000 records (set via `maxResults`). For larger datasets, schedule multiple runs with different place IDs or taxon filters.

#### What is a "research grade" observation?

Research grade is iNaturalist's highest quality tier — the observation has a photo, a date, coordinates, and at least two community identifications agreeing on the species. These observations are used in scientific publications and GBIF data exports.

#### Why are some coordinates null?

iNaturalist allows observers to obscure their GPS location for sensitive or endangered species. When geoprivacy is set to `obscured`, the API returns null coordinates. The `placeGuess` field (human-written location text) may still be populated.

#### Can I filter by country or region?

Yes — use the `placeId` parameter. Find the numeric ID by visiting the country or region page on iNaturalist.org and extracting the ID from the URL. For example, Kenya = `6986`, USA = `1`, Germany = `7082`.

#### What taxon groups are covered?

All of iNaturalist's iconic groups: Mammalia (mammals), Aves (birds), Reptilia, Amphibia, Insecta, Actinopterygii (fish), Arachnida, Mollusca, Plantae, Fungi, and more — any life form recorded on the platform.

#### How often is iNaturalist data updated?

Observations are submitted in near-real-time by millions of citizen scientists worldwide. Running the actor daily captures new research-grade submissions as they are community-validated.

#### Can I get all species in a genus?

Use `taxa` mode with `query` set to the genus name (e.g., `Panthera`). This returns all species, subspecies, and higher ranks matching that name from the iNaturalist taxonomy.

#### How do I export to CSV or Excel?

In Apify, every dataset can be downloaded as CSV, JSON, XML, or Excel from the dataset view or via API with `?format=csv`. Google Sheets integration is also available in one click.

#### Is the photo URL always available?

Most research-grade observations include at least one photo. The actor returns the medium-size URL. Some observations may have no photo (sound-only or text-only records), in which case `photoUrl` is null.

#### What happens if I get zero results?

Check that your `taxonName` is spelled correctly and matches iNaturalist's taxonomy (use `taxa` mode first to verify). Also confirm your `placeId` is valid. When `taxonName` and `iconicTaxon` are both set, they are combined and must belong to the same group — for example `Corvus` + `Aves`; `Panthera` + `Aves` is an intentionally empty intersection. Some rare species may also have very few or no research-grade observations. A network/API failure is reported as a failed run rather than being mislabeled as a valid empty dataset.

#### Is there a rate limit?

The iNaturalist public API allows approximately 60 requests per minute per IP. The actor handles 429 responses automatically with exponential back-off and retries.

### Is it legal?

iNaturalist observations are published under Creative Commons licenses (primarily CC BY-NC) by the contributors who upload them. The iNaturalist API is publicly documented and designed for programmatic access. This actor retrieves only publicly available observation data. Always respect the `license` field in each record when republishing or using the data commercially — some records are CC BY-NC (non-commercial use only). Review iNaturalist's [Terms of Service](https://www.inaturalist.org/pages/terms) and the applicable Creative Commons license for each observation before use in commercial products.

### Related scrapers

- **[GBIF Species Occurrence Scraper](https://apify.com/logiover)** — access the Global Biodiversity Information Facility for curated, peer-reviewed species occurrence data from museum collections worldwide.
- **[OpenStreetMap Business & POI Scraper](https://apify.com/logiover/openstreetmap-business-poi-scraper)** — extract geographic features and POIs from OSM for spatial analysis and location intelligence.
- **[USGS Earthquake Scraper](https://apify.com/logiover/usgs-earthquake-scraper)** — pull real-time seismic event data from the USGS API for geospatial research.
- **[Global Health Stats Scraper](https://apify.com/logiover/global-health-stats-scraper)** — extract WHO/World Bank health indicators for cross-country public health analysis.

### 📝 Changelog

#### 2026-08-01

- Completed the August 2026 full health check: verified empty/programmatic default, Console UI default, and two source-informed alternative inputs on Apify.
- Confirmed successful live execution, non-empty structured output, dataset-field/type integrity, and logical sample quality within the 5-minute quality window.
- Preserved taxon-filter semantics: an unresolved taxon no longer falls back to unrelated unfiltered observations, first-page API failures now fail explicitly, and invalid mode-specific inputs are rejected instead of succeeding empty.
- Documented that taxonName and iconicTaxon are intersected, and refreshed the contradictory Aves + Panthera health-check input to the officially verified productive Aves + Corvus combination.
- Aligned README output documentation with the actual 18-field numeric contract, including integer IDs, numeric coordinates, positional accuracy and identification-agreement counts.

#### 2026-08-01 — Health-check remediation

- August 2026 monthly health-check remediation is in progress; this build contains fixes verified from empty/default, Console-default, targeted live probes, or field-level semantic review.
- Preserved taxon-filter semantics: an unresolved taxon no longer falls back to unrelated unfiltered observations, first-page API failures now fail explicitly, and invalid mode-specific inputs are rejected instead of succeeding empty.
- Documented that taxonName and iconicTaxon are intersected, and refreshed the contradictory Aves + Panthera health-check input to the officially verified productive Aves + Corvus combination.
- Aligned README output documentation with the actual 18-field numeric contract, including integer IDs, numeric coordinates, positional accuracy and identification-agreement counts.
- The final four-input matrix verdict will be appended after post-build cloud revalidation.

# Actor input Schema

## `mode` (type: `string`):

Scraping mode: 'observations' (search observations), 'taxa' (search species/taxa), or 'observationDetail' (single observation by ID).

## `query` (type: `string`):

Free-text search term (e.g. 'lion', 'eagle'). Used in observations and taxa modes. Leave empty to browse all.

## `iconicTaxon` (type: `string`):

Restrict observations to a major group of life. This is the fastest way to filter (e.g. all mammals, all birds). Leave empty for all groups. If you also set Taxon Name, both filters are combined, so they must describe the same group (for example Aves + Corvus, not Aves + Panthera).

## `taxonName` (type: `string`):

Scientific or common name at ANY rank — species ('Panthera leo'), genus ('Panthera'), family, order, or class ('Mammalia'). It is resolved to a taxon id, so higher taxa work too. Leave empty for no taxon filter. When combined with Iconic Taxon, the two filters must be taxonomically compatible.

## `placeId` (type: `integer`):

iNaturalist place ID to filter observations geographically (e.g. 1=USA, 6986=Kenya). Optional.

## `qualityGrade` (type: `string`):

Filter by observation quality. Leave as 'All' for everything.

## `observationId` (type: `integer`):

For 'observationDetail' mode — specific iNaturalist observation ID to fetch.

## `maxResults` (type: `integer`):

Maximum number of records to scrape. The observations endpoint caps paging at 10000. Default 200.

## `proxyConfig` (type: `object`):

Apify proxy settings. Automatic proxy is recommended; the actor also falls back to a direct connection if the proxy is unavailable.

## Actor input object example

```json
{
  "mode": "observations",
  "iconicTaxon": "",
  "qualityGrade": "research",
  "maxResults": 500,
  "proxyConfig": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `results` (type: `string`):

All records extracted by this run. Open the Dataset tab to browse, filter, and export as CSV, JSON, or Excel.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "qualityGrade": "research",
    "maxResults": 500
};

// Run the Actor and wait for it to finish
const run = await client.actor("logiover/inaturalist-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "qualityGrade": "research",
    "maxResults": 500,
}

# Run the Actor and wait for it to finish
run = client.actor("logiover/inaturalist-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "qualityGrade": "research",
  "maxResults": 500
}' |
apify call logiover/inaturalist-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=logiover/inaturalist-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/NHZFsF5C8jfeOQNKa/builds/zpbdXw9f9JyC55AGf/openapi.json
