Skip to main content

NDBC API

Coverage Status PyPI DOI PyPI - Python Version LinkedIn GitHub PyPI - Downloads

A Python API for the National Data Buoy Center

The National Oceanic and Atmospheric Association's National Data Buoy Center maintains marine monitoring and observation stations around the world1. These stations report atmospheric, oceanographic, and other meterological data at regular intervals to the NDBC. Measurements are made available over HTTP through the NDBC's data service.

The ndbc-api is a python library that makes this data more widely accessible.

The ndbc-api is primarily built to parse whitespace-delimited oceanographic and atmospheric data distributed as text files for available time ranges, on a station-by-station basis2. Measurements are typically distributed as utf-8 encoded, station-by-station, fixed-period text files. More information on the measurements and methodology are available on the NDBC website3.

Please see the included example notebook for a more detailed walkthrough of the API's capabilities.

Installation

The ndbc-api can be installed via PIP:

pip install ndbc-api

To use the async API, install the optional async extra:

pip install ndbc-api[async]

To use Polars instead of Pandas, install the optional polars extra:

pip install ndbc-api[polars]

Lightweight Environments & Polars-Only Support The ndbc-api features a dependency-free parser core that uses a List[dict] intermediate representation. This architecture allows the core API to function without heavy data-science libraries.

By default, pandas and xarray are installed as hard dependencies to ensure compatibility with existing users. However, if you are building a lightweight application or prefer to use Polars exclusively, you can safely uninstall them post-installation:

pip install ndbc-api[polars]
pip uninstall pandas xarray

When uninstalled, the API will gracefully fall back to returning data as a list of dictionaries (as_df=False), or as a Polars DataFrame if requested (as_pl=True).

Conda users can install the ndbc-api via the conda-forge channel:

conda install -c conda-forge ndbc-api

Finally, to install the ndbc-api from source, clone the repository and run the following command:

pip install .

Requirements

The ndbc-api has been tested on Python 3.9, 3.10, 3.12, and 3.13.

The API uses synchronous HTTP requests to compile data matching the user-supplied parameters. The ndbc-api package requires:

  • requests>=2.10.0
  • beautifulsoup4
  • html5lib>=1.1

Legacy Compatibility Dependencies: To ensure backward compatibility for existing users, the following libraries are installed by default but can be safely uninstalled for lightweight or Polars-only environments:

  • pandas>=2.0.0
  • numpy>=1.26.3
  • xarray
  • scipy
  • h5netcdf
Async

The async API additionally requires:

  • aiohttp>=3.9.0

Install it with pip install ndbc-api[async].

Development

If you would like to contribute to the growth and maintenance of the ndbc-api, please feel free to open a PR with tests covering your changes. The tests leverage pytest and depend on the above requirements, as well as:

  • coveralls
  • httpretty
  • pytest
  • pytest-cov
  • pytest-asyncio
  • aioresponses
  • pyyaml
  • pyarrow

Breaking changes will be considered, especially in the current alpha state of the package on PyPi. As the API further matures, breaking changes will only be considered with new major versions (e.g. N.0.0).

Example

The ndbc-api exposes public methods through the NdbcApi class.

from ndbc_api import NdbcApi

api = NdbcApi()

The NdbcApi provides a unified access point for NDBC data. All methods for obtaining data, metadata, and locating stations are available using the api object. The get_data method is the primary method for accessing NDBC data, and is used to retrieve measurements from a given station over a specified time range. This method can request data from the NDBC HTTP Data Service or the THREDDS data service, and return the data as a pandas.DataFrame, xarray.Dataset or python dict object.

Data made available by the NDBC falls into two broad categories.

  1. Station metadata
  2. Station measurements

The api supports a range of public methods for accessing data from the above categories.

Station metadata

The api provides public methods for accessing NDBC station metadata and capabilities:

  1. stations: Returns all active NDBC stations.
  2. historical_stations and station_deployments: Returns historical station deployments and sensor history across hull/location changes.
  3. nearest_station and radial_search: Geodesic spatial search with optional capability filtering (met, currents, waterquality, dart, owner, program, station_type) and k-nearest / limit support.
  4. station: Returns station metadata from a given station ID.
  5. available_realtime and available_historical: Returns hyperlinks and measurement names for realtime and historical measurements captured by a given station.
  6. explain_station: Synthesizes station metadata, realtime modes, and historical coverage into a unified dictionary.
stations
# get all stations and some metadata as a Pandas DataFrame
stations_df = api.stations()
# parse the response as a dictionary
stations_dict = api.stations(as_df=False)
nearest_station
# specify desired latitude and longitude
lat = '38.88N'
lon = '76.43W'

# find the station ID of the nearest NDBC station
nearest = api.nearest_station(lat=lat, lon=lon)
print(nearest)
'tplm2'
# find the 3 nearest stations equipped with meteorological sensors
nearest_3_ids = api.nearest_station(lat=lat, lon=lon, k=3, met=True)
# specify desired latitude, longitude, radius, and units ('km', 'nm', or 'mi')
lat = '38.88N'
lon = '76.43W'
radius = 100
units = 'km'

# find all NDBC stations within the radius, sorted by geodesic distance
nearby_stations_df = api.radial_search(lat=lat, lon=lon, radius=radius, units=units)
station, station_deployments, and explain_station
# get station metadata
tplm2_meta = api.station(station_id='tplm2')
# parse the response as a Pandas DataFrame
tplm2_df = api.station(station_id='tplm2', as_df=True)

# inspect historical deployment spans for a single station
deployments_df = api.station_deployments(station_id='41001')

# get a unified summary of metadata, realtime modes, and historical coverage
summary = api.explain_station(station_id='tplm2')
available_realtime
# get all available realtime measurements, periods, and hyperlinks
tplm2_realtime = api.available_realtime(station_id='tplm2')
# parse the response as a Pandas DataFrame
tplm2_realtime_df = api.available_realtime(station_id='tplm2', as_df=True)
available_historical
# get all available historical measurements, periods, and hyperlinks
tplm2_historical = api.available_historical(station_id='tplm2')
# parse the response as a Pandas DataFrame
tplm2_historical_df = api.available_historical(station_id='tplm2', as_df=True)
Station measurements

The api provides methods for inspecting, planning, and executing NDBC station measurement queries:

  1. get_modes: Returns a list of supported modes corresponding to the data formats provided by the NDBC data service.
  2. describe_mode: Returns structured schema metadata, physical units, and missing-data sentinel values for one or all NDBC modes without network I/O.
  3. build_requests: Pure dry-run URL builder returning the exact NDBC HTTP or THREDDS/OpenDAP URLs for a query without network I/O.
  4. get_data: Returns measurements of a given type for one or more stations (pandas.DataFrame with df.attrs['units'], polars.DataFrame, xarray.Dataset, or dict).
  5. dump_cache and load_cache: Persist and restore per-station LRU request caches to/from a dict or pickle filepath for reproducible offline workflows.

Note that not all stations provide the same set of measurements. The available_realtime, available_historical, or explain_station methods can be called on a station-by-station basis to ensure a station has the desired data available before building and executing requests with get_data.

get_modes and describe_mode
# get the list of supported meteorological measurement modes
modes = api.get_modes()
print(modes)

# inspect schema, column units, and missing-value sentinels for 'stdmet'
stdmet_schema = api.describe_mode('stdmet')

# preview the exact archive URLs that get_data will fetch
urls = api.build_requests(
    station_id='tplm2',
    mode='stdmet',
    start_time='2020-01-01',
    end_time='2022-01-01',
)
[
    'adcp',
    'cwind',
    'ocean',
    'spec',
    'stdmet',
    'supl',
    'swden',
    'swdir',
    'swdir2',
    'swr1',
    'swr2'
]

Passing use_opendap=True (or as_xarray_dataset=True) to api.get_modes(use_opendap=True) returns the supported THREDDS/OpenDAP modes ('adcp', 'cwind', 'hfradar', 'ocean', 'pwind', 'stdmet', 'swden', 'wlevel').

The mode values above map directly to the identifiers used by the NDBC. Descriptions for each mode are presented below:

  • adcp: Acoustic Doppler Current Profiler measurements, providing information about ocean currents at different depths.
  • cwind: Continuous winds data, offering high-frequency wind speed and direction measurements.
  • ocean: Oceanographic data, including water temperature, salinity, and wave measurements.
  • spec: Spectral wave data, providing detailed information about wave energy and direction.
  • stdmet: Standard meteorological data, including air temperature, pressure, wind speed, and visibility.
  • supl: Supplemental measurements, which can vary depending on the specific buoy and its sensors.
  • swden: Spectral wave density data, providing information about the distribution of wave energy across different frequencies.
  • swdir: Spectral wave direction data, indicating the primary direction of wave energy.
  • swdir2: Secondary spectral wave direction data, capturing additional wave direction information.
  • swr1: First-order spectral wave data, providing basic wave height and period information.
  • swr2: Second-order spectral wave data, offering more detailed wave measurements.
get_data
# get all continuous wind (`cwind`) measurements for station tplm2
cwind_df = api.get_data(
    station_id='tplm2',
    mode='cwind',
    start_time='2020-01-01',
    end_time='2022-09-15',
)
# return data as a dictionary
cwind_dict = api.get_data(
    station_id='tplm2',
    mode='cwind',
    start_time='2020-01-01',
    end_time='2022-09-15',
    as_df=False
)
# get only the wind speed measurements
wspd_df = api.get_data(
    station_id='tplm2',
    mode='cwind',
    start_time='2020-01-01',
    end_time='2022-09-15',
    as_df=True,
    cols=['WSPD']
)
# get all standard meterological (`stdmet`) measurements for stations tplm2 and apam2
stdmet_df = api.get_data(
    station_ids=['tplm2', 'apam2'],
    mode='stdmet',
    start_time='2022-01-01',
    end_time='2023-01-01',
)
# get all (available) continuous wind and standard meterological measurements for stations tplm2 and apam2
# for station apam2, this is unavailable and will log an error but not affect the rest of the results.
stdmet_df = api.get_data(
    station_ids=['tplm2', 'apam2'],
    modes=['stdmet', 'cwind'],
    start_time='2022-01-01',
    end_time='2023-01-01',
)

Async API

The ndbc-api also provides an async API, AsyncNdbcApi, for use in asyncio applications. All public methods mirror those of the synchronous NdbcApi, but are defined as async def and use aiohttp for non-blocking I/O.

Install the async extra if you haven't already:

pip install ndbc-api[async]

The AsyncNdbcApi is used as an async context manager:

import asyncio
from ndbc_api import AsyncNdbcApi

async def main():
    async with AsyncNdbcApi() as api:
        # get all stations
        stations_df = await api.stations()

        # find the nearest station
        nearest = await api.nearest_station(lat='38.88N', lon='76.43W')

        # get standard meteorological data
        stdmet_df = await api.get_data(
            station_id='tplm2',
            mode='stdmet',
            start_time='2020-01-01',
            end_time='2022-01-01',
        )

        # concurrent multi-station query
        multi_df = await api.get_data(
            station_ids=['tplm2', 'apam2'],
            mode='stdmet',
            start_time='2022-01-01',
            end_time='2023-01-01',
        )

asyncio.run(main())

The async API supports the same use_opendap / as_xarray_dataset options as the synchronous API for accessing data via the THREDDS/OpenDAP service:

async with AsyncNdbcApi() as api:
    ds = await api.get_data(
        station_id='tplm2',
        mode='stdmet',
        start_time='2020-01-01',
        end_time='2022-01-01',
        use_opendap=True,
    )

More Information

Please see the included example notebook for a more detailed walkthrough of the API's capabilities.

Questions

If you have questions regarding the library please post them into the GitHub discussion forum.

  1. https://www.ndbc.noaa.gov/ ↩

  2. https://www.ndbc.noaa.gov/obs.shtml ↩

  3. https://www.ndbc.noaa.gov/docs/ndbc_web_data_guide.pdf ↩

Metadata

Release files for ndbc-api 0.26.11.7.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ndbc-api 0.26.11.7.1
File Size Uploaded Provenance Actions
ndbc_api-0.26.11.7.1.tar.gz 65.0 kB With provenance Details for ndbc_api-0.26.11.7.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for ndbc-api 0.26.11.7.1
File Interpreter ABI Platform Actions
ndbc_api-0.26.11.7.1-py3-none-any.whl Python 3 none any Details for ndbc_api-0.26.11.7.1-py3-none-any.whl

Total release size: 155.7 kB

Release files / ndbc_api-0.26.11.7.1.tar.gz

Download URL ndbc_api-0.26.11.7.1.tar.gz
Size 65.0 kB
Tags Source
SHA-256 checksum
How to use checksums
01a9eb464d6015ee66617839a53f11da3f39387681fddc62aa26feac8ef30e7a
BLAKE2b-256 checksum
How to use checksums
81ac1c6a793be8f2bc7d29d8388c1186702fcef1699e8f31a59e97b63a24e9a6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 8, 2026.

Transparency log

Release files / ndbc_api-0.26.11.7.1-py3-none-any.whl

Download URL ndbc_api-0.26.11.7.1-py3-none-any.whl
Size 90.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e6094c0868acd5e12cdc09dc309cd97db3c0d31d0f16c3fccd674c9b4e5cb77a
BLAKE2b-256 checksum
How to use checksums
3ebf7b844507247cca46131c78cd3e8f0c85b871b444eb4a08aac240972a0517
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 8, 2026.

Transparency log

Security for ndbc-api 0.26.11.7.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for ndbc_api-0.26.11.7.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 8, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page