EarthCARE ESA MAAP Data Access Example#
@ ESA, 2025 = Licensed under “European Space Agency Community License”
Author: Saskia Brose (saskia.brose@esa.int)
Last updated: 05-11-2025
NEW features:
Long lasting token
JSON keys for EarthCARE data files renamed
This script shows how to query the ESA MAAP catalog, stream/download EarthCARE data and then plot the cloud water path and cloud top tempetaure directly from the streamed file.
Prerequisities#
from pystac_client import Client
import fsspec
import xarray as xr
import matplotlib.pyplot as plt
from tqdm import tqdm
import pandas as pd
import requests
from IPython.display import Image, display
import pathlib
Using the STAC API to query the ESA MAAP stac catalog#
While the discovery of data (querying the ESA MAAP catalogue) does not require any authentication or authorization, accessing the data requires a token generated with an authorized ESA account (EO Sign in) to verify the user. This is the same account and credentials you will have used for the OADS system.
catalog_url = 'https://catalog.maap.eo.esa.int/catalogue/'
catalog = Client.open(catalog_url)
The EarthCARE collections have the same name as previously on OADS, but have the extension _MAAP to distinguish them from the OADS collections. Currently the latest two baselines are provided and there are 12 collections:
Open and Free |
Restricted to special users |
Restricted CalVal users |
|---|---|---|
EarthCAREL1InstChecked_MAAP |
EarthCAREL0L1Products_MAAP |
EarthCAREL1Validated_MAAP |
EarthCAREL2InstChecked_MAAP |
EarthCAREL2Products_MAAP |
EarthCAREL2Validated_MAAP |
JAXAL2InstChecked_MAAP |
EarthCAREAuxiliary_MAAP |
JAXAL2Validated_MAAP |
EarthCAREOrbitData_MAAP |
JAXAL2Products_MAAP |
|
EarthCAREXMETL1DProducts10_MAAP |
The first step is to select a collection. You can select multiple collections by extending the list. Note that if you pass multiple collections, the query filters you use must exist across both collections!
# Select one or more collection(s)
EC_COLLECTION = ['EarthCAREL2Validated_MAAP']
EC_multiple_COLLECTIONS = ['EarthCAREL2Validated_MAAP', 'EarthCAREL1Validated_MAAP']
The second step is to further narrow down your search:
Datetime represents the temporal coverage of the data. None can be used for both start and end to indicated unbounded queries.
bbox is defined by the bottom left corner (longmin latmin) and the top right corner coordinates (longmax latmax). The default is [-180,-90,180,90].
Filter – allows you to search based on different metadata parameters.
To understand which queryables exist, you can visit:
https://catalog.maap.eo.esa.int/catalogue/collections/NAMEOFCOLLECTION/queryables
Multiple filters can be combined with or and and following a boolean type of logic.
Examples include:
productType
frame
processingLevel
instrument
orbitNumber
search = catalog.search(
collections=EC_COLLECTION,
filter="productType = 'MSI_COP_2A' and productVersion = 'ba'", # For example filter by product type and baseline. Use boolean logic for multi-filter queries
bbox = [0, -20, 10, -10],
datetime = ['2025-10-01T00:00:00Z', '2025-10-22T23:59:59Z'], # Filter by date
method = 'GET', # This is necessary
max_items=5 # Adjust as needed, given the large amount of products it is recommended to set a limit if especially if you display results in pandas dataframe or similiar
)
items = list(search.items()) # Get all items as a list
#items = search.item_collection() # Get all items as a STAC ItemCollection
results = search.matched()
print(f"{results} items found that matched the query.")
print(f"Accessing {len(items)} items (limited by max_items).")
26 items found that matched the query.
Accessing 5 items (limited by max_items).
# Inspect results
for item in items:
print(f"Item ID: {item.id}")
print(f" - Datetime: {item.datetime}")
print(f" - BBOX: {item.bbox}")
print(f" - Properties: {item.properties}")
print(f" - Assets: {list(item.assets.keys())}")
print()
Item ID: ECA_EXBA_MSI_COP_2A_20251004T014358Z_20251004T023139Z_07673A
- Datetime: 2025-10-04 01:43:58+00:00
- BBOX: [-3.943258, -22.733236, 6.340663, 22.57464]
- Properties: {'start_datetime': '2025-10-04T01:43:58.000Z', 'end_datetime': '2025-10-04T01:55:34.000Z', 'processing:facility': 'PDGS-CPFxx', 'product:type': 'MSI_COP_2A', 'sat:anx_datetime': '2025-10-04T00:17:13.853Z', 'title': 'ECA_EXBA_MSI_COP_2A_20251004T014358Z_20251004T023139Z_07673A', 'platform': 'EarthCARE', 'datetime': '2025-10-04T01:43:58.000Z', 'instruments': ['MSI'], 'constellation': 'EarthCARE', 'sat:orbit_state': 'ascending', 'processing:software': {'M-CLD': '11.30'}, 'eof-eos:mission_phase': 'Routine', 'grid:code': 'WRS-7673-A', 'processing:level': 'L2A', 'sci:doi': '10.57780/eca-94b4e53', 'created': '2025-10-04T02:31:39.000Z', 'published': '2025-10-13T11:36:52.030Z', 'version': 'BA', 'auth:schemes': {'s3': {'type': 's3'}, 'oidc': {'openIdConnectUrl': 'https://iam.ascend.icsgate.eu/realms/esa-maap/.well-known/openid-configuration', 'type': 'openIdConnect'}}, 'processing:datetime': '2025-10-04T02:31:39.000Z', 'eopf:instrument_mode': 'DEFAULT', 'updated': '2025-10-13T17:21:31Z', 'sat:absolute_orbit': 7673, 'product:acquisition_type': 'other'}
- Assets: ['thumbnail', 'product', 'metadata_ogc_10_157r4', 'enclosure_h5', 'metadata_ogc_17_003r2', 'metadata_iso_19139', 'enclosure_hdr', 'quicklook']
Item ID: ECA_EXBA_MSI_COP_2A_20251013T131444Z_20251013T162407Z_07820E
- Datetime: 2025-10-13 13:14:44+00:00
- BBOX: [4.13775, -22.718754, 14.422692, 22.589455]
- Properties: {'start_datetime': '2025-10-13T13:14:44.000Z', 'end_datetime': '2025-10-13T13:26:20.000Z', 'processing:facility': 'PDGS-CPFxx', 'product:type': 'MSI_COP_2A', 'sat:anx_datetime': '2025-10-13T12:34:19.778Z', 'title': 'ECA_EXBA_MSI_COP_2A_20251013T131444Z_20251013T162407Z_07820E', 'platform': 'EarthCARE', 'datetime': '2025-10-13T13:14:44.000Z', 'instruments': ['MSI'], 'constellation': 'EarthCARE', 'sat:orbit_state': 'descending', 'processing:software': {'M-CLD': '11.30'}, 'eof-eos:mission_phase': 'Routine', 'grid:code': 'WRS-7820-E', 'processing:level': 'L2A', 'sci:doi': '10.57780/eca-94b4e53', 'created': '2025-10-13T16:24:07.000Z', 'published': '2025-10-17T11:36:12.056Z', 'version': 'BA', 'auth:schemes': {'s3': {'type': 's3'}, 'oidc': {'openIdConnectUrl': 'https://iam.ascend.icsgate.eu/realms/esa-maap/.well-known/openid-configuration', 'type': 'openIdConnect'}}, 'processing:datetime': '2025-10-13T16:24:07.000Z', 'eopf:instrument_mode': 'DEFAULT', 'updated': '2025-10-17T13:51:49Z', 'sat:absolute_orbit': 7820, 'product:acquisition_type': 'other'}
- Assets: ['thumbnail', 'product', 'metadata_ogc_10_157r4', 'enclosure_h5', 'metadata_ogc_17_003r2', 'metadata_iso_19139', 'enclosure_hdr', 'quicklook']
Item ID: ECA_EXBA_MSI_COP_2A_20251020T132215Z_20251020T162940Z_07929E
- Datetime: 2025-10-20 13:22:15+00:00
- BBOX: [2.265359, -22.686682, 12.536523, 22.561153]
- Properties: {'start_datetime': '2025-10-20T13:22:15.000Z', 'end_datetime': '2025-10-20T13:33:50.000Z', 'processing:facility': 'PDGS-CPFxx', 'product:type': 'MSI_COP_2A', 'sat:anx_datetime': '2025-10-20T12:41:50.623Z', 'title': 'ECA_EXBA_MSI_COP_2A_20251020T132215Z_20251020T162940Z_07929E', 'platform': 'EarthCARE', 'datetime': '2025-10-20T13:22:15.000Z', 'instruments': ['MSI'], 'constellation': 'EarthCARE', 'sat:orbit_state': 'descending', 'processing:software': {'M-CLD': '11.30'}, 'eof-eos:mission_phase': 'Routine', 'grid:code': 'WRS-7929-E', 'processing:level': 'L2A', 'sci:doi': '10.57780/eca-94b4e53', 'created': '2025-10-20T16:29:40.000Z', 'published': '2025-10-20T17:34:18.048Z', 'version': 'BA', 'auth:schemes': {'s3': {'type': 's3'}, 'oidc': {'openIdConnectUrl': 'https://iam.ascend.icsgate.eu/realms/esa-maap/.well-known/openid-configuration', 'type': 'openIdConnect'}}, 'processing:datetime': '2025-10-20T16:29:40.000Z', 'eopf:instrument_mode': 'DEFAULT', 'updated': '2025-10-20T19:32:35Z', 'sat:absolute_orbit': 7929, 'product:acquisition_type': 'other'}
- Assets: ['thumbnail', 'product', 'metadata_ogc_10_157r4', 'enclosure_h5', 'metadata_ogc_17_003r2', 'metadata_iso_19139', 'enclosure_hdr', 'quicklook']
Item ID: ECA_EXBA_MSI_COP_2A_20251002T015505Z_20251002T023847Z_07642A
- Datetime: 2025-10-02 01:55:05+00:00
- BBOX: [-6.714505, -22.686855, 3.556215, 22.553251]
- Properties: {'start_datetime': '2025-10-02T01:55:05.000Z', 'end_datetime': '2025-10-02T02:06:40.000Z', 'processing:facility': 'PDGS-CPFxx', 'product:type': 'MSI_COP_2A', 'sat:anx_datetime': '2025-10-02T00:28:19.754Z', 'title': 'ECA_EXBA_MSI_COP_2A_20251002T015505Z_20251002T023847Z_07642A', 'platform': 'EarthCARE', 'datetime': '2025-10-02T01:55:05.000Z', 'instruments': ['MSI'], 'constellation': 'EarthCARE', 'sat:orbit_state': 'ascending', 'processing:software': {'M-CLD': '11.30'}, 'eof-eos:mission_phase': 'Routine', 'grid:code': 'WRS-7642-A', 'processing:level': 'L2A', 'sci:doi': '10.57780/eca-94b4e53', 'created': '2025-10-02T02:38:47.000Z', 'published': '2025-10-14T05:22:37.274Z', 'version': 'BA', 'auth:schemes': {'s3': {'type': 's3'}, 'oidc': {'openIdConnectUrl': 'https://iam.ascend.icsgate.eu/realms/esa-maap/.well-known/openid-configuration', 'type': 'openIdConnect'}}, 'processing:datetime': '2025-10-02T02:38:47.000Z', 'eopf:instrument_mode': 'DEFAULT', 'updated': '2025-10-14T07:05:47Z', 'sat:absolute_orbit': 7642, 'product:acquisition_type': 'other'}
- Assets: ['thumbnail', 'product', 'metadata_ogc_10_157r4', 'enclosure_h5', 'metadata_ogc_17_003r2', 'metadata_iso_19139', 'enclosure_hdr', 'quicklook']
Item ID: ECA_EXBA_MSI_COP_2A_20251007T134713Z_20251008T162223Z_07727E
- Datetime: 2025-10-07 13:47:13+00:00
- BBOX: [-3.97911, -22.715141, 6.304434, 22.59963]
- Properties: {'start_datetime': '2025-10-07T13:47:13.000Z', 'end_datetime': '2025-10-07T13:58:49.000Z', 'processing:facility': 'PDGS-CPFxx', 'product:type': 'MSI_COP_2A', 'sat:anx_datetime': '2025-10-07T13:06:49.316Z', 'title': 'ECA_EXBA_MSI_COP_2A_20251007T134713Z_20251008T162223Z_07727E', 'platform': 'EarthCARE', 'datetime': '2025-10-07T13:47:13.000Z', 'instruments': ['MSI'], 'constellation': 'EarthCARE', 'sat:orbit_state': 'descending', 'processing:software': {'M-CLD': '11.30'}, 'eof-eos:mission_phase': 'Routine', 'grid:code': 'WRS-7727-E', 'processing:level': 'L2A', 'sci:doi': '10.57780/eca-94b4e53', 'created': '2025-10-08T16:22:23.000Z', 'published': '2025-10-12T07:28:10.143Z', 'version': 'BA', 'auth:schemes': {'s3': {'type': 's3'}, 'oidc': {'openIdConnectUrl': 'https://iam.ascend.icsgate.eu/realms/esa-maap/.well-known/openid-configuration', 'type': 'openIdConnect'}}, 'processing:datetime': '2025-10-08T16:22:23.000Z', 'eopf:instrument_mode': 'DEFAULT', 'updated': '2025-10-13T17:24:05Z', 'sat:absolute_orbit': 7727, 'product:acquisition_type': 'other'}
- Assets: ['thumbnail', 'product', 'metadata_ogc_10_157r4', 'enclosure_h5', 'metadata_ogc_17_003r2', 'metadata_iso_19139', 'enclosure_hdr', 'quicklook']
# Choose one item
ec_product = items[1]
Results#
Assets in the ESA MAAP STAC Catalog: Each granule (one frame of EarthCARE data per product) includes multiple assets, which are different files that serve distinct purposes. These assets can include preview images, scientific data, metadata, and more.
# Optional: Inspect available assets
for asset_key, asset in ec_product.assets.items():
print(f" Asset key: {asset_key}")
print(f" href: {asset.href}")
print(f" type: {asset.media_type}")
print(f" roles: {asset.roles}")
Asset key: thumbnail
href: https://catalog.maap.eo.esa.int/data/earthcare-pdgs-01/EarthCARE/MSI_COP_2A/BA/2025/10/13/ECA_EXBA_MSI_COP_2A_20251013T131444Z_20251013T162407Z_07820E/public/ECA_EXBA_MSI_COP_2A_20251013T131444Z_20251013T162407Z_07820E.BID_1.jpeg
type: image/jpeg
roles: ['thumbnail']
Asset key: product
href: https://catalog.maap.eo.esa.int/data/zipper/earthcare-pdgs-01/EarthCARE/MSI_COP_2A/BA/2025/10/13/ECA_EXBA_MSI_COP_2A_20251013T131444Z_20251013T162407Z_07820E/ECA_EXBA_MSI_COP_2A_20251013T131444Z_20251013T162407Z_07820E
type: application/zip
roles: ['data', 'metadata', 'archive']
Asset key: metadata_ogc_10_157r4
href: https://catalog.maap.eo.esa.int/catalogue/collections/EarthCAREL2Validated_MAAP/items/ECA_EXBA_MSI_COP_2A_20251013T131444Z_20251013T162407Z_07820E?httpAccept=application/gml%2Bxml&recordSchema=om
type: application/gml+xml;profile="http://www.opengis.net/spec/EOMPOM/1.1"
roles: ['metadata']
Asset key: enclosure_h5
href: https://catalog.maap.eo.esa.int/data/earthcare-pdgs-01/EarthCARE/MSI_COP_2A/BA/2025/10/13/ECA_EXBA_MSI_COP_2A_20251013T131444Z_20251013T162407Z_07820E/ECA_EXBA_MSI_COP_2A_20251013T131444Z_20251013T162407Z_07820E/ECA_EXBA_MSI_COP_2A_20251013T131444Z_20251013T162407Z_07820E.h5
type: application/x-hdf5
roles: ['data']
Asset key: metadata_ogc_17_003r2
href: https://catalog.maap.eo.esa.int/catalogue/collections/EarthCAREL2Validated_MAAP/items/ECA_EXBA_MSI_COP_2A_20251013T131444Z_20251013T162407Z_07820E?mode=owc
type: application/geo+json;profile="http://www.opengis.net/spec/eo-geojson/1.0"
roles: ['metadata']
Asset key: metadata_iso_19139
href: https://catalog.maap.eo.esa.int/catalogue/collections/EarthCAREL2Validated_MAAP/items/ECA_EXBA_MSI_COP_2A_20251013T131444Z_20251013T162407Z_07820E?httpAccept=application/vnd.iso.19139%2Bxml
type: application/vnd.iso.19139+xml
roles: ['metadata']
Asset key: enclosure_hdr
href: https://catalog.maap.eo.esa.int/data/earthcare-pdgs-01/EarthCARE/MSI_COP_2A/BA/2025/10/13/ECA_EXBA_MSI_COP_2A_20251013T131444Z_20251013T162407Z_07820E/ECA_EXBA_MSI_COP_2A_20251013T131444Z_20251013T162407Z_07820E/ECA_EXBA_MSI_COP_2A_20251013T131444Z_20251013T162407Z_07820E.HDR
type: image/vnd.radiance
roles: ['data']
Asset key: quicklook
href: https://catalog.maap.eo.esa.int/data/earthcare-pdgs-01/EarthCARE/MSI_COP_2A/BA/2025/10/13/ECA_EXBA_MSI_COP_2A_20251013T131444Z_20251013T162407Z_07820E/public/ECA_EXBA_MSI_COP_2A_20251013T131444Z_20251013T162407Z_07820E.BID_1.jpeg
type: image/jpeg
roles: ['overview']
Tips:
Want a quick look? Use the quicklook or thumbnail to preview the data.
Need to analyze? Work with the enclosure files as demonstrated in the scripts later on.
Don’t need everything? Avoid the .zip unless you really need to download all files.
Curious about metadata? Open the XML/JSON metadata files for detailed info.
Quicklook of the data#
You don’t need to authenticate or authorize to preview the data.
By referencing the thumbnail asset, you’re accessing a remote URL where a quicklook image of the product is stored. Note that not all products necessarily have a quicklook stored.
This provides a fast and convenient way to visually inspect the data before downloading or processing it.
ql_url = ec_product.assets['thumbnail'].href
display(Image(url= ql_url))

Token#
You can generate an offline access token that is valid for 90 days here. We recommend to save this personal offline token in a separate file and not paste it into your scripts. This offline access token in combination with a client ID and secret creates a refresh token which authenticates/authorizes you to access the data files. In simple terms, the offline token is like a temporary key that helps you securely log in without needing to re-enter your credentials every time.
# offline token link: https://portal.maap.eo.esa.int/ini/services/auth/token/90dToken.php
CLIENT_ID="offline-token"
CLIENT_SECRET="p1eL7uonXs6MDxtGbgKdPVRAmnGxHpVE"
# Save your personal offline token in a text file token_yourname.txt in the same directory as this script
if pathlib.Path("token_yourname.txt").exists():
with open("token_yourname.txt","rt") as f:
OFFLINE_TOKEN = f.read().strip().replace("\n","")
url = "https://iam.maap.eo.esa.int/realms/esa-maap/protocol/openid-connect/token"
data = {
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET,
"grant_type": "refresh_token",
"refresh_token": OFFLINE_TOKEN,
"scope": "offline_access openid"
}
response = requests.post(url, data=data)
response.raise_for_status()
response_json = response.json()
access_token = response_json.get('access_token')
print("Access token retrieved successfully.")
if not access_token:
raise RuntimeError("Failed to retrieve access token from IAM response")
Access token retrieved successfully.
Stream and plot data#
⚠️ NEW: The .h5 file is now stored under
enclosure_h5while the header file is stored in theenclosure_hdrasset.
# Fetching the url of the desired file
ds_url = ec_product.assets.get('enclosure_h5').href # Updated to enclosure_h5
print(f"Dataset URL: {ds_url}")
Dataset URL: https://catalog.maap.eo.esa.int/data/earthcare-pdgs-01/EarthCARE/MSI_COP_2A/BA/2025/10/13/ECA_EXBA_MSI_COP_2A_20251013T131444Z_20251013T162407Z_07820E/ECA_EXBA_MSI_COP_2A_20251013T131444Z_20251013T162407Z_07820E/ECA_EXBA_MSI_COP_2A_20251013T131444Z_20251013T162407Z_07820E.h5
This provides a faster way to access the NetCDF data in the cloud. It configures how the HDF5 (.h5) files are read and cached.
io_params = {
"fsspec_params": {
"cache_type": "blockcache",
"block_size": 8 * 1024 * 1024
},
"h5py_params": {
"driver_kwds": {
"rdcc_nbytes": 8 * 1024 * 1024
}
}
}
fs = fsspec.filesystem(
"https",
headers={"Authorization": f"Bearer {access_token}"},
**io_params["fsspec_params"] )
# Open the file and read it into an xarray Dataset
with fs.open(ds_url, "rb") as f:
ds = xr.open_dataset(f,
engine="h5netcdf",
**io_params["h5py_params"],
group="ScienceData")
# Do something with ds! Here we plot two variables as an example.
fig, axes = plt.subplots(1, 2, figsize=(14, 6))
# Plot Cloud Water Path
ds["cloud_water_path"].plot(ax=axes[0], cmap="Blues")
axes[0].set_title("Cloud Water Path")
# Plot Cloud Top Temperature
ds["cloud_top_temperature"].plot(ax=axes[1], cmap="plasma")
axes[1].set_title("Cloud Top Temperature")
plt.tight_layout()
plt.show()
Download data#
You can also use your token and the url to download data and not just stream it.
def download_file_with_bearer_token(url, token, disable_bar=False):
"""
Downloads a file from a given URL using a Bearer token.
"""
try:
headers = {"Authorization": f"Bearer {token}"}
response = requests.get(url, headers=headers, stream=True)
response.raise_for_status() # Raise an exception for bad status codes
file_size = int(response.headers.get('content-length', 0))
chunk_size = 8 * 1024 * 1024 # Byes - 1MiB
file_path = url.rsplit('/', 1)[-1]
print(file_path)
with open(file_path, "wb") as f, tqdm(
desc=file_path,
total=file_size,
unit='iB',
unit_scale=True,
unit_divisor=1024,
disable=disable_bar,
) as bar:
for chunk in response.iter_content(chunk_size=chunk_size):
read_size=f.write(chunk)
bar.update(read_size)
if (disable_bar):
print(f"File downloaded successfully to {file_path}")
except requests.exceptions.RequestException as e:
print(f"Error downloading file: {e}")
import requests
download_file_with_bearer_token(ds_url, access_token)
ECA_EXBA_MSI_COP_2A_20251013T131444Z_20251013T162407Z_07820E.h5
ECA_EXBA_MSI_COP_2A_20251013T131444Z_20251013T162407Z_07820E.h5: 100%|██████████| 131M/131M [00:38<00:00, 3.57MiB/s]