| name | erddap |
| description | Help users construct correct ERDDAP(TM) server request URLs and understand the ERDDAP REST protocol, in any programming language, for any ERDDAP server (not just NOAA's). Use when users need to query griddap or tabledap datasets, search/browse a dataset catalog (search, categorize, info), browse/download raw files (files), convert time/units/keywords (convert), check server version, or debug an ERDDAP request error, timeout, or malformed-URL problem. |
| metadata | {"author":"Roy Mendelssohn (@rmendels)","version":"1.0"} |
| license | CC0 |
ERDDAP(TM) is a NOAA-developed (now widely adopted) REST data server for gridded and tabular scientific datasets. This skill covers the protocol — it applies to any ERDDAP instance, in any language, from curl to Python to R. (For an R client built on this protocol, see the rerddap/rerddapXtracto/plotdap/rerddapUtils skills.)
Core Principle: Everything Is a Bookmarkable GET URL
Every ERDDAP request — search, metadata, data, even graphs — is a single stateless HTTP GET URL of the form:
https://<host>/erddap/<service>/<path>.<fileType>?<query>
https://coastwatch.pfeg.noaa.gov/erddap/tabledap/pmelTaoDySst.csv?longitude,latitude,time,T_25&time>=2015-05-23T12:00:00Z
There's no session, no auth token for public data, no POST body — the URL is the entire request, which is why it's shareable/cacheable/bookmarkable. .<fileType> picks the response format (.json, .csv, .nc, .png, ...); available file types differ by service (a UI service like search supports a different set than griddap/tabledap data requests).
Wrong pattern: guessing dimension/variable names or their valid ranges. Always call info first (see below) — same principle as rerddap::info() before griddap()/tabledap() in the R ecosystem.
Services at a Glance
| Service | Purpose | URL pattern |
|---|
info | Dataset metadata: variables, dimensions, ranges, units | /erddap/info/<datasetID>/index.<fileType> |
search | Full-text dataset search | /erddap/search/index.<fileType>?searchFor=<query> |
search/advanced | Search by bounding box/time/protocol/institution/etc. | /erddap/search/advanced.<fileType>?... |
categorize | Browse datasets by attribute (e.g. standard_name) | /erddap/categorize/<attribute>/<value>/index.<fileType> |
griddap | Fetch gridded data (satellite, model output) | /erddap/griddap/<datasetID>.<fileType>?<query> |
tabledap | Fetch tabular data (buoys, cruises, animal tracks) | /erddap/tabledap/<datasetID>.<fileType>?<query> |
files | Browse/download the dataset's raw source files | /erddap/files/<datasetID>/<path> |
wms | Map images per the OGC Web Map Service standard | /erddap/wms/<datasetID>/... |
convert | Time / units / FIPS county / CF-keyword conversion | /erddap/convert/<converter>?<params> |
subscriptions | Email/URL notification when a dataset updates | /erddap/subscriptions/... |
version | Server version (plain text ERDDAP_version=X.Y.Z) | /erddap/version |
Full reference: ERDDAP REST services page on any ERDDAP install (the docs are bundled with the server, so the path works on every instance, not just NOAA's).
info: Always the First Call
https://coastwatch.pfeg.noaa.gov/erddap/info/jplMURSST41/index.json
Returns every variable (dimensions and data variables), its data type, units, and actual_range — the only reliable source for names/ranges to build a griddap/tabledap query against. /erddap/info/index.json?page=1&itemsPerPage=100000 (no datasetID) lists every dataset on the server.
griddap: Gridded Data
Subsets by dimension using [start:stride:stop] array-index syntax, or [(value):stride:(value)] using actual dimension values in parentheses — either form, per dimension, comma-separated for multiple variables:
https://coastwatch.pfeg.noaa.gov/erddap/griddap/jplMURSST41.csv?analysed_sst[(2020-06-15T09:00:00Z)][(30):100:(50)][(-140):100:(-110)]
(last) grabs the final index on that dimension; (last-10) offsets from it. Full subsetting syntax, gotchas (dateline handling, timeout on long time ranges, the NetCDF-Java "virtual file" trap, graphics parameters) and the complete file-type table: see references/griddap-syntax.md.
tabledap: Tabular Data
An optional comma-separated field list, followed by &-joined variable OP value constraints (implicit AND):
https://coastwatch.pfeg.noaa.gov/erddap/tabledap/pmelTaoDySst.csv?longitude,latitude,time,T_25&time>=2015-05-23T12:00:00Z&time<=2015-05-31T12:00:00Z
Operators: =, !=, <, <=, >, >=, =~ (Java regex). String/regex right-hand values must be double-quoted: station=~"(Able|Baker)". Server-side distinct()/orderBy*() functions, floating-point/NaN constraint gotchas, and the complete file-type table: see references/tabledap-syntax.md.
files: Raw Source Files
https://coastwatch.pfeg.noaa.gov/erddap/files/cwwcNDBCMet/nrt/NDBC_41008_met.nc
curl --compressed "https://coastwatch.pfeg.noaa.gov/erddap/files/cwwcNDBCMet/nrt/NDBC_{41008,41009}_met.nc" -o ndbc/#1.nc
Appending / with no filename lists the directory (default HTML table; .csv/.json/etc. work too, same file-type set as index/info/search).
convert: Time / Units
# ISO string -> seconds since epoch
https://coastwatch.pfeg.noaa.gov/erddap/convert/time.txt?stringTime=1985-01-02T00:00:00Z&units=seconds%20since%201970-01-01T00:00:00Z
# seconds since epoch -> ISO string
https://coastwatch.pfeg.noaa.gov/erddap/convert/time.txt?n=473472000&units=seconds%20since%201970-01-01T00:00:00Z
Swap .html for .txt for a plain-text (script-friendly) response. Same pattern for /erddap/convert/units.txt?UDUNITS=... / ?UCUM=..., fipscounty.txt, and keywords.txt.
Percent-Encoding: Applies Everywhere
Browsers percent-encode form submissions automatically; scripts and curl must do it explicitly. Special characters (anything outside A-Za-z0-9_-!.~'()*) become %HH (2-digit hex): space → %20, & → %26, " → %22, </> → %3C/%3E, [/] → %5B/%5D, + → %2B, | → %7C. Don't encode the structural & between constraints or the = that separates a constraint's variable from its value — only the values.
curl "https://coastwatch.pfeg.noaa.gov/erddap/search/index.json?searchFor=sea%20surface%20temperature"
Response File Types, Briefly
| Category | Common types |
|---|
UI services (info/search/categorize/files/index) | .csv, .json, .htmlTable, .tsv, .mat, .nc, .xhtml |
griddap/tabledap data | .nc, .csv, .csvp, .json, .mat, .parquet, .nccsv, plus OPeNDAP .das/.dds/.dods |
| Graphics (either data protocol) | .png, .pdf, .transparentPng, .kml, .geotif (griddap only) |
All .json responses share one shape: {"table": {"columnNames": [...], "columnTypes": [...], "columnUnits": [...], "rows": [[...], ...]}} — write one parser, reuse it across every ERDDAP service.
Common Mistakes
| Mistake | Fix |
|---|
Guessing dimension/variable names instead of calling info first | /erddap/info/<datasetID>/index.json is the source of truth for names, units, ranges |
Treating a griddap/tabledap .nc URL as a static file for a NetCDF library (NetCDF-Java, ncdf4, etc.) | It's a virtual file, not persistent — download it first (or connect via OPeNDAP using the dataset URL without a file extension) |
Requesting a long time range (>~30 time steps) from griddap in one call | Split into several smaller-time-range requests; long single requests are prone to proxy/timeout errors |
| Building a polygon-shaped request | Not supported — compute the lat/lon bounding box (min/max) and subset that instead |
Unquoted string values in tabledap constraints (station=NDBC41201) | String/regex constraint values must be double-quoted: station="NDBC41201" |
temperature!=-99 to filter a numeric fill value | Use the standard missing-value convention instead: temperature!=NaN |
Relying on =/!=/<=/>= for exact floating-point matches | Floating point storage error can make longitude=220.2 miss; use a small range instead |
Forgetting to percent-encode constraint values in scripts/curl | Browsers do it silently; scripts must encode spaces, quotes, brackets, etc. explicitly |
Assuming the version endpoint always exists | A 404 there means the server predates ERDDAP 1.22 — treat it as an old version |
Resources