How to use the Compatibility API¶
The /compatibility endpoint helps you understand how to call TiTiler-CMR for a collection. It returns the sampled granule_ur and accepts granule_ur when you want to inspect a specific granule. 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": {},
"compatible_groups": [
"science/LSAR/GCOV/grids/frequencyA",
"science/LSAR/GCOV/grids/frequencyB"
],
"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": []
}
Interpret the response¶
For hierarchical datasets, a root /compatibility request stays lightweight. The most important fields are:
granule_ur: the sampled granule used for this compatibility checkcompatible_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: - science/LSAR/GCOV/grids/frequencyA - science/LSAR/GCOV/grids/frequencyB
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))
{
"concept_id": "C3622214170-ASF",
"backend": "xarray",
"datetime": [
{
"RangeDateTimes": [
{
"BeginningDateTime": "2025-10-01T00:00:00.000Z"
}
],
"EndsAtPresentFlag": true
}
],
"variables": {
"HHHH": {
"shape": [
4590,
4635
],
"dtype": "float32",
"min": 1.9753079380513405e-15,
"max": 126.9072265625,
"mean": 0.2488117665052414,
"p01": 5.214990765611826e-15,
"p05": 1.1158001606004219e-14,
"p95": 0.572845458984375,
"p99": 1.0888000488281195
},
"HVHV": {
"shape": [
4590,
4635
],
"dtype": "float32",
"min": 3.3623819874206706e-16,
"max": 1.6359405517578125,
"mean": 0.05236886069178581,
"p01": 9.670644276690842e-16,
"p05": 2.27081808218399e-15,
"p95": 0.13129768371582023,
"p99": 0.24061668395996075
},
"listOfCovarianceTerms": {
"shape": [
2
],
"dtype": "|S4",
"min": null,
"max": null,
"mean": null,
"p01": null,
"p05": null,
"p95": null,
"p99": null
},
"listOfPolarizations": {
"shape": [
2
],
"dtype": "|S2",
"min": null,
"max": null,
"mean": null,
"p01": null,
"p05": null,
"p95": null,
"p99": null
},
"mask": {
"shape": [
4590,
4635
],
"dtype": "float32",
"min": 0.0,
"max": 3.0,
"mean": 1.6180167198181152,
"p01": 0.0,
"p05": 0.0,
"p95": 3.0,
"p99": 3.0
},
"numberOfLooks": {
"shape": [
4590,
4635
],
"dtype": "float32",
"min": 0.036182284355163574,
"max": 68.21331024169922,
"mean": 36.98814010620117,
"p01": 20.3447624206543,
"p05": 27.77091426849365,
"p95": 45.24116630554199,
"p99": 50.53271461486816
},
"numberOfSubSwaths": {
"shape": [],
"dtype": "uint8",
"min": 3.0,
"max": 3.0,
"mean": 3.0,
"p01": 3.0,
"p05": 3.0,
"p95": 3.0,
"p99": 3.0
},
"rtcGammaToSigmaFactor": {
"shape": [
4590,
4635
],
"dtype": "float32",
"min": 0.2671063244342804,
"max": 0.9898551106452942,
"mean": 0.7490795254707336,
"p01": 0.5234366035461426,
"p05": 0.6213086247444153,
"p95": 0.8584897398948669,
"p99": 0.9072614645957946
},
"xCoordinateSpacing": {
"shape": [],
"dtype": "float64",
"min": 80.0,
"max": 80.0,
"mean": 80.0,
"p01": 80.0,
"p05": 80.0,
"p95": 80.0,
"p99": 80.0
},
"yCoordinateSpacing": {
"shape": [],
"dtype": "float64",
"min": -80.0,
"max": -80.0,
"mean": -80.0,
"p01": -80.0,
"p05": -80.0,
"p95": -80.0,
"p99": -80.0
}
},
"dimensions": {
"yCoordinates": 4590,
"xCoordinates": 4635,
"phony_dim_5": 2
},
"coordinates": {
"projection": {
"size": 1,
"dtype": "uint32",
"min": 32633.0,
"max": 32633.0
},
"xCoordinates": {
"size": 4635,
"dtype": "float64",
"min": 148360.0,
"max": 519080.0
},
"yCoordinates": {
"size": 4590,
"dtype": "float64",
"min": 5392840.0,
"max": 5759960.0
}
},
"compatible_groups": null,
"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/xarray/WebMercatorQuad/tilejson.json?collection_concept_id=C3622214170-ASF&variables=HHHH&group=science/LSAR/GCOV/grids/frequencyB&temporal={temporal}",
"title": "TileJSON",
"type": "application/json"
},
{
"rel": "map",
"href": "https://openveda.cloud/api/titiler-cmr/xarray/WebMercatorQuad/map.html?collection_concept_id=C3622214170-ASF&variables=HHHH&group=science/LSAR/GCOV/grids/frequencyB&temporal={temporal}",
"title": "Map viewer",
"type": "text/html"
},
{
"rel": "tile",
"href": "https://openveda.cloud/api/titiler-cmr/xarray/tiles/WebMercatorQuad/{z}/{x}/{y}?collection_concept_id=C3622214170-ASF&variables=HHHH&group=science/LSAR/GCOV/grids/frequencyB&temporal={temporal}",
"title": "Map tile",
"type": "image/png"
}
]
}
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)
selected group: science/LSAR/GCOV/grids/frequencyB
variables in selected group (first 10): ['HHHH', 'HVHV', 'listOfCovarianceTerms', 'listOfPolarizations', 'mask', 'numberOfLooks', 'numberOfSubSwaths', 'rtcGammaToSigmaFactor', 'xCoordinateSpacing', 'yCoordinateSpacing']
tilejson link for selected group: https://openveda.cloud/api/titiler-cmr/xarray/WebMercatorQuad/tilejson.json?collection_concept_id=C3622214170-ASF&variables=HHHH&group=science/LSAR/GCOV/grids/frequencyB&temporal={temporal}
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.