Sentinel Hub — usage#
The request shape#
A Sentinel Hub request is variables={collection_or_recipe: [band, ...]} plus a
bbox (lat_lim / lon_lim) and a date window (start / end). A variables
key is either:
- an evalscript recipe (e.g.
"sentinel-2-l2a-ndvi") — a bundled.jsthat pins its collection and render logic; the band list may be empty, or - a collection (e.g.
"sentinel-2-l2a") — then you must pass an explicitevalscript=(an inline V3 JS string or a.jsfile path).
See the collections & recipes reference for the full bundled library.
from earthlens import EarthLens
el = EarthLens(
data_source="sentinel-hub",
start="2020-06-10", end="2020-06-20",
variables={"sentinel-2-l2a-ndvi": []},
lat_lim=[40.80, 40.83], lon_lim=[14.24, 14.27],
path="out", resolution=20,
)
paths = el.download() # -> [Path('out/.../response.tiff')]
Keyword arguments#
| Keyword | Default | Meaning |
|---|---|---|
resolution |
10.0 |
Output pixel size in metres (drives bbox_to_dimensions). |
evalscript |
None |
A custom evalscript — inline V3 JS string or a .js path — that bypasses the recipe lookup. |
endpoint |
"cdse" |
"cdse" / "commercial" / a full base URL. |
mosaicking_order |
"mostRecent" |
Per-pixel scene selection: "mostRecent" / "leastRecent" / "leastCC". |
api |
None |
The request plane (see below); None auto-selects. |
geometry |
None |
A shapely geometry / GeoJSON mapping / FeatureCollection for the Statistical planes. |
maxcc |
None |
Maximum cloud cover (0–1), forwarded to input_data (optical only). |
batch_output |
None |
S3 delivery spec for the async / batch planes (see below). |
client_id / client_secret / profile |
None |
Credentials (see Authentication). |
download() returns the written GeoTIFF paths (raster planes), the table
paths (statistical planes), or the S3 destination URIs (async / batch).
The request planes (api=) and size auto-routing#
api= |
Output | Notes |
|---|---|---|
"process" |
GeoTIFF | Synchronous, ≤ 2500 px/side. |
"async" |
S3 URIs | ≤ 10000 px/side; needs batch_output. |
"tiling" |
GeoTIFF | Split into ≤ 2500 px tiles + mosaic; no S3. |
"batch" |
S3 URIs | Server-side tiling to S3; needs batch_output. |
"statistical" |
CSV | Zonal stats; needs geometry=. |
"batch-statistical" |
CSV | Zonal stats over a huge FeatureCollection via S3. |
When api= is omitted, the backend computes the render size from the bbox +
resolution and routes:
geometry= supplied -> statistical
size ≤ 2500 px -> process
size > 2500 px, no batch_output -> tiling (local split + mosaic)
size 2500–10000 px, batch_output -> async (S3)
size > 10000 px, batch_output -> batch (S3)
An explicit api= is honoured verbatim; forcing api="process" on an oversized
request raises a clear error rather than silently truncating.
Async is S3-delivered
Sentinel Hub's Async Processing API delivers to S3 (it is not a direct
synchronous download). The no-S3 path for medium/large AOIs is therefore
"tiling" — local split into Process tiles, mosaicked with
pyramids.dataset.merge.merge_rasters.
A custom evalscript#
NDVI = """//VERSION=3
function setup() { return { input: ["B04","B08"], output: { bands: 1, sampleType: "FLOAT32" } }; }
function evaluatePixel(s) { return [(s.B08 - s.B04) / (s.B08 + s.B04)]; }
"""
el = EarthLens(
data_source="sentinel-hub",
start="2020-06-10", end="2020-06-20",
variables={"sentinel-2-l2a": []}, # a plain collection
lat_lim=[40.80, 40.83], lon_lim=[14.24, 14.27],
path="out", resolution=20,
evalscript=NDVI, # inline JS (or a path to a .js file)
)
aggregate= — windowed reduction#
download(aggregate=AggregationConfig(freq=..., op=...)) is accepted on every
plane (the backend is OUTPUT_KIND="mixed", so the facade forwards it):
- raster planes loop one render per
freqwindow, writing one per-window GeoTIFF named{key}_{freq}_{YYYYMMDD}.tif(theecmwf/cmemsshape); - the statistical plane maps
freqto the Statisticalaggregation_interval(the server returns one stats row per interval).
from earthlens.aggregate import AggregationConfig
el.download(aggregate=AggregationConfig(freq="1MS", op="mean")) # monthly windows
Browsing coverage with the Catalog API#
backend.search() queries the Sentinel Hub Catalog API for the scenes
intersecting the request bbox + window, without rendering:
el = EarthLens(data_source="sentinel-hub", ...)
products = el.datasource.search(limit=50)
for p in products:
print(p.id, p.metadata["datetime"])
Rate limits & quotas#
Sentinel Hub enforces per-account processing-unit quotas. sentinelhub-py
retries throttled requests automatically (its default_retry_time is 30 s in
3.11.x). Keep AOIs and windows tight, prefer the Statistical plane for
zonal questions (it is far cheaper than rendering), and use Batch for
continental work.