Build a query
Every control below maps one-to-one onto a CGI parameter of the public MADIS text/XML service — the same endpoint NOAA's own viewer forms submit to. The URL assembles live on the right. Open it in a tab, copy it as curl or Python, or fetch inline.
Nominal time timetimefilter
Receipt-time filtering is real-time only — the service requires time=0 with it. Useful for "what just arrived since my last poll" harvesting.
Time window minbckminfwdrecwin
Window span (forward − back) must not exceed 119 minutes — the service rejects wider windows. For longer periods, loop hourly nominal times.
Station selection dfltrsel
Uses the state's bounding box — expect stations from neighboring states along the edges (and buoys for coastal states).
Providers pvdrselpvd
Aggregates like ALL-MTR, ALL-MESO, INC-RWIS are providers themselves — one token pulls a whole class. Mesonet observations carry a redistribution restriction; see the Datasets tab.
Variables varselnvars
"Standard set" = TD, RH, T, DD, FF, FFGUST, ALTSE. "All variables" returns every populated column — wide. Hover any token in the Variables tab for units and max QC level.
QC filter qcselqctype
pick your quality floor — the rung is the minimum a value must reach to be returnedFiltering happens per-value, not per-station: a station's temperature can pass while its wind is withheld. qcsel=0 returns everything with descriptors — usually what you want for QC research, since the rejects are the interesting part.
Output xmlcsvmiss
xml=4 appends the QC-applied and QC-results bitmask words after each descriptor — feed those straight into the Bitmask Decoder tab. All numeric output is SI: K, m/s, Pa, meters.
Request URL
NOAA sends no CORS headers, so in-page fetch needs a pass-through proxy (a 12-line one is in the Cookbook — your server is a natural home for it). "Open in new tab" and copied commands always work directly.
QC Handbook
MADIS is one of the only public feeds that ships quality-control verdicts alongside every observation. This is the whole system on one page: the descriptor a value carries, the three-level check pipeline that produced it, and the honest limits of what each variable can be checked against.
The descriptor ladder
every value carries exactly one of these lettersThe three levels
Range/sanity gates, position consistency, and any QC the provider did upstream. Cheap, per-value, catches gross errors: 150°F, negative RH, a buoy on land.
Does the station agree with itself? Internal consistency (T vs TD, SLP vs P), temporal consistency (step changes vs plausible rates), plus model consistency and — for profiles — hydrostatic, super-adiabatic lapse rate, and wind shear checks.
Does the station agree with its neighbors? Optimal-interpolation buddy checking against surrounding observations. The strongest signal — and the one that exposes siting problems no internal check can see.
What each check actually does
Validity — climatological range limits per variable and elevation.
Position consistency — for movers (ships, aircraft): is the implied speed between reports physical?
Provider QC — upstream flags honored where a network runs its own control (e.g. RWIS).
Internal consistency — pairs that must cohere: sea-level vs station pressure, 3-h tendency vs pressure, T vs TD (dewpoint can't exceed temperature), SST vs air temperature.
Temporal consistency — change since the station's last report vs allowable rate.
Model / time-height consistency — background-field comparison for profile datasets.
Statistical spatial consistency — the value vs an OI analysis of neighbors, thresholded by local error statistics.
Spatial consistency — the formal buddy check; failure here with level-1/2 passes is the classic signature of a badly-sited but healthy sensor.
How far can each variable be checked?
max attainable level, surface datasetsLegend: = levels 1·2·3 attainable. Only the core thermodynamic and wind state variables reach level 3.
qcsel — what the filter returns
No filtering. X, Q, and Z values arrive labeled. The research setting.
Drops only the provably impossible (X). Keeps Q.
Internally and temporally coherent values.
Spatially verified. Note: variables whose max level is 1 (precip!) still flow through — they can't fail checks that don't run.
"Best available" — each variable held to its own maximum attainable level. The operational setting.
qcsel=99. QC research, station forensics, or building your own filters → qcsel=0, xml=4 and decode the bitmasks.Precip "since" accumulations — provider conventions
PCPLM / PCPUTCM / PCPCDAY-style fields reset on different clocks per network. MADIS publishes the convention each provider uses — without this table, cross-network precip comparisons silently mix accumulation periods:
Bitmask decoder
With xml=4, every value returns two integers after its descriptor: QCA (checks applied) and QCR (checks failed). Each is a bit-sum. Paste them here and read the verdict check-by-check — this is the audit trail behind the single-letter descriptor.
308.75 K, V, QCA=123, QCR=0. 123 = 1+2+8+16+32+64 → master, validity, internal, temporal, statistical-spatial, and spatial checks all applied; QCR=0 → all passed. That's what earns a V. The same pull's high-frequency METAR row showed QCA=59 — no spatial check yet (bit 64 unset), hence only an S: the descriptor is honest about which checks have actually run.Variable catalog
All 228 tokens the surface service accepts, with names, SI units, and the maximum QC level each can attain — merged from the METAR, mesonet, maritime, COOP, climate, and UrbaNet variable lists. Click a token to add it to the query builder.
Provider catalog
134 surface provider tokens plus the hydro set. Aggregates pull whole classes; individual tokens pin one network. Click any token to select it in the builder.
The MADIS datasets
MADIS ingests thirteen observation families. Two — Surface and Hydro — are exposed through this public CGI. The rest are distributed as netCDF via FTP/LDM and read with the Fortran API (the *dump utilities), which is where the archive-scale work lives.
Cookbook
Copy-paste patterns for scripted access. Everything is GET; everything is UTC; numeric output is SI; missing is −99999.