Retrieve historical captures

While standard lookupLandscape calls omit the capture date to provide features synthesized from multiple recent satellite images, some applications require landscape data at a certain historical time point. For example, you might want to observe year-over-year changes to field boundaries, farm ponds, or tree cover.

To fetch landscape features from a historical date, use a "discover then retrieve" workflow: first identifying when imagery was captured for a region, and then requesting landscape features for that specific date.

Prerequisites

To follow this guide, you need:

  • A basic understanding of Python.
  • Familiarity with S2 geometry concepts. See Understanding the data for more information.
  • An API key for the Agricultural Understanding API. See Setup for instructions on how to get an API key.

Discover and retrieve workflow

To fetch historical estimates, you interact with two endpoints in sequence:

  1. Discover: Issue a request to lookupLandscapeCaptureDate, specifying the area of interest using a level 13 S2 cell ID.
  2. Select: Extract an available captureDate structured as year, month, and day from the response. Dates are returned in ascending order in the response, so the earliest available date appears as the first entry.
  3. Retrieve: Issue a request to lookupLandscape, passing both the s2CellId and the explicit captureDate.

Handle single-capture data limitations

When you omit captureDate in standard lookupLandscape calls, the API synthesizes features from satellite imagery.

However, when supplying a specific captureDate, the API returns boundaries extracted from satellite images only from that specific capture date. Single satellite captures may have missing features due to cloud cover or atmospheric haze.

Imagery availabilities vary based on location, and there might not be satellite images in a selected date range. In such situations, we recommend using the synthesized landscape features (without specifying a captureDate) as a fallback. For details covering standard retrievals, refer to Basic retrieval.

Historical retrieval example

The following Python example demonstrates the "discover then retrieve" workflow, first finding available dates and then retrieving the landscape for the first discovered date:

import json
import os
import requests

API_KEY = os.environ.get("AG_UNDERSTANDING_API_KEY")
if not API_KEY:
    raise ValueError("Please set the 'AG_UNDERSTANDING_API_KEY' environment variable.")

date_url = "https://agriculturalunderstanding.googleapis.com/v1:lookupLandscapeCaptureDate"
lookup_url = "https://agriculturalunderstanding.googleapis.com/v1:lookupLandscape"

s2_cell_id = "4306523180387794944"
request_payload = {
    "locationSpecifier": {
        "s2CellId": s2_cell_id
    }
}

# 1. Discover available dates
date_response = requests.post(date_url, json=request_payload, params={"key": API_KEY})
date_response.raise_for_status()
date_data = date_response.json()

available_dates = date_data.get("captureDates", [])
if available_dates:
    # 2. Select the first available date
    chosen_date = available_dates[0]
    print(f"Discovered available data for: {chosen_date}")

    # 3. Retrieve landscape for the explicit date
    lookup_payload = {
        "locationSpecifier": {
            "s2CellId": s2_cell_id
        },
        "captureDate": chosen_date
    }

    lookup_response = requests.post(lookup_url, json=lookup_payload, params={"key": API_KEY})
    lookup_response.raise_for_status()
    lookup_data = lookup_response.json()

    geojson_str = lookup_data.get("landscape", {}).get("geojson", "{}")
    geojson_data = json.loads(geojson_str)

    features = geojson_data.get("features", [])
    print(f"Successfully retrieved {len(features)} landscape features for {chosen_date}.")
    for feature in features:
        alu_type = feature.get("properties", {}).get("alu_type")
        area = feature.get("properties", {}).get("area_sq_m")
        print(f"Feature type: {alu_type}, area: {area} sq m")
else:
    print("No landscape data available for this location.")

Parsed capture dates

The endpoint returns an array of available dates for the requested S2 cell:

{
  "captureDates": [
    {
      "year": 2011,
      "month": 11,
      "day": 10
    },
    {
      "year": 2012,
      "month": 4,
      "day": 1
    }
  ]
}

Parsed GeoJSON

When the stringified GeoJSON in landscape.geojson is parsed from the historical lookupLandscape response, it expands to standard GeoJSON features:

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "id": "7M2JHHF6+MFWC",
      "geometry": {
        "type": "MultiPolygon",
        "coordinates": [
          [
            [
              [92.5612194, 10.5741646],
              [92.5612194, 10.5742008],
              [92.5612559, 10.5742551],
              [92.5612467, 10.5742912],
              [92.5612192, 10.5743094],
              [92.5611644, 10.5743001],
              [92.5611462, 10.5742731],
              [92.5611462, 10.5742006],
              [92.5611646, 10.5741555],
              [92.5612194, 10.5741646]
            ]
          ]
        ]
      },
      "properties": {
        "alu_type": "trees",
        "area_sq_m": 149.7001,
        "class_confidence": 1.0,
        "capture_timestamp_sec": 1697353200
      }
    }
  ]
}

Payload breakdown:

  • Capture timestamp: The capture_timestamp_sec (for example, 1697353200) reflects the Unix timestamp of the specific historical satellite capture.
  • Cross-references: For details on schema characteristics, see Response format.