eBird-IUCN Synthesizer
CLI tool and Python library that synthesizes eBird observation data with IUCN Red List conservation status.
Problem
Ecologists spend hours manually cross-referencing bird sighting data when preparing conservation reports. eBird provides observation data, IUCN Red List provides threat categories — but these databases don't communicate automatically.
Solution
Query eBird for a region or coordinates, automatically enrich with IUCN threat status, and export clean JSON/CSV/Avro reports ready for analysis.
Features
- Query by region code (e.g.,
RS,US-NY) or coordinates - IUCN Red List enrichment with local caching (90-day TTL)
- Filter to threatened species only (VU/EN/CR)
- Multiple output formats: JSON, CSV, Avro
- Optional UUID resolution via BirdLife Resolution API
- Stale-while-revalidate caching strategy
- Cache backends: JSON files, SQLite, PostgreSQL
Installation
pip install birdlife-ebird-iucn
# With PostgreSQL support
pip install birdlife-ebird-iucn[postgres]
Quick Start
CLI
# Set up credentials
export EBIRD_API_KEY="your-key" # https://ebird.org/api/keygen
export IUCN_API_TOKEN="your-token" # https://api.iucnredlist.org/users/sign_up
# Query by region
python -m birdlife_ebird_iucn RS --format json
# Query by coordinates
python -m birdlife_ebird_iucn --lat 44.8 --lng 20.4 --days 7
# Threatened species only
python -m birdlife_ebird_iucn RS --threatened-only --format csv
Python API
import asyncio
from birdlife_ebird_iucn import Config, Synthesizer
from birdlife_ebird_iucn.serializers import JsonSerializer
async def main():
config = Config() # Reads from environment
synth = Synthesizer.from_config(config)
try:
result = await synth.synthesize(
region_code="RS",
back_days=14,
threatened_only=True,
)
# Access species via result.data, location via result.meta.location
print(f"Found {len(result.data)} threatened species")
for species in result.data:
print(f" {species.iucn_status.value}: {species.scientific_name}")
# Export to JSON
print(JsonSerializer().serialize(result))
finally:
await synth.close()
asyncio.run(main())
Configuration
All settings via environment variables or .env file:
| Variable | Required | Description |
|---|---|---|
EBIRD_API_KEY |
Yes | eBird API key |
IUCN_API_TOKEN |
Yes | IUCN Red List API token |
CACHE_TYPE |
No | json (default), sqlite, or postgres |
CACHE_DIR |
No | Cache directory (default: ./.cache) |
CACHE_TTL_DAYS |
No | Cache TTL in days (default: 90) |
POSTGRES_URL |
If postgres | PostgreSQL connection URL |
RESOLUTION_API_URL |
No | BirdLife Resolution API for canonical UUIDs |
RESOLUTION_API_TOKEN |
No | Bearer token for Resolution API |
Cache Backends
JSON (default)
CACHE_TYPE=json
CACHE_DIR=./.cache
SQLite
CACHE_TYPE=sqlite
CACHE_DIR=./.cache
PostgreSQL
CACHE_TYPE=postgres
POSTGRES_URL=postgresql://user:pass@localhost:5432/birdlife
Resolution API
By default, UUIDs are generated locally. To use canonical BirdLife IDs:
RESOLUTION_API_URL=https://birdlife.tech/api/v1
Output Formats
All outputs follow the API Response Convention with a {data, meta} envelope:
{
"data": [...], // Taxon[] - species found
"meta": {
"resultType": "species-search",
"queryTimestamp": "2026-07-10T12:00:00Z",
"filtersApplied": {"backDays": "14", "threatenedOnly": "true"},
"location": {
"locationID": "...",
"name": "Serbia",
"decimalLatitude": 44.0,
"decimalLongitude": 21.0,
...
}
}
}
JSON
Schema-compliant JSON following birdlife-schema.
CSV
Flattened tabular format for spreadsheet analysis. Metadata fields extracted from meta.
Avro
Binary format for big data pipelines.
Examples
The examples/ directory contains ready-to-run examples:
CLI Example
cd examples
cp .env.example .env # Add your API keys
# Query Serbia
python cli_example.py RS
# Query by coordinates (Belgrade)
python cli_example.py --lat 44.8 --lng 20.4 --days 7
# Threatened species only, CSV output
python cli_example.py RS --threatened-only --format csv
Jupyter Notebook
Interactive notebook with step-by-step examples:
cd examples
jupyter notebook notebook_example.ipynb
Region Codes
eBird uses hierarchical region codes:
- Country:
RS(Serbia),US(USA),GB(UK) - State/Province:
US-NY(New York),CA-ON(Ontario) - County:
US-NY-061(New York County)
Find codes at: https://ebird.org/region/world
Development
# Clone and install
git clone https://github.com/birdlife-tools/ebird-iucn-synthesizer
cd ebird-iucn-synthesizer
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
# Run tests
pytest
# Type check
mypy src/
# Lint
ruff check src/
Architecture
synthesize() request
│
▼
┌──────────────┐
│ eBird API │ ─── recent observations
└──────────────┘
│
▼
┌──────────────┐
│ IUCN Cache │ ─── threat status (stale-while-revalidate)
└──────────────┘
│
▼
┌──────────────┐
│ Resolver │ ─── canonical UUIDs (optional)
└──────────────┘
│
▼
┌──────────────┐
│ Serializer │ ─── JSON / CSV / Avro
└──────────────┘
Community
Join the discussion:
License
MIT — see LICENSE
Release files for birdlife-ebird-iucn 0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| birdlife_ebird_iucn-0.2.1.tar.gz | 69.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| birdlife_ebird_iucn-0.2.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 98.2 kB
Release files / birdlife_ebird_iucn-0.2.1.tar.gz
| Download URL | birdlife_ebird_iucn-0.2.1.tar.gz |
|---|---|
| Size | 69.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
737eefdb8c60dcdf81c7f4400c680caf5a653f8ba8aa7278f3255caf615217d9
|
|
BLAKE2b-256 checksum How to use checksums |
cb6a8092c60466576ca6d7a6f4f883ddd18707768c612631a69251414bb11714
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.13
|
Release files / birdlife_ebird_iucn-0.2.1-py3-none-any.whl
| Download URL | birdlife_ebird_iucn-0.2.1-py3-none-any.whl |
|---|---|
| Size | 28.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3485bb2e847c4699b48d1c95a8556ad14de1635c7ab2471aa2119f6cb28fa6b3
|
|
BLAKE2b-256 checksum How to use checksums |
f29305f73534af897aff807666ed38c070ee7ea5b9764f3ef09f466a8536f04e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.13
|