eBird CLI
A command-line interface for exploring eBird bird observation data.
Prerequisites
- Python 3.11+
- eBird API Key (obtainable with free eBird account)
Installation
- Clone the repository
- Set up a virtual environment
- Install the
ebird-clicommand from the checkout:pip install .
- Configure your eBird API key
Configuration
Command-Line Arguments
The CLI supports the following arguments:
| Argument | Description | Default | Required |
|---|---|---|---|
--api-key |
eBird API key | From EBIRDAPIKEY env var |
Yes |
--region |
eBird subnational level 2 region code | From EBIRDDEFAULTREGION env var |
Yes |
--locale |
Language locale | From EBIRDLOCALE (or fr) |
No |
--lat |
Latitude | From EBIRDLAT env var |
No |
--long |
Longitude | From EBIRDLONG env var |
No |
--year-list |
Path to year observations list | From EBIRDYEARLIST env var |
No |
--life-list |
Path to lifetime observations list | From EBIRDLIFELIST env var |
No |
--aggregations |
Path to aggregations JSON file | From EBIRDAGGREGATIONS env var |
No |
Environment Variables
You can configure the CLI using the following environment variables to avoid manual parameter entry:
EBIRDAPIKEY: Your eBird API keyEBIRDDEFAULTREGION: Default region for default search and hotspots filtering (CA-QC-MR)EBIRDLOCALE: Preferred language locale (fr)EBIRDLAT: Latitude for location-based searches (47.87)EBIRDLONG: Longitude for location-based searches (-72.17)EBIRDYEARLIST: Path to your year observations list (~/ebird_data/year_list.csv)EBIRDLIFELIST: Path to your lifetime observations list (~/ebird_data/life_list.csv)EBIRDAGGREGATIONS: Path to your aggregations JSON file (~/ebird_data/aggregations.json)
Usage
Launching the CLI
ebird-cli --api-key <ebird-api-key> --region <region-code> [optional arguments]
ebird-cli --version prints the installed version.
Available Commands
When launched, the CLI will display a menu of available commands:
recent <scope, -region> [-back, -species]: Fetch recent bird observationsnotable <scope, -region> [-back]: Fetch notable bird observations
Autocompletion
Suggestions appear as you type: command names, scopes, flags, region names for the chosen scope, species names and -back values. Press Tab to accept the first suggestion, or press it again to cycle through them.
Search Scopes
Bird observations can be searched in multiple scopes.
-
Nearby: Based on provided latitude and longitude
- Requires
--latand--longprogram arguments - Shows observations near the specified geographic coordinates
recent nearby
- Requires
-
Hotspot: eBird-defined hotspots
recent hotspot -region Dunes de Tadoussac
-
Regional: eBird Subnational Level 2
recent regional -region Montréal
-
Subnational: eBird Subnational Level 1
recent subnational -region Québec
The -region flag supports context-sensitive autocompletion based on the selected scope. If no -region flag is provided, default region will be used.
Search length
Use the optional -back parameter to change the number of days back to fetch observations.
-
Values: from 1 to 30
-
Default: 7
notable subnational -region Québec -back 30
Aggregations
Aggregations allow you to define custom named groups of hotspots that appear alongside eBird hotspots when using the hotspot scope. This is useful for combining multiple nearby locations under a single name.
Provide the path to your aggregations file via --aggregations or the EBIRDAGGREGATIONS environment variable:
ebird-cli --api-key <key> --region <region> --aggregations ~/ebird_data/aggregations.json
The aggregations file is a JSON array where each element maps a custom name to a list of eBird location IDs:
[
{
"Technoparc": ["L9980102", "L4886900", "L11363355"]
}
]
Once configured, aggregation names are available in the -region autocomplete when using the hotspot scope:
recent hotspot -region Technoparc
Species filter
Use the optional -species flag with the recent command to filter observations to a single species.
recent nearby -species Canard colvert
recent regional -region Montréal -species Harfang des neiges
The -species flag supports context-sensitive autocompletion using the cached taxonomy. Start typing a common name and press Tab to see matching species.
Note: Autocompletion and lookup use the locale specified by
--locale/EBIRDLOCALE. Species names must be typed in the configured locale.
List highlighting
When using --year-list and --life-list:
- Year list targets are highlighted in green
- Life list targets are highlighted in red
Obtaining list files
The eBird API does not expose life list or year list data, so these CSV files must be downloaded from the eBird website. The ebird-cli-download-lists command, installed alongside ebird-cli, downloads both into output_dir as life_list.csv and year_list.csv:
ebird-cli-download-lists session_id output_dir
This requires a valid eBird session cookie (EBIRD_SESSIONID), which can be obtained from your browser after logging in to ebird.org. The command must be re-run whenever your lists change.
Note: The life list only changes when you see a species for the first time ever, making it infrequent and easy to manage. The year list changes with every new species seen in the current year and resets annually, requiring more frequent re-runs of the command.
Data cache
To avoid redundant API calls to eBird, the CLI caches reference data locally on first run. The cache is stored in the platform-appropriate user cache directory (e.g. %LOCALAPPDATA%\ebird_cli\Cache\ebird_cli on Windows, ~/.cache/ebird_cli on Linux/macOS).
The following data is cached:
- Location data (per region): subnational level 1 regions, subnational level 2 regions, and every hotspot in the subnational region — stored as JSON files under
location/<national>/andlocation/<national>/<subnational>/ - Taxonomy (per locale and national region): the full eBird taxonomy filtered to species observed in the configured country — stored as CSV files under
taxonomy/<national>/
Hotspots are fetched again on launch once their cached file is more than 30 days old, so new hotspots appear; if eBird can't be reached, the older file is used. All other cached data is written once and reused on every subsequent launch. To force a refresh (e.g. after a new eBird taxonomy release or a region change), delete the relevant files or the entire cache directory.
Log file
Each launch appends debug messages to app.log in the platform-appropriate user log directory, created on first launch:
- Windows:
%LOCALAPPDATA%\ebird_cli\ebird_cli\Logs\app.log - Linux:
~/.cache/ebird_cli/log/app.log(under$XDG_CACHE_HOMEinstead of~/.cachewhen it is set) - macOS:
~/Library/Logs/ebird_cli/app.log
The file is never rotated or trimmed; delete it at any time.
Development setup
Virtual environment
-
Activate the virtual environment:
- On Windows:
venv\Scripts\activate - On macOS/Linux:
source venv/bin/activate
- On Windows:
-
Install the project in editable mode with the dev tools (
requirements-dev.txtadds the test, lint and build tools to the pinned runtime dependencies):pip install -e . -r requirements-dev.txt
The tests read the version from the installed package, so they need this editable install.
Tests
The test suite runs offline: it never calls the eBird API, needs no API key and never touches your user cache or log directory.
python -m pytest
Tests live in tests/, mirroring the source layout:
tests/cli/: therecentandnotablecommands and autocompletion, driven through their public entry pointstests/services/,tests/domain/: cache, location and taxonomy services and domain value parsingtests/utils/: where the app log is writtentests/test_prompt_dispatch.py,tests/test_program_arguments.py: prompt input handling and program argumentstests/conftest.py: shared fixtures, includingmake_cli, which wires real services and commands the waymaindoestests/fakes.py: the in-memory fake eBird client, the only test doubletests/fixtures/: small hand-written cache, list and aggregation files for theCA-QC-MRregion
Tests named ..._currently_... pin behaviour that looks accidental, so changing it is a deliberate test change.
Demo GIFs
The GIFs in this README are recorded with VHS from the tapes in docs/demo/. They call the live eBird API, so they need your API key and environment variables set. config.tape holds the shared settings and launches the CLI out of frame.
On Windows, install VHS and its terminal dependency, then re-record a GIF from the repository root:
winget install charmbracelet.vhs tsl0922.ttyd
vhs docs/demo/overview.tape
VHS also needs ffmpeg on the PATH.
Cutting a release
Releases are published to PyPI by the Release workflow (.github/workflows/release.yml) through trusted publishing; no API token is involved.
- Bump
versioninpyproject.tomland merge it tomain. - Optionally, do a dry run: run the
Releaseworkflow manually from the Actions tab. It uploads that version to TestPyPI, which accepts each version only once. Check the upload installs:pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ ebird-cli
- Tag the release commit
vX.Y.Z, matching the version, and push the tag. - Publish a GitHub release from that tag. The workflow uploads it to PyPI, and fails without uploading if the tag doesn't match the version in
pyproject.toml.
Credits
Bird observation data and the eBird platform are provided by the Cornell Lab of Ornithology. This project would not be possible without their freely available eBird API.
This project relies on the following open-source packages:
- ebird-api — Python wrapper for the eBird API
- prompt_toolkit — Interactive command-line interface with autocompletion
- rich — Terminal formatting and highlighted output
- pandas — CSV observation list parsing
- colorama — Cross-platform terminal color support
- requests — HTTP requests to the eBird API
License
MIT License
Metadata
Release files for ebird-cli 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| ebird_cli-0.1.0.tar.gz | 28.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ebird_cli-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 55.0 kB
Release files / ebird_cli-0.1.0.tar.gz
| Download URL | ebird_cli-0.1.0.tar.gz |
|---|---|
| Size | 28.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
38f00c5188e64af96a961e79605d9540a9c535175c796fd0d62c46e9fa099c96
|
|
BLAKE2b-256 checksum How to use checksums |
b8f485119e6b7560b615a19313309e7eda65cba6a0d8d5e7d928cac4c34de426
|
| 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 Oct 18, 2026.
Transparency logRelease files / ebird_cli-0.1.0-py3-none-any.whl
| Download URL | ebird_cli-0.1.0-py3-none-any.whl |
|---|---|
| Size | 26.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f51eba7222bbbb944440c7a7f9c0d25f32049a7539232c357369ac59fabbcb6b
|
|
BLAKE2b-256 checksum How to use checksums |
79873ee633bf38f530d83dff76da727701d1868e83354a5bf50bfad39f3ad2d7
|
| 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 Oct 18, 2026.
Transparency log