How to use the Compatibility API¶
The /compatibility endpoint helps you understand how to call TiTiler-CMR for a collection. For hierarchical HDF5 and NetCDF datasets it can return a lightweight list of candidate group paths from the root request, then let you inspect variables by making a follow-up request with group=....
This notebook demonstrates that workflow for the NISAR Beta Geocoded Polarimetric Covariance (GCOV) collection, which is a known example of a hierarchical HDF5 dataset that needs a group parameter for xarray requests.
Setup¶
import json
import os
import earthaccess
import httpx2 as httpx
titiler_endpoint = os.getenv(
"TITILER_CMR_ENDPOINT", "https://staging.openveda.cloud/api/titiler-cmr"
)
Identify the dataset¶
You can find the collection with earthaccess.search_datasets.
datasets = earthaccess.search_datasets(concept_id="C3622214170-ASF")
ds = datasets[0]
collection_concept_id = ds["meta"]["concept-id"]
print("CollectionConcept-Id:", collection_concept_id)
print("Short name:", ds["umm"]["ShortName"])
print("Version:", ds["umm"]["Version"])
CollectionConcept-Id: C3622214170-ASF Short name: NISAR_L2_GCOV_BETA_V1 Version: 1
Explore the collection using /compatibility¶
compatibility_response = httpx.get(
f"{titiler_endpoint}/compatibility",
params={"collection_concept_id": collection_concept_id},
timeout=None,
).json()
print(json.dumps(compatibility_response, indent=2))
{
"concept_id": "C3622214170-ASF",
"backend": "xarray",
"datetime": [
{
"RangeDateTimes": [
{
"BeginningDateTime": "2025-10-01T00:00:00.000Z"
}
],
"EndsAtPresentFlag": true
}
],
"variables": {},
"dimensions": {},
"coordinates": {},
"example_assets": "s3://sds-n-cumulus-prod-nisar-products/NISAR_L2_GCOV_BETA_V1/NISAR_L2_PR_GCOV_002_109_D_063_4005_DHDH_A_20251012T182508_20251012T182531_X05010_N_P_J_001/NISAR_L2_PR_GCOV_002_109_D_063_4005_DHDH_A_20251012T182508_20251012T182531_X05010_N_P_J_001.h5",
"sample_asset_raster_info": null,
"links": [
{
"rel": "tilejson",
"href": "https://openveda.cloud/api/titiler-cmr/rasterio/WebMercatorQuad/tilejson.json?collection_concept_id=C3622214170-ASF&temporal={temporal}",
"title": "TileJSON",
"type": "application/json"
},
{
"rel": "map",
"href": "https://openveda.cloud/api/titiler-cmr/rasterio/WebMercatorQuad/map.html?collection_concept_id=C3622214170-ASF&temporal={temporal}",
"title": "Map viewer",
"type": "text/html"
},
{
"rel": "tile",
"href": "https://openveda.cloud/api/titiler-cmr/rasterio/tiles/WebMercatorQuad/{z}/{x}/{y}?collection_concept_id=C3622214170-ASF&temporal={temporal}",
"title": "Map tile",
"type": "image/png"
}
]
}
Interpret the response¶
For hierarchical datasets, a root /compatibility request stays lightweight. The most important field is:
compatible_groups: candidate group paths to try in a follow-up request
At this stage the response may not include variable metadata or xarray links yet, because TiTiler-CMR has not inspected a nested group.
compatible_groups = compatibility_response.get("compatible_groups", [])
variables = list((compatibility_response.get("variables") or {}).keys())
tilejson_link = next(
(
link["href"]
for link in compatibility_response.get("links", [])
if link["rel"] == "tilejson"
),
None,
)
print("compatible_groups:")
for group in compatible_groups:
print(" -", group)
compatible_groups:
Inspect a specific group¶
Once you choose a group from compatible_groups, make a follow-up /compatibility request with group=... to inspect variables and get xarray links.
selected_group = compatible_groups[1]
grouped_compatibility_response = httpx.get(
f"{titiler_endpoint}/compatibility",
params={
"collection_concept_id": collection_concept_id,
"group": selected_group,
},
timeout=30,
).json()
print(json.dumps(grouped_compatibility_response, indent=2))
--------------------------------------------------------------------------- IndexError Traceback (most recent call last) Cell In[5], line 1 ----> 1 selected_group = compatible_groups[1] 3 grouped_compatibility_response = httpx.get( 4 f"{titiler_endpoint}/compatibility", 5 params={ (...) 9 timeout=30, 10 ).json() 12 print(json.dumps(grouped_compatibility_response, indent=2)) IndexError: list index out of range
group_variables = list((grouped_compatibility_response.get("variables") or {}).keys())
group_tilejson_link = next(
link["href"]
for link in grouped_compatibility_response.get("links", [])
if link["rel"] == "tilejson"
)
print("selected group:", selected_group)
print("variables in selected group (first 10):", group_variables[:10])
print("tilejson link for selected group:", group_tilejson_link)
--------------------------------------------------------------------------- NameError Traceback (most recent call last) Cell In[6], line 1 ----> 1 group_variables = list((grouped_compatibility_response.get("variables") or {}).keys()) 2 group_tilejson_link = next( 3 link["href"] 4 for link in grouped_compatibility_response.get("links", []) 5 if link["rel"] == "tilejson" 6 ) 8 print("selected group:", selected_group) NameError: name 'grouped_compatibility_response' is not defined
For a grouped dataset like NISAR GCOV, the workflow is:
- Call
/compatibilitywithoutgroupto get candidatecompatible_groups. - Choose one of those group paths.
- Call
/compatibilityagain withgroup=...to inspect variables and dimensions for that group. - Pick a variable name from
variables. - Reuse the returned xarray links from the grouped response.
That keeps the root compatibility response lightweight while still giving you a practical path to the next xarray request.