Tropical Storms example
Business question
Which tropical storms of Red alert level have we been tracking in the last 30 days, and how does peak wind speed compare across them?
We use adam.adam_ts_events for the events themselves and adam.adam_ts_tracks for the forecast tracks — both linked by the same event identifier.
Step-by-step from a terminal
1. List recent Red-alert storms
curl -sS -H "Accept: application/geo+json" \
"https://api.adam.geospatial.wfp.org/api/collections/adam.adam_ts_events/items?limit=5&sortby=-wind_speed&filter=alert_level%20%3D%20'Red'%20AND%20published_at%20%3E%20TIMESTAMP('2026-03-21T00:00:00')" \
| jq '{numberMatched, sample: (.features[0].properties | {name, published_at, current_storm_status, alert_level, wind_speed, iso3, cleared})}'
{
"numberMatched": 20,
"sample": {
"name": "SINLAKU-26",
"published_at": "2026-04-15T02:21:45",
"current_storm_status": "Category 3",
"alert_level": "Red",
"wind_speed": 203.7024,
"iso3": "MNP",
"cleared": false
}
}
{
"numberMatched": 20,
"sample": {
"name": "SINLAKU-26",
"published_at": "2026-04-15T02:21:45",
"current_storm_status": "Category 3",
"alert_level": "Red",
"wind_speed": 203.7024,
"iso3": "MNP",
"cleared": false
}
}
2. Follow a named storm across collections
Once you have a storm name, you can pull its track geometries from the sibling tracks collection:
curl -sS -H "Accept: application/geo+json" \
"https://api.adam.geospatial.wfp.org/api/collections/adam.adam_ts_tracks/items?limit=100&filter=name%20%3D%20'SINLAKU-26'" \
| jq '{numberMatched, fields: (.features[0].properties | keys)}'
And the forecast nodes (with the node_time <> 'previous position' trick to skip the history):
curl -sS -H "Accept: application/geo+json" \
"https://api.adam.geospatial.wfp.org/api/collections/adam.adam_ts_nodes/items?limit=100&filter=name%20%3D%20'SINLAKU-26'%20AND%20node_time%20%3C%3E%20'previous%20position'" \
| jq '.features[].properties | {name, node_time, wind_speed, storm_status}' \
| head -40
Python recap
import json
import urllib.parse
import urllib.request
from datetime import datetime, timedelta, timezone
BASE = "https://api.adam.geospatial.wfp.org/api"
since = (datetime.now(timezone.utc) - timedelta(days=30)).strftime("%Y-%m-%dT%H:%M:%S")
params = urllib.parse.urlencode({
"filter": f"alert_level = 'Red' AND published_at > TIMESTAMP('{since}')",
"sortby": "-wind_speed",
"limit": 50,
})
url = f"{BASE}/collections/adam.adam_ts_events/items?{params}"
req = urllib.request.Request(url, headers={"Accept": "application/geo+json"})
with urllib.request.urlopen(req) as r:
fc = json.loads(r.read())
for f in fc["features"][:10]:
p = f["properties"]
print(f" {p.get('name', ''):<15} {p.get('current_storm_status', ''):<15} {p.get('wind_speed', 0):>6.1f} km/h")
Interactive — marimo playground
Change the alert level dropdown or slide the date window; the query and chart update reactively.
Download: tropical-storms.py
Try it yourself
Live references
- All 8 TS collections → Collections Reference
- Events on Swagger →
items_collections__collectionId__items_get - Browse TS events live → /api/collections/adam.adam_ts_events/items
- Browse tracks → /api/collections/adam.adam_ts_tracks/items