---
name: usgs-landsat-m2m-ingestion
description: "How to get USGS Landsat M2M API data into a pandas DataFrame and Parquet: access, the request, the format, limits, quirks and terms."
---

# Search USGS Landsat scenes into pandas and Parquet

Source entry: https://signal-lab-jet.vercel.app/datasets/usgs-landsat-m2m
Provider: https://m2m.cr.usgs.gov/
Checked against the provider's documentation: 2026-11-01

## Access
- Create a free EROS account, request M2M access in the account's Access Controls, and create an application token.
- Set USGS_EROS_USERNAME and USGS_M2M_APP_TOKEN; never embed the application token or returned API key.

## Request
```bash
curl -X POST 'https://m2m.cr.usgs.gov/api/api/json/stable/login-token' -H 'Content-Type: application/json' -d '{"username":"'$USGS_EROS_USERNAME'","token":"'$USGS_M2M_APP_TOKEN'"}'
```

## Format
REST JSON responses; scene-search records include entity and display IDs, acquisition and publish dates, spatial bounds, cloud-cover values, browse links and dataset-specific metadata.

## Load into pandas and Parquet
Needs Python 3 with requests, pandas and pyarrow.
```python
"""Search Landsat 8-9 Level-2 scenes over a small bounding box -> pandas -> Parquet."""
import os
import requests
import pandas as pd

BASE = "https://m2m.cr.usgs.gov/api/api/json/stable"
username = os.environ["USGS_EROS_USERNAME"]
app_token = os.environ["USGS_M2M_APP_TOKEN"]
login = requests.post(f"{BASE}/login-token", json={"username": username, "token": app_token}, timeout=60)
login.raise_for_status()
api_key = login.json()["data"]
headers = {"X-Auth-Token": api_key}
payload = {"datasetName": "landsat_ot_c2_l2", "maxResults": 100, "sceneFilter": {"spatialFilter": {"filterType": "mbr", "lowerLeft": {"latitude": 43.60, "longitude": -79.65}, "upperRight": {"latitude": 43.90, "longitude": -79.10}}, "acquisitionFilter": {"start": "2026-10-01", "end": "2026-10-31"}}}
r = requests.post(f"{BASE}/scene-search", json=payload, headers=headers, timeout=60)
r.raise_for_status()
df = pd.json_normalize(r.json()["data"]["results"], sep="_")
df.to_parquet("usgs_landsat_scenes.parquet", index=False)
print(len(df), "scenes")
requests.post(f"{BASE}/logout", headers=headers, timeout=60).raise_for_status()
```
Not run: it needs a free API key.

## Limits
- Rate limit: Not stated.
- M2M API access requires an approved account request in addition to an EROS account.
- Raster downloads can be large; search metadata first and request only required bands or bundles.

## Quirks
- The application token authenticates at login-token and returns a temporary API key used in the X-Auth-Token header.
- Dataset names and available metadata filters vary across Landsat collections.
- Cloud cover is scene metadata; inspect pixel-level quality bands before deriving a local signal.

## Terms and attribution
- USGS-authored data and information are public-domain material; marked third-party content is excluded.
- USGS asks users to give proper credit.
- Terms page: https://www.usgs.gov/information-policies-and-instructions/copyrights-and-credits

## Sources
- https://m2m.cr.usgs.gov/: "Utilizes RESTful JSON API for accessing more than 300 unique USGS/EROS datasets"
- https://www.usgs.gov/faqs/how-do-i-search-and-download-landsat-data: "Landsat data products held in the USGS archives can be searched and downloaded at no charge from a variety of sources."
- https://www.usgs.gov/media/files/m2m-application-token-documentation: "The application token is a 64-bit encrypted string that can be used in the Machine-2-Machine API 'login-token' endpoint"
- https://www.usgs.gov/information-policies-and-instructions/copyrights-and-credits: "USGS-authored or produced data and information are considered to be in the U.S. Public Domain"

## Help improve this skill
Missing a source, or see something to improve? Call the MCP tool suggest_source or feedback (or POST /api/suggest or /api/feedback). Reviewed ideas: https://signal-lab-jet.vercel.app/agent-suggestions

Information for educational purposes only. Free tiers, limits and licenses belong to the providers and may change; check the provider's own terms before using the data.
