Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Tropical cyclone tracking and intensity data. Spire aggregates data from the NHC (NOAA/NWS), CPHC, and JTWC to provide global coverage of tropical cyclone activity, including historical tracks dating back to 1990.

Endpoints

MethodEndpointDescription
GET/storm/jsonGet storm data as JSON
GET/storm/kmzGet storm data as KMZ

Storm JSON

GET /storm/json

Retrieve tropical cyclone track and intensity information as JSON. Storms are identified by their ATCF ID.

Parameters

ParameterTypeRequiredDescription
statusstringNoactive (default), inactive, or all
idstringNoATCF ID (e.g., AL022024)
namestringNoStorm name (case insensitive, does not include category)
categorystringNoMinimum category reached (returns storms at this level or higher)
intensitynumberNoMinimum sustained wind speed (knots) reached at any point
regionstringNoBasin or sub-basin code
periodstringNoISO 8601 time range (e.g., 2023-01-01T00:00:00/2023-07-15T00:00:00)
data_filterstringNoall (default), analysis, or forecast
limitintegerNoMax storms to return (1–100, default: 100)
offsetintegerNoNumber of storms to skip (for pagination)

ATCF ID Format

Storm IDs follow the format BBXXYYYY:

Example: AL022024 = Atlantic basin, 2nd storm of 2024

Storm Categories

Categories are listed in order of increasing intensity. When filtering by category, all storms that reached that level or higher are returned.

CodeDescription
XXUnknown
DSDissipating
INInland
PTPost-Tropical Cyclone
LOLow Pressure Center
SSSubtropical Storm
TDTropical Depression
TSTropical Storm
TC1Category 1 Hurricane / Typhoon
TC2Category 2 Hurricane / Typhoon
TC3Category 3 Hurricane / Typhoon
TC4Category 4 Hurricane / Typhoon
TC5Category 5 Hurricane / Super Typhoon

Basins

CodeName
NANorth Atlantic
SASouth Atlantic
EPEastern North Pacific
WPWestern North Pacific
NINorth Indian
SISouth Indian
SPSouthern Pacific

Sub-Basins

CodeName
CSCaribbean Sea
GMGulf of Mexico
MMMissing (no sub-basin assigned)
CPCentral Pacific
ASArabian Sea
BBBay of Bengal
WAWestern Australia
EAEastern Australia

Example Requests

Get active storms:

Shell
Python
Node.js
curl -X GET \
  'https://api.wx.spire.com/storm/json?status=active' \
  -H 'spire-api-key: YOUR_API_KEY'

Get a specific storm by name:

Shell
Python
Node.js
curl -X GET \
  'https://api.wx.spire.com/storm/json?name=Beryl&status=all' \
  -H 'spire-api-key: YOUR_API_KEY'

Get storms in a time period:

Shell
Python
Node.js
curl -X GET \
  'https://api.wx.spire.com/storm/json?period=2024-06-01T00:00:00/2024-11-30T00:00:00&status=inactive' \
  -H 'spire-api-key: YOUR_API_KEY'

Get major hurricanes (Category 3+):

Shell
Python
Node.js
curl -X GET \
  'https://api.wx.spire.com/storm/json?category=TC3&region=NA&status=all' \
  -H 'spire-api-key: YOUR_API_KEY'

Response

The response is an array of storm objects, each with separate observed_track and forecast_track arrays:

[
  {
    "atcf_id": "WP052023",
    "storm_name": "Doksuri",
    "basin": "WP",
    "subbasin": "MM",
    "season": 2023,
    "is_active": true,
    "advisory_number": 18,
    "advisory_issuance_time": "2023-07-25T18:00:00+00:00",
    "max_development_category": "TC4",
    "max_sustained_wind": 128.0,
    "min_mslp": 926.0,
    "dates_active": {
      "start": "2023-07-17",
      "end": "ongoing"
    },
    "observed_track": [
      {
        "lat": 7.1,
        "lon": 136.2,
        "category_code": "XX",
        "basin": "WP",
        "subbasin": "MM",
        "wind_gusts": null,
        "max_sustained_wind": 20.0,
        "min_mslp": 1004.0,
        "movement_direction": null,
        "movement_speed": null,
        "wind_extent_radii": {},
        "time": "2023-07-17T00:00:00+00:00"
      }
    ],
    "forecast_track": [
      {
        "lat": 19.6,
        "lon": 120.6,
        "category_code": "TC3",
        "basin": "WP",
        "subbasin": "MM",
        "wind_gusts": 135.0,
        "max_sustained_wind": 110.0,
        "min_mslp": null,
        "movement_direction": 315.0,
        "movement_speed": 6.0,
        "wind_extent_radii": {
          "34kts": {
            "wind_speed": 34.0,
            "ne": 190.0,
            "se": 210.0,
            "nw": 180.0,
            "sw": 150.0
          },
          "50kts": {
            "wind_speed": 50.0,
            "ne": 80.0,
            "se": 80.0,
            "nw": 70.0,
            "sw": 90.0
          },
          "64kts": {
            "wind_speed": 64.0,
            "ne": 40.0,
            "se": 40.0,
            "nw": 30.0,
            "sw": 30.0
          }
        },
        "forecast_hour": 12,
        "forecast_time": "2023-07-26T06:00:00+00:00"
      }
    ]
  }
]

Response Fields — Storm Summary

FieldTypeDescription
atcf_idstringATCF ID storm identifier
storm_namestringStorm name (empty until named)
basinstringOcean basin code
subbasinstringSub-basin code
seasonintegerYear of the storm season
is_activebooleanWhether storm is currently active
advisory_numberintegerAdvisory number (null for inactive storms)
advisory_issuance_timestringAdvisory issuance time (null for inactive storms)
max_development_categorystringHighest category reached over observed track
max_sustained_windnumberMaximum sustained wind (knots) over observed track
min_mslpnumberMinimum sea-level pressure (hPa) over observed track
dates_activeobjectStart/end dates for all positions

Response Fields — Track Positions

FieldTypeDescription
latnumberLatitude of storm center
lonnumberLongitude of storm center
category_codestringStorm category at this position
basinstringBasin at this position
subbasinstringSub-basin at this position
wind_gustsnumberMaximum wind gusts (knots)
max_sustained_windnumberMaximum sustained wind (knots)
min_mslpnumberMinimum sea-level pressure (hPa)
movement_directionnumberDirection storm is moving toward (degrees from N)
movement_speednumberSpeed of storm movement (knots)
wind_extent_radiiobjectWind Radii for 34, 50, 64 kt thresholds (NE/SE/NW/SW quadrants, nautical miles)
timestringValid time (observed track only)
forecast_timestringValid time (forecast track only)
forecast_hourintegerHours from advisory issuance (forecast track only)

Storm KMZ

GET /storm/kmz

Retrieve storm data as KMZ file for visualization in Google Earth Pro.

Parameters

Same parameters as /storm/json.

Example Request

Shell
Python
Node.js
curl -OJ -X GET \
  'https://api.wx.spire.com/storm/kmz?name=Beryl&status=all' \
  -H 'spire-api-key: YOUR_API_KEY'

Python Example

Track active storms and monitor intensity:

import requests

headers = {'spire-api-key': 'YOUR_API_KEY'}

# Get all active storms
response = requests.get(
    'https://api.wx.spire.com/storm/json',
    headers=headers,
    params={'status': 'active'}
)

storms = response.json()

for storm in storms:
    print(f"\n{storm['storm_name']} ({storm['atcf_id']})")
    print(f"  Basin: {storm['basin']}")
    print(f"  Category: {storm['max_development_category']}")
    print(f"  Max Wind: {storm['max_sustained_wind']} kt")
    print(f"  Min Pressure: {storm['min_mslp']} hPa")
    print(f"  Active: {storm['is_active']}")

    # Get latest observed position
    if storm['observed_track']:
        latest = storm['observed_track'][-1]
        print(f"  Latest Position: {latest['lat']:.1f}N, {latest['lon']:.1f}E")
        print(f"  As of: {latest['time']}")

    # Show forecast positions
    if storm.get('forecast_track'):
        print(f"  Forecast positions: {len(storm['forecast_track'])}")
        for pos in storm['forecast_track'][:3]:
            print(f"    +{pos['forecast_hour']}h: {pos['lat']:.1f}N, {pos['lon']:.1f}E "
                  f"({pos['category_code']}, {pos['max_sustained_wind']} kt)")

Plot Storm Tracks

import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature

# Get historical storms for Atlantic 2024 season
response = requests.get(
    'https://api.wx.spire.com/storm/json',
    headers=headers,
    params={
        'region': 'NA',
        'period': '2024-06-01T00:00:00/2024-11-30T00:00:00',
        'status': 'inactive'
    }
)

storms = response.json()

fig, ax = plt.subplots(
    figsize=(12, 8),
    subplot_kw={'projection': ccrs.PlateCarree()}
)

ax.add_feature(cfeature.LAND)
ax.add_feature(cfeature.OCEAN)
ax.add_feature(cfeature.COASTLINE)
ax.set_extent([-100, -10, 5, 50])

for storm in storms:
    # Plot observed track
    obs = storm.get('observed_track', [])
    if obs:
        lats = [p['lat'] for p in obs]
        lons = [p['lon'] for p in obs]
        ax.plot(lons, lats, label=storm['storm_name'], transform=ccrs.PlateCarree())

ax.legend(loc='upper left')
plt.title('Atlantic Tropical Cyclones 2024')
plt.show()