Working with Sentinel-2 Imagery

Learn how to search for, analyze, and retrieve Sentinel-2 satellite imagery for your areas of interest.

Prerequisites: Before starting this tutorial, make sure you have:
  • An ObservEarth API key
  • Created at least one Area of Interest (AOI)
If you haven't done these steps yet, check out our Authentication and Areas of Interest tutorials first.

Introduction to Sentinel-2

Sentinel-2 is a constellation of satellites operated by the European Space Agency (ESA) that provides high-resolution optical imagery. Key features include:

  • Spatial resolution: 10m, 20m, and 60m (depending on the band)
  • Temporal resolution: 5-day revisit time (with two satellites)
  • Spectral resolution: 13 bands from visible to shortwave infrared
  • Coverage: Global land and coastal areas

Sentinel-2 imagery is particularly useful for:

  • Vegetation monitoring
  • Land cover classification
  • Agricultural applications
  • Forest management
  • Water resource monitoring

Searching for Sentinel-2 Imagery

Search for Available Imagery

The first step in working with Sentinel-2 imagery is to search for available images that cover your area of interest within a specific date range.

API Type
POST
Endpoint
https://observearth.com/api/s2/search/
Request Parameters
Parameter Type Required Description
geometry_id UUID Yes UUID of your Area of Interest
start_date string Yes Start date in YYYY-MM-DD format
end_date string Yes End date in YYYY-MM-DD format
cloud_cover number No Maximum cloud cover percentage (0-100), default 20
Code Example
import requests
import json

api_key = "your_api_key_here"
url = "https://observearth.com/api/s2/search/"

payload = {
    "geometry_id": "123e4567-e89b-12d3-a456-426614174000",
    "start_date": "2023-01-01",
    "end_date": "2023-01-31",
    "cloud_cover": 10
}

headers = {
    "X-API-Key": api_key,
    "Content-Type": "application/json"
}

response = requests.post(url, headers=headers, data=json.dumps(payload))
data = response.json()

for image in data['results']:
    print(f"ID: {image['id']}, Date: {image['date']}, Cloud Cover: {image['cloud_cover']}%")

Getting Image Statistics

Calculate Statistics for Imagery

Once you've found available images, you can calculate statistics for vegetation indices over your area of interest.

API Type
POST
Endpoint
https://observearth.com/api/s2/stats/
Request Parameters
Parameter Type Required Description
geometry_id UUID Yes UUID of your Area of Interest
start_date string Yes Start date in YYYY-MM-DD format
end_date string Yes End date in YYYY-MM-DD format
cloud_cover number No Maximum cloud cover percentage (0-100), default 20
index string No Vegetation index to analyze (ndvi, evi, lai, ndmi, ndwi)
Code Example
import requests
import json

api_key = "your_api_key_here"
url = "https://observearth.com/api/s2/stats/"

payload = {
    "geometry_id": "123e4567-e89b-12d3-a456-426614174000",
    "start_date": "2023-01-01",
    "end_date": "2023-01-31",
    "cloud_cover": 10,
    "index": "ndvi"
}

headers = {
    "X-API-Key": api_key,
    "Content-Type": "application/json"
}

response = requests.post(url, headers=headers, data=json.dumps(payload))
data = response.json()


for result in data:
    print(f"Date: {result['date']}, Mean NDVI: {result['mean']:.2f}")

Retrieving Imagery

Get Imagery for Visualization

Once you've identified the images you want, you can retrieve them for visualization or analysis.

API Type
GET
Endpoint
https://observearth.com/api/s2/image/{geometry_id}/
Path Parameters
Parameter Type Description
geometry_id UUID UUID of your Area of Interest
Query Parameters
Parameter Type Required Description
item_id string Yes ID of the Sentinel-2 image
image_type string Yes Image format (png, tiff)
index string Yes Vegetation index (ndvi, evi, lai, ndmi, ndwi)
Code Example
import requests
import os

api_key = "your_api_key_here"
geometry_id = "123e4567-e89b-12d3-a456-426614174000"
item_id = "S2A_MSIL2A_20230105T123456_N0509_R123_T18TXM_20230105T150000"

url = f"https://observearth.com/api/s2/image/{geometry_id}/"

params = {
    "item_id": item_id,
    "image_type": "png",
    "index": "ndvi"
}

headers = {
    "X-API-Key": api_key
}

response = requests.get(url, headers=headers, params=params)

if response.status_code == 200:
    # Save the image
    with open("ndvi_image.png", "wb") as f:
        f.write(response.content)
    print("Image saved as ndvi_image.png")
else:
    print(f"Error: {response.status_code}")
    print(response.text)

Get Raw Imagery

You can also retrieve raw Sentinel-2 imagery without any processing or index calculation.

API Type
GET
Endpoint
https://observearth.com/api/s2/raw/{geometry_id}/
Path Parameters
Parameter Type Description
geometry_id UUID UUID of your Area of Interest
Query Parameters
Parameter Type Required Description
item_id string Yes ID of the Sentinel-2 image
bands string Yes Comma-separated list of bands (e.g., "B04,B08,B02" for RGB)
image_type string Yes Image format (png, tiff)
Code Example
import requests
import os

api_key = "your_api_key_here"
geometry_id = "123e4567-e89b-12d3-a456-426614174000"
item_id = "S2A_MSIL2A_20230105T123456_N0509_R123_T18TXM_20230105T150000"

url = f"https://observearth.com/api/s2/raw/{geometry_id}/"

params = {
    "item_id": item_id,
    "bands": "B04,B03,B02",  # RGB natural color
    "image_type": "png"
}

headers = {
    "X-API-Key": api_key
}

response = requests.get(url, headers=headers, params=params)

if response.status_code == 200:
    # Save the image
    with open("rgb_image.png", "wb") as f:
        f.write(response.content)
    print("Image saved as rgb_image.png")
else:
    print(f"Error: {response.status_code}")
    print(response.text)

Common Vegetation Indices

Sentinel-2 imagery can be used to calculate various vegetation indices. Here are the most common ones:

Index Name Formula Description Value Range
ndvi NDVI (B8 - B4) / (B8 + B4) Normalized Difference Vegetation Index -1 to 1
evi EVI 2.5 * ((B8 - B4) / (B8 + 6 * B4 - 7.5 * B2 + 1)) Enhanced Vegetation Index -1 to 1
ndmi NDMI (B8 - B11) / (B8 + B11) Normalized Difference Moisture Index -1 to 1
ndwi NDWI (B3 - B8) / (B3 + B8) Normalized Difference Water Index -1 to 1
lai LAI 3.618 * EVI Leaf Area Index 0 to 7
savi SAVI ((B8 - B4) / (B8 + B4 + 0.5)) * 1.5 Soil Adjusted Vegetation Index -1 to 1
msavi MSAVI (2 * B8 + 1 - sqrt((2 * B8 + 1)² - 8 * (B8 - B4))) / 2 Modified Soil Adjusted Vegetation Index -1 to 1
ndre NDRE (B8 - B5) / (B8 + B5) Normalized Difference Red Edge -1 to 1
gndvi GNDVI (B8 - B3) / (B8 + B3) Green Normalized Difference Vegetation Index -1 to 1
nbr NBR (B8 - B12) / (B8 + B12) Normalized Burn Ratio -1 to 1
ndbi NDBI (B11 - B8) / (B11 + B8) Normalized Difference Built-up Index -1 to 1
bsi BSI ((B11 + B4) - (B8 + B2)) / ((B11 + B4) + (B8 + B2)) Bare Soil Index -1 to 1
chl_rededge CHL RedEdge B7 / B5 Chlorophyll Red Edge 0 to 30
ccci CCCI ((B8 - B5) / (B8 + B5)) / ((B8 - B4) / (B8 + B4)) Canopy Chlorophyll Content Index 0 to 3

Next Steps