Skip to content

Search for an AOI

This guide demonstrates how to search Aleph's Archive Service using a known AOI (Area of Interest) and retrieve associated imagery and metadata using the STAC API.

The following Python example connects to the STAC-compliant Archive API, performs an AOI-based search, prints metadata, and downloads available preview images.

You must have a valid Bearer token and a Contract ID. If you're unsure how to authenticate, refer to ourAuthentication Getting Started guide.

Configuration and imports

Requirements for this demo:

To start, include the packages that we are going to need:

from pystac_client import Client
import requests
import os, json
from datetime import datetime, timedelta
from pystac_client.stac_api_io import StacApiIO
from pystac_client.exceptions import APIError

Replace with your actual credentials

token = "YOUR_BEARER_TOKEN"
contract_id = "YOUR_CONTRACT_ID"

Connect to the Archive API

Then, let's create a connection to the archive API.

STAC_API_URL = "https://api.satellogic.com/archive/stac/"


headers = {
    "authorizationToken": f"Bearer {token}",
    "X-Satellogic-Contract-Id": contract_id,
    "Content-Type": "application/json",
}


client = Client.open(STAC_API_URL, headers=headers)

Define the Area of Interest (AOI)

Now, we are going define the AOI as a GeoJson polygon. This can be done in the code directly like this:

aoi = {
    "coordinates": [
      [
        [2.1147711862296035, 41.38373806805163],
        [2.1147711862296035, 41.37709414091424],
        [2.130796005839642, 41.37709414091424],
        [2.130796005839642, 41.38373806805163],
        [2.1147711862296035, 41.38373806805163]
      ]
    ],
    "type": "Polygon"
}

Or we can directly import a GeoJson file into memory as follows:

with open("ancilliary_files/AOI.geojson") as fp:
    aoi = json.loads(fp.read())["geometry"] 

To perform the search, specify your date range and desired collection. You can find available collections here.

items = client.search(    
    intersects = aoi,
    collections=["quickview-visual"],
    datetime="2024-07-01/2024-08-01",        
  ).item_collection() 

for i, item in enumerate(items):
    print(i)
    asset = item.assets.get("preview")
    if asset:
        asset_href = asset.href
        print(f"Downloading {asset_href}...")
        response = requests.get(asset_href, headers=headers)
        filename = f"storage/preview_{i}.png"
        with open(filename, "wb") as f:
            f.write(response.content)
        print(f"Saved to {filename}")
    else:
        print(f"No 'analytic' asset found for item {item.id}")

Replace "preview" with "analytic" in item.assets.get() if you need access to high-resolution imagery.

Optional Filters

You can refine your search results using optional metadata filters such as:

  • Cloud Cover: Limit imagery to a maximum % of cloud presence.
  • Off-Nadir Angle: Filter by the angle between the satellite view and vertical (ideal for orthorectified imagery).
  • GSD (Ground Sample Distance): Filter by spatial resolution (in meters per pixel).

These filters use the STAC Filter Extension with the CQL2 query language.

Here’s an example using all three filters together:

filters = {
    "op": "and",
    "args": [
        {"op": "<=", "args": [{"property": "eo:cloud_cover"}, 20]},
        {"op": "<=", "args": [{"property": "view:off_nadir"}, 15]},
        {"op": "<=", "args": [{"property": "gsd"}, 1.0]},
        {"op": "s_intersects", "args": [{"property": "geometry"}, aoi]},
        {"op": "t_intersects", "args": [{"property": "datetime"}, "2024-07-01/2024-08-01"]}
    ]
}

items = client.search(
    filter_lang="cql2-json",
    filter=filters,
    collections=["quickview-visual"]
).item_collection()

We appreciate your feedback so if there is anything that is not clear or that you think might help if added, please let us know.