# Data Access
Learn how to access data and optimise your workflows.
## Environment setup
**Pure open standards. Zero vendor lock-in.**
Earth Data Hub is built entirely on open standards. Our datasets are cloud-optimised Zarr stores, meaning you can stream them directly over HTTP using any language or library you already know.
While you can use any language, we recommend **Python combined with [Xarray](https://docs.xarray.dev/en/stable/)** for the best experience.
Install the required packages for this quick start by running this command in your terminal:
### pip
```bash
pip install xarray "zarr>3" dask aiohttp
```
### uv
```bash
uv add xarray "zarr>3" dask aiohttp
```
### conda
```bash
conda install -c conda-forge xarray "zarr>3" dask aiohttp
```
## Try a public dataset
Let’s verify your environment. We have provided a **public test dataset** that you can access instantly, with **no accounts or passwords required**. It is the perfect place to test your setup before exploring the wider catalogue.
Run the following in your Python console:
```pycon
>>> import xarray as xr
>>> xr.open_dataset(
... "https://data.earthdatahub.destine.eu/public/test-dataset-v1.zarr",
... chunks={}, # Tells Xarray to load data on-demand
... engine="zarr",
... )
Size: 4GB
Dimensions: (latitude: 720, longitude: 1440,
age_band_lower_bound: 14, year: 71)
Coordinates:
* latitude (latitude) float64 6kB 90.0 89.75 ... -89.5 -89.75
* longitude (longitude) float64 12kB 0.0 0.25 0.5 ... 359.5 359.8
* age_band_lower_bound (age_band_lower_bound) int64 112B 0 5 10 ... 55 60 65
* year (year) int64 568B 1950 1951 1952 ... 2018 2019 2020
Data variables:
demographic_totals (latitude, longitude, age_band_lower_bound, year) float32 4GB dask.array
```
And just like that, you are connected! The output above shows an Xarray `Dataset` representing the data you are accessing. To access the rest of our catalogue, you will need to **set up authentication**.
## Set up your API key
To access our full suite of datasets, you will need a free **API Key**.
1. **Register an account** on the [DestinE Platform](https://earthdatahub.destine.eu/login?came_from=https%3A//earthdatahub.destine.eu/docs/data-access.html).
2. Visit the [API keys management section](https://earthdatahub.destine.eu/quota-api-keys#my-personal-access-tokens).
3. **Copy your default API key** (or generate a new one).
**Climate DT requires upgraded access.**
Some datasets, including the **Destination Earth Climate Adaptation Digital Twin (Climate DT)** collection, require additional permissions. See [Upgraded access](#upgraded-access).
## Access protected datasets
Most datasets in the Earth Data Hub catalogue require your API key. Here are two ways to configure authentication:
### Option 1: Key in the URL
The quickest way to test protected data is to include your API key directly as the password in the dataset URL:
```python
import xarray as xr
# Replace with your actual key
xr.open_dataset(
"https://edh:@data.earthdatahub.destine.eu/private/test-dataset-v1.zarr",
chunks={},
engine="zarr",
)
```
### Option 2: Using .netrc (Recommended)
For everyday use, we recommend **storing your API key in a hidden `.netrc` file**. This allows your Python scripts to authenticate automatically in the background without exposing your keys.
If you don’t have it already, **create a file** in your home directory:
- **macOS/Linux:** `~/.netrc`
- **Windows:** `C:\Users\\_netrc`
Then, **add the following lines** to the `.netrc` file:
```text
machine data.earthdatahub.destine.eu
password
machine api.earthdatahub.destine.eu
password
```
#### NOTE
Earth Data Hub uses multiple endpoints, so your `.netrc` file needs an entry for each one. You can retrieve your `.netrc` file directly from your [EDH account settings](https://earthdatahub.destine.eu/quota-api-keys#my-personal-access-tokens) using the “Show how to use this API key” button.
Now, you can load protected datasets cleanly by enabling environment trust (`trust_env=True`):
```python
import xarray as xr
xr.open_dataset(
"https://data.earthdatahub.destine.eu/private/test-dataset-v1.zarr",
storage_options={"client_kwargs": {"trust_env": True}}, # Auto-detect your .netrc
chunks={},
engine="zarr",
)
```
**Set it up once, use it everywhere.**
Direct authentication is fine for a quick test, but using a `.netrc` file is the recommended approach. It keeps your API key out of your code, helps prevent accidental commits, and makes your scripts easier to share.
## Upgraded access
Some datasets, including the Destination Earth Climate Adaptation Digital Twin ([Climate DT](https://earthdatahub.destine.eu/collections/climate-dt-2)) collection, require upgraded access. You can easily recognise these datasets in the catalogue by their Restricted badge.
For example, if you try to access a Climate DT dataset without the required permissions, your request will fail with `HTTP 403 Forbidden`.
Visit the [**Destination Earth User Access Upgrade**](https://platform.destine.eu/access-policy-upgrade/) page to check your eligibility and learn how to apply for upgraded access.
## Quotas
Earth Data Hub datasets are divided into small blocks of data called **chunks**, so you only retrieve the parts of the data you need. To learn more about how chunks are organised, see [Chunking schemes](https://earthdatahub.destine.eu/docs/core-concepts.md#chunking-schemes).
When you stream data on demand, each chunk is retrieved through an HTTP request behind the scenes. To keep the service fair and reliable for everyone, each user has a **monthly quota of 500,000 requests**.
That may sound like a lot, and for most workflows, it is. But if you need to access large amounts of data, the key is to **stream only the data you need** and avoid downloading the same chunks repeatedly. To reduce unnecessary requests, see [Cache data locally](#cache-data-locally).
#### NOTE
Your quota resets at midnight on the **first day of each month**. You can [check your quota usage](https://earthdatahub.destine.eu/quota-api-keys#quota) at any time.
## Cache data locally
Accessing the same dataset multiple times? **Local caching** makes repeated reads much faster and avoids downloading the same chunks again, saving both time and quota.
Before running the example, replace **`URL`** with your dataset URL and **`CACHE_STORAGE`** with your preferred cache directory.
```python
import xarray as xr
# Replace with the Earth Data Hub dataset URL you'd like to access
URL = "https://data.earthdatahub.destine.eu/private/test-dataset-v1.zarr"
# Replace with the local directory you'd like to use for caching
CACHE_STORAGE = "./edh_cache/"
ds = xr.open_dataset(
f"asyncwrapper::simplecache::{URL}",
storage_options={
"https": {"client_kwargs": {"trust_env": True}},
"simplecache": {"cache_storage": CACHE_STORAGE},
"asyncwrapper": {"asynchronous": True},
},
chunks={},
engine="zarr",
)
```
Behind the scenes, caching is handled by the **fsspec** library. The `simplecache` backend is a great default for most workflows, while other caching backends provide additional features such as customisable cache expiration and size limits.
To learn more about available caching options, see the [fsspec documentation](https://filesystem-spec.readthedocs.io/en/latest/features.html#caching-files-locally).
## API reference
Under the hood, Earth Data Hub is just two open interfaces: a **STAC catalogue** to find data, and **Zarr over HTTPS** to read it. No SDK required. If your tool can make a web request, it can use Earth Data Hub.
### STAC catalogue
[STAC](https://stacspec.org/) (SpatioTemporal Asset Catalog) is a standard, searchable catalogue of Earth data. Every collection and dataset you see in the Earth Data Hub catalogue is also available as STAC metadata, starting from a single root URL: https://earthdatahub.destine.eu/api/stac/v1
**One URL to discover everything.**
The STAC catalogue is **public**: browsing it requires no API key. You only need your key when you read the data itself.
Explore the catalogue straight from your terminal:
```bash
# Root catalogue
curl https://earthdatahub.destine.eu/api/stac/v1/
# All collections (e.g. era5, cmip6, climate-dt-2)
curl https://earthdatahub.destine.eu/api/stac/v1/collections
# All datasets in a collection
curl https://earthdatahub.destine.eu/api/stac/v1/collections/era5/items
# Search across the catalogue
curl "https://earthdatahub.destine.eu/api/stac/v1/search?collections=era5&limit=5"
```
For the full list of endpoints and query parameters, see the [interactive STAC API documentation](https://earthdatahub.destine.eu/api/stac/v1/api.html).
In STAC, each dataset is an **item**. Its `data` asset holds the **dataset URL**, along with the exact arguments needed to open it with Xarray:
```json
"assets": {
"data": {
"href": "https://data.earthdatahub.destine.eu/era5/era5-land-monthly-v0.zarr",
"roles": ["data"],
"xarray:open_kwargs": {"chunks": {}, "engine": "zarr"},
"xarray:storage_options": {"client_kwargs": {"trust_env": true}}
}
}
```
#### From catalogue to dataset in Python
Install [pystac-client](https://pystac-client.readthedocs.io/) alongside the packages from [Environment setup](#environment-setup):
### pip
```bash
pip install pystac-client xarray "zarr>3" dask aiohttp
```
### uv
```bash
uv add pystac-client xarray "zarr>3" dask aiohttp
```
### conda
```bash
conda install -c conda-forge pystac-client xarray "zarr>3" dask aiohttp
```
Then find a dataset in the catalogue and open it, with no URLs to copy and paste. This example uses your `.netrc` file, see [Access protected datasets](#protected-datasets):
```python
import pystac_client
import xarray as xr
catalog = pystac_client.Client.open("https://earthdatahub.destine.eu/api/stac/v1")
item = catalog.get_collection("era5").get_item("era5-land")
asset = item.assets["data"]
xr.open_dataset(
asset.href,
storage_options=asset.extra_fields.get("xarray:storage_options"),
**asset.extra_fields.get("xarray:open_kwargs", {}),
)
```
### Zarr over HTTPS
A Zarr dataset is simply a **folder of small files** on the web: a few JSON files describing the data, plus the data itself split into chunks. Each of those files has its own URL, so a plain HTTPS request is all it takes to read one.
Try it with the public test dataset:
```bash
# Dataset metadata: variables, dimensions and attributes
curl https://data.earthdatahub.destine.eu/public/test-dataset-v1.zarr/zarr.json
# Variable metadata: shape, chunk shape, data type and compression
curl https://data.earthdatahub.destine.eu/public/test-dataset-v1.zarr/demographic_totals/zarr.json
# A single chunk of raw data
curl -o chunk.bin https://data.earthdatahub.destine.eu/public/test-dataset-v1.zarr/year/c/0
```
File names follow the standard [Zarr conventions](https://zarr-specs.readthedocs.io/en/latest/v3/core/index.html). To learn more about how chunks are organised, see [Chunking schemes](https://earthdatahub.destine.eu/docs/core-concepts.md#chunking-schemes).
For protected datasets, add your API key to the request:
```bash
# Using your API key directly
curl -u edh: https://data.earthdatahub.destine.eu/private/test-dataset-v1.zarr/zarr.json
# Using your API key (with bearer auth)
curl https://data.earthdatahub.destine.eu/private/test-dataset-v1.zarr/zarr.json -H "Authorization: Bearer "
# Using your .netrc file
curl --netrc https://data.earthdatahub.destine.eu/private/test-dataset-v1.zarr/zarr.json
```
#### NOTE
Every request counts towards your monthly quota, whichever tool you use. See [Quotas](#quotas).