The EarthDaily Python Client is a comprehensive library for interacting with the EarthDaily Analytics platform. It provides seamless access to satellite data, STAC item management, and platform APIs through a unified interface.
- Platform API Access: Full integration with EarthDaily platform services
- STAC Item Management: Complete CRUD operations for STAC items
- Datacube Module: Modern, self-contained datacube creation and manipulation
- Modern Architecture: Streamlined client design with comprehensive error handling
- Flexible Installation: Modular installation options for different use cases
Supported Python Versions: 3.10, 3.11, 3.12, 3.13, 3.14
pip install earthdailypip install "earthdaily[platform]"pip install "earthdaily[datacube]"pip install "earthdaily[platform,datacube]"pip install "earthdaily[platform,datacube,utils]"Looking for v1/legacy functionality? The legacy module (
client.legacy) was removed in v2.0.0. If you need legacy datacube features, pin to v1.x.x (earthdaily<2.0.0). The v1.x.x line will continue to receive security and critical bug fixes only.
The EarthPlatform STAC API is protected by bearer authentication. A bearer token is generated using OAuth Client Credentials Flow. The required client_id, client_secret, and access_token_url values can be found on the Account Management Console.
- Go to the Account Management Console
- Click the Provision New API Credentials button to generate your API credentials
- Copy the generated
client_secretvalue β this will be yourEDS_SECRET
For more details, see the API Authentication Guide.
Create a .env file in your project root with your credentials:
# .env
EDS_CLIENT_ID=EARTHDAILY_API_TOKEN
EDS_SECRET=<Go to Account Management Console, click Provision New API Credentials, copy the client_secret>
EDS_AUTH_URL=https://api.earthdaily.com/account_management/v1/authentication/api_tokens/exchange
EDS_API_URL=https://api.earthdaily.comNote: To use .env files and Jupyter notebooks, install with the utils extra:
pip install "earthdaily[utils]"from dotenv import load_dotenv
from earthdaily import EDSClient, EDSConfig
# Load environment variables
load_dotenv(".env")
# Initialize client
config = EDSConfig()
client = EDSClient(config)# Direct configuration (without .env file)
config = EDSConfig(
client_id="EARTHDAILY_API_TOKEN",
client_secret="<Go to Account Management Console, click Provision New API Credentials, copy the client_secret>",
token_url="https://api.earthdaily.com/account_management/v1/authentication/api_tokens/exchange",
base_url="https://api.earthdaily.com"
)
client = EDSClient(config)The EDSConfig class supports additional configuration options for customizing client behavior:
config = EDSConfig(
# ... authentication parameters ...
# HTTP retry configuration
max_retries=5, # Maximum retry attempts (default: 3)
retry_backoff_factor=2.0, # Exponential backoff factor (default: 1.0)
# Asset access mode
asset_access_mode="presigned-urls" # "presigned-urls", "proxy-urls", or "raw"
)max_retries: Maximum number of retry attemptsretry_backoff_factor: Backoff factor for retry delays
Examples:
retry_backoff_factor=1.0: Delays of 1s, 2s, 4sretry_backoff_factor=0.5: Delays of 0.5s, 1s, 2sretry_backoff_factor=2.0: Delays of 2s, 4s, 8s
When asset_access_mode="proxy-urls", assets are served through authenticated
proxy URLs. GDAL/rasterio cannot send the EDS bearer token, so the client can
fetch a short-lived asset cookie and write it to a Netscape-format file that
you pass through GDAL_HTTP_COOKIEFILE.
Enable the feature on EDSConfig and ask the client for a cookie file. You
must provide path explicitly so the credential-like file does not end up in
an unexpected location (for example, committed to a repository):
import rasterio
from earthdaily import EDSClient, EDSConfig
config = EDSConfig(
asset_access_mode="proxy-urls",
platform_cookie_enabled=True,
platform_cookie_auto_refresh=True,
)
with EDSClient(config) as client:
cookie_file = client.get_platform_cookie_file(
path="/tmp/earthdaily-platform-cookies.txt"
)
with rasterio.Env(GDAL_HTTP_COOKIEFILE=str(cookie_file)):
... # e.g. odc.stac.stac_load(...), rasterio.open(...)platform_cookie_auto_refresh=Truestarts a background daemon thread that refreshes the cookie file in place before it expires.EDSClient.close()(called automatically by thewithstatement) stops the refresh thread and deletes the cookie file.- The parent directory of
pathmust already exist; the client never creates directories for you.
See the EarthMosaics notebook for a full example.
Search for satellite data using STAC:
# Search for Sentinel-2 data
search_result = client.platform.pystac_client.search(
collections=["sentinel-2-l2a"],
datetime="2024-06-01T00:00:00Z/2024-08-01T00:00:00Z",
max_items=10
)
items = list(search_result.items())Create and manage STAC items:
# Create a new STAC item
stac_item = {
"type": "Feature",
"stac_version": "1.0.0",
"id": "example-item-123",
"collection": "your-collection",
"geometry": {"type": "Point", "coordinates": [-67.7, -37.8]},
"properties": {"datetime": "2024-01-01T00:00:00Z"},
"links": [],
"assets": {}
}
client.platform.stac_item.create_item("your-collection", stac_item)The client is organized into main modules:
-
client.platform: Modern platform API accesspystac_client: STAC catalog searchstac_item: STAC item CRUD operationsbulk_search: Bulk search operationsbulk_insert: Bulk data insertionbulk_delete: Bulk data deletion
-
client.datacube: Datacube creation and manipulationcreate(): Create analysis-ready datacubes from STAC items- Masking, temporal aggregation, spectral indices, zonal statistics, and more
# Create a new STAC item
item = client.platform.stac_item.create_item(
collection_id="your-collection",
item_data={
"type": "Feature",
"stac_version": "1.0.0",
"id": "item-123",
"geometry": {"type": "Point", "coordinates": [-67.7, -37.8]},
"properties": {"datetime": "2024-01-01T00:00:00Z"}
},
return_format="dict" # "dict", "json", or "pystac"
)# Get a specific item
item = client.platform.stac_item.get_item(
collection_id="your-collection",
item_id="item-123",
return_format="pystac"
)# Update an existing item
updated_item = client.platform.stac_item.update_item(
collection_id="your-collection",
item_id="item-123",
item_data={"properties": {"updated": "2024-01-02T00:00:00Z"}},
return_format="dict"
)# Delete an item
client.platform.stac_item.delete_item(
collection_id="your-collection",
item_id="item-123"
)# Download item assets
downloads = client.platform.stac_item.download_assets(
item=item,
asset_keys=["blue", "green", "red"],
output_dir="./downloads",
max_workers=3
)# Create a bulk search job
search_job = client.platform.bulk_search.create(
collections=["sentinel-2-l2a"],
datetime="2024-01-01T00:00:00Z/2024-02-01T00:00:00Z",
bbox=[-74.2, 40.6, -73.9, 40.9], # NYC area
limit=1000,
export_format="stacjson"
)
print(f"Job ID: {search_job.job_id}")# Check job status
job_status = client.platform.bulk_search.fetch(search_job.job_id)
print(f"Status: {job_status.status}")
print(f"Assets: {len(job_status.assets)}")# Download search results when completed
if job_status.status == "COMPLETED":
job_status.download_assets(save_location=Path("./bulk_results"))# Create bulk insert job
insert_job = client.platform.bulk_insert.create(
collection_id="your-collection",
error_handling_mode="CONTINUE", # or "STOP"
conflict_resolution_mode="SKIP" # or "OVERRIDE"
)# Prepare STAC items file and upload
items_file = Path("./stac_items.jsonl") # JSONL format
insert_job.upload(items_file)
# Start the job
insert_job.start()# Check insert job status
job_status = client.platform.bulk_insert.fetch(insert_job.job_id)
print(f"Items written: {job_status.items_written_count}")
print(f"Errors: {job_status.items_error_count}")# Create bulk delete job
delete_job = client.platform.bulk_delete.create(
collection_id="your-collection"
)# Prepare file with item IDs to delete
ids_file = Path("./items_to_delete.txt")
delete_job.upload(ids_file)
# Start the deletion
delete_job.start()# Check delete job status
job_status = client.platform.bulk_delete.fetch(delete_job.job_id)
print(f"Items deleted: {job_status.items_deleted_count}")
print(f"Errors: {job_status.items_error_count}")# Search for items using STAC API
search_results = client.platform.pystac_client.search(
collections=["sentinel-2-l2a"],
datetime="2024-01-01T00:00:00Z/2024-02-01T00:00:00Z",
bbox=[-74.2, 40.6, -73.9, 40.9],
max_items=50
)
# Process results
items = list(search_results.items())
print(f"Found {len(items)} items")# List available collections
collections = client.platform.pystac_client.get_collections()
for collection in collections:
print(f"Collection: {collection.id}")# Find available collections
collections = client.platform.pystac_client.get_collections()
print([c.id for c in collections])# Download assets from search results
for item in items:
client.platform.stac_item.download_assets(
item,
asset_keys=["blue", "green", "red"],
output_dir="./downloads",
max_workers=3
)We welcome contributions! Please see our Contributing Guide for details on:
- Development setup
- Code style guidelines
- Testing procedures
- Pull request process
This project is licensed under the MIT License - see the LICENSE file for details.
Need help? Here's how to get support:
- π Check the documentation
- π Open an issue for bugs
- π¬ Ask questions in GitHub Discussions
Ready to get started? Check out our Quick Start Example or explore the API Documentation! π