A Python wrapper for the NOAA CO-OPS Tides & Currents Data and Metadata APIs.
Supported on Python 3.10, 3.11, 3.12, and 3.13.
uv add noaa-coopsOr with pip:
pip install noaa-coopsData is accessed via Station objects identified by a NOAA station id:
>>> from noaa_coops import Station
>>> seattle = Station(id="9447130") # Seattle, WAFind station IDs via the NOAA Tides & Currents mapping interface or search by bounding box:
>>> from noaa_coops import get_stations_from_bbox, Station
>>> stations = get_stations_from_bbox(
... lat_coords=[40.389, 40.9397],
... lon_coords=[-74.4751, -73.7432],
... )
>>> stations
['8516945', '8518750', '8531680']
>>> Station(id="8516945").name
'Kings Point'Station metadata lives on the .metadata attribute, and individual fields are
also promoted to top-level attributes on the Station object:
>>> seattle = Station(id="9447130")
>>> seattle.name
'Seattle'
>>> seattle.state
'WA'
>>> seattle.lat_lon
{'lat': 47.60264, 'lon': -122.3393}Per-product first/last observation dates:
>>> seattle.data_inventory["Wind"]
{'start_date': '1991-11-09 00:00', 'end_date': '...'}Note: The data inventory comes from NOAA's legacy SOAP endpoint and is best-effort. If the service is unreachable,
data_inventoryis set to{}and a warning is logged —Station()construction still succeeds.
Data is returned as a pandas DataFrame indexed by timestamp. Column names
mirror NOAA's response format.
>>> seattle = Station(id="9447130")
>>> df = seattle.get_data(
... begin_date="20150101",
... end_date="20150131",
... product="water_level",
... datum="MLLW",
... units="metric",
... time_zone="gmt",
... )
>>> df.head()
v s f q
t
2015-01-01 00:00:00 1.799 0.023 0,0,0,0 v
2015-01-01 00:06:00 1.718 0.018 0,0,0,0 v
2015-01-01 00:12:00 1.639 0.013 0,0,0,0 v
2015-01-01 00:18:00 1.557 0.012 0,0,0,0 v
2015-01-01 00:24:00 1.473 0.014 0,0,0,0 vMulti-month and multi-year ranges are automatically split into 31-day (or
365-day for hourly_height / high_low) blocks and concatenated. If NOAA
fails to return data for a block, you get a partial DataFrame along with a
RuntimeWarning and a df.attrs["missing_blocks"] list describing which
ranges failed — downstream code can detect gaps instead of silently averaging
across them.
Values accepted by Station.get_data(...) — see
NOAA's API docs for
the authoritative reference.
| Argument | Accepted values |
|---|---|
product |
water_level, hourly_height, high_low, daily_mean, monthly_mean, one_minute_water_level, predictions, datums, air_gap, air_temperature, water_temperature, wind, air_pressure, conductivity, visibility, humidity, salinity, currents, currents_predictions, ofs_water_level |
datum |
CRD, IGLD, LWD, MHHW, MHW, MTL, MSL, MLW, MLLW, NAVD, STND (case-insensitive). Required for water-level products. |
units |
metric, english |
time_zone |
gmt, lst, lst_ldt |
bin_num |
Integer. Required for currents and currents_predictions. Find values on each station's info page. |
interval |
Product-specific. predictions: h, 1, 5, 10, 15, 30, 60, hilo. currents: 6, h. currents_predictions: h, 1, 6, 10, 30, 60, max_slack. Forbidden on water_level, hourly_height, one_minute_water_level. |
begin_date and end_date accept any of:
"20150101"—%Y%m%d"20150101 12:34"—%Y%m%d %H:%M"01/15/2015"—%m/%d/%Y"01/15/2015 23:59"—%m/%d/%Y %H:%M
NOAA's CO-OPS APIs are public and free. There are no enforced rate limits but
please be reasonable — avoid tight loops against a single station and cache
results when you can. This library uses connection pooling and automatic
retries on transient failures (429 / 5xx) via a module-level
requests.Session.
Bug reports, feature requests, and PRs welcome. See CONTRIBUTING.md for dev-environment setup and the release workflow.
