The Aviation Weather Center's Data API at aviationweather.gov is the first place most developers go for METAR and TAF data, and for good reason. It's free, it's run by the US National Weather Service, it covers airports worldwide, and it returns JSON. Plenty of good apps run on it.

It also has rules that catch people out: a hard rate limit that leads to being blocked, result caps, a 30-day history window, and no support channel or service-level agreement. This guide covers how to use the API without running into those limits, and when it makes sense to pay for a commercial aviation weather API instead.

We sell one of those commercial APIs. For many projects, our honest advice is to stay on AviationWeather.gov, and we'll say which ones.

The rules, from the documentation

The Data API page lists these limits and guidelines:

RuleDetail
Rate limit100 requests per minute. Exceeding it "will result in access being blocked", and excess requests get HTTP 429
Result capMost endpoints return at most 400 entries
HistoryAbout the previous 30 days
User-AgentSet a custom one, so automated filtering doesn't block legitimate traffic
Browser useCross-origin requests (CORS) aren't permitted
ParametersUndocumented query parameters return an error
Bulk dataUse the cache files instead of large or frequent custom queries
Empty results204 No Content means a valid request with no data

The base path is /api/data, for example https://aviationweather.gov/api/data/metar?ids=KJFK&format=json. Use HTTPS and leave out the www.

The gotchas

Rate limiting blocks you, not just your request

Most commercial APIs reject requests over the limit and let the next ones through. AviationWeather.gov says exceeding the limit results in access being blocked. A loop that fetches 300 airports one at a time, or a few app servers polling at once, can get your IP address blocked, and every request from it fails until the block lifts.

Two things make this easy to hit by accident. Serverless functions and containers often share outbound IP addresses, so you don't always control the traffic counted against you. And retry logic that retries immediately on errors makes a burst worse.

One request per station is the slow way

The ids parameter accepts several stations, so ids=KJFK,KLAX,KORD is one request, not three. For hundreds or thousands of stations, use the cache files: complete datasets that AviationWeather.gov regenerates on a schedule (METARs every minute, TAFs every 10 minutes) and recommends for bulk access. Downloading one file is far kinder to their servers, and to your rate limit, than thousands of station queries.

Browsers can't call it directly

CORS isn't permitted, so a web page can't call the API with fetch from the browser. You need a small backend or serverless function in between. That's also the right place for caching.

Endpoints and schemas change

The API is versioned and changes over time. The older ADDS text data server and /cgi-bin URLs that many tutorials still use have been retired in favour of /api/data. Release notes have also recorded removed query parameters and changed JSON property names, and US text AIRMETs were discontinued in January 2025 in favour of graphical G-AIRMETs. If your parser expects exact property names, pin your expectations in tests and watch the changelog.

US-centric products

METARs and TAFs are available worldwide, but several other products are US-focused, including G-AIRMETs, Center Weather Advisories and the winds aloft tables. If you're building for European or Asian operations, check product coverage before you design around it.

A technician servicing a remote automatic weather station on a hillside

Calling it properly in Python

This client sets a User-Agent, batches stations, caches results for five minutes, treats 204 as "no data", and backs off on 429 instead of retrying straight away:

import time
import requests

API = "https://aviationweather.gov/api/data/metar"
SESSION = requests.Session()
SESSION.headers["User-Agent"] = "my-app/1.0 ([email protected])"  # a custom UA is requested

_cache: dict[str, tuple[float, dict]] = {}
TTL = 300  # METARs are usually issued hourly; 5 minutes is plenty

def metars(stations: list[str]) -> dict[str, dict]:
    """Latest METAR per station, batched and cached. Missing stations are omitted."""
    now = time.time()
    fresh = {s: _cache[s][1] for s in stations if s in _cache and now - _cache[s][0] < TTL}
    todo = [s for s in stations if s not in fresh]

    for i in range(0, len(todo), 100):          # stay well under the 400-result cap
        batch = todo[i : i + 100]
        for attempt in range(4):
            r = SESSION.get(API, params={"ids": ",".join(batch), "format": "json"}, timeout=(5, 20))
            if r.status_code == 429:
                time.sleep(30 * (attempt + 1))  # back off; hammering makes a block worse
                continue
            break
        if r.status_code == 204:                # valid request, no data
            continue
        r.raise_for_status()
        for obs in r.json():
            fresh[obs["icaoId"]] = obs
            _cache[obs["icaoId"]] = (now, obs)
        time.sleep(1)                           # pace batches

    return fresh

print(metars(["KJFK", "EGLL", "LFPG"])["EGLL"]["rawOb"])

Each observation includes the raw report (rawOb) alongside decoded values such as temperature, wind, visibility, cloud layers and the flight category (fltCat). If you only need a handful of airports, this is all you need, and it's free.

When to stay on AviationWeather.gov

Stay on the free API if:

  • it's a personal project, a hobby app or an internal tool
  • you need METAR and TAF only, for a manageable number of airports
  • you can cache properly and stay under 100 requests a minute
  • you want bulk data, where the cache files are the best option available anywhere
  • an outage would be an inconvenience rather than a problem for paying customers

One thing a commercial API can't honestly offer you is better weather. METARs and TAFs are issued by national weather services and airports, and every provider, including us, ultimately distributes the same observations. What you pay for is the service around the data.

When a commercial API is worth paying for

A commercial API makes sense when:

Customers depend on it. AviationWeather.gov is a public service with no service-level agreement, no paid tier, no published way to raise limits and no commercial support. That's reasonable for a free government service, but it's hard to put in front of an enterprise customer's procurement questions. SLAs for flight data explains what uptime commitments mean in practice.

You need weather alongside flight data. Weather is rarely the whole product. An EFB, dispatch tool or travel app usually also needs flight status, NOTAMs, airport details and live positions. Getting them from one provider means one key, one bill and consistent airport codes. SkyLink's aviation weather API sits next to NOTAMs, flight status and a 74,000-airport database.

You want a stable, decoded schema. SkyLink's METAR endpoint returns the raw report plus decoded fields, adds density altitude, pressure altitude and relative humidity, and documents its schema field by field.

You need more throughput than 100 requests a minute without managing cache files, or you can't risk an IP block. SkyLink's Pro plan allows 10 requests a second.

Here's the same lookup with SkyLink:

import requests

r = requests.get(
    "https://data.skylinkapi.com/v3.1/weather/metar/EGLL",
    headers={"x-api-key": API_KEY},
    params={"parsed": "true"},
    timeout=(5, 15),
)
r.raise_for_status()
m = r.json()
print(m["raw"])
print(m["parsed"]["flight_rules"], m["parsed"]["wind"], m["parsed"]["density_altitude"])

There's a trade-off to know about: SkyLink's METAR endpoint takes one airport per request, while AviationWeather.gov's ids parameter accepts many. For thousands of stations at once, the free cache files are still the more efficient tool. METAR vs TAF covers which endpoint suits which feature.

An airliner in flight at dusk, its contrails lit by the setting sun

Comparing the options

AviationWeather.govSkyLink API
PriceFreeFrom $19/month; free trial for personal projects
Rate limit100 requests/minute, then blocked2/second on Basic, 10/second on Pro; 429 without blocking
Batch queriesYes, multiple stations per request, plus cache filesOne airport per METAR or TAF request
HistoryAbout 30 daysCurrent reports
METAR and TAFRaw and decoded with flight category, worldwideRaw and decoded with flight category, plus density altitude and humidity
Other weatherPIREPs, SIGMETs, G-AIRMETs, CWAs, winds aloft (US-focused)PIREPs, AIRMET/SIGMET, winds aloft (US)
Flight data, NOTAMs, airportsNoYes, same key
Support and SLANonePriority support on every paid plan; 99.9% uptime SLA on Business (coming soon) and Enterprise
LicencePublic dataCommercial licence on paid plans

Getting started

If AviationWeather.gov does what you need, use the client above and you're done. If you need weather as part of a larger aviation product, the weather feature page and the METAR docs show what's available, and METAR and TAF explained covers how to read the reports. Plans start at $19 a month on the pricing page.