agentsclimarketplace

Open meteo api

Skill NanookAI/open-meteo-api/skills/open-meteo-api

Claude Code skill for the free Open-Meteo API — weather forecasts, current conditions, historical weather, and air quality, no API key required

Install
npx -y skills add NanookAI/open-meteo-api --skill open-meteo-api

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Fetch weather forecasts, current conditions, historical weather, and air quality with the free Open-Meteo API (no API key). Use for any weather, temperature, rain, wind, UV, sunrise/sunset, air quality, or climate data task, even if Open-Meteo isn't mentioned.

SKILL.md

9.9 KB, as published. Nobody here has run it

Open-Meteo API

Open-Meteo is a free, open-source weather API. No API key, no signup for non-commercial use (fair-use limit ~10,000 requests/day). It blends national weather models (NOAA GFS, DWD ICON, ECMWF, Météo-France, JMA...) and auto-selects the best model per location.

Fastest path: bundled script

For the common case — current conditions and a daily forecast for a place — run the bundled zero-dependency script (Python 3.8+, stdlib only) instead of composing API calls by hand:

python3 scripts/get_weather.py "Taipei"                 # current + 3-day forecast
python3 scripts/get_weather.py "Paris" --country FR     # disambiguate place name
python3 scripts/get_weather.py --lat 25.05 --lon 121.53 # skip geocoding
python3 scripts/get_weather.py "Tokyo" --days 7 --json  # raw JSON for parsing
python3 scripts/get_weather.py "Denver" --fahrenheit

It geocodes, fetches, and decodes WMO weather codes into readable text. Exit codes: 0 success, 1 place not found, 2 API/network error.

Call the API directly (below) for anything the script doesn't cover: hourly data, specific variables (UV, soil, radiation...), historical weather, air quality, marine, or non-Python environments.

Typical workflow (direct API)

Most user questions name a place, but the API takes coordinates:

  1. Geocode the place name → latitude/longitude (Geocoding API below). Skip this step if coordinates are already known.
  2. Fetch weather from the forecast (or other) endpoint.
  3. Interpret weather_code using the WMO table below.

Quick reference

TaskEndpoint
Forecast / current weatherhttps://api.open-meteo.com/v1/forecast
Place name → coordinateshttps://geocoding-api.open-meteo.com/v1/search
Historical weather (1940→now)https://archive-api.open-meteo.com/v1/archive
Air quality (PM2.5, AQI, pollen)https://air-quality-api.open-meteo.com/v1/air-quality
Marine (waves, sea temp)https://marine-api.open-meteo.com/v1/marine
Elevation lookuphttps://api.open-meteo.com/v1/elevation

All endpoints: GET with query parameters, JSON responses, HTTPS, CORS enabled. See references/other-apis.md for historical/air-quality/marine/elevation/flood/climate details.

Forecast API

GET https://api.open-meteo.com/v1/forecast

Key parameters:

ParameterMeaning
latitude, longitudeRequired. WGS84 decimal degrees.
currentComma-separated variables for current conditions
hourlyComma-separated hourly variables
dailyComma-separated daily aggregations (requires timezone)
timezoneauto (recommended — resolves from coordinates) or IANA name like Asia/Taipei. Default is GMT.
forecast_days0–16 (default 7)
past_days0–92 — include recent past days in the same response
start_date, end_dateYYYY-MM-DD, alternative to forecast_days/past_days
temperature_unitcelsius (default) or fahrenheit
wind_speed_unitkmh (default), ms, mph, kn
precipitation_unitmm (default) or inch

Most-used variables (full list in references/weather-variables.md):

  • current: temperature_2m, relative_humidity_2m, apparent_temperature, precipitation, weather_code, wind_speed_10m, wind_direction_10m, is_day
  • hourly: temperature_2m, precipitation_probability, precipitation, weather_code, wind_speed_10m, relative_humidity_2m, cloud_cover, uv_index
  • daily: weather_code, temperature_2m_max, temperature_2m_min, precipitation_sum, precipitation_probability_max, sunrise, sunset, uv_index_max, wind_speed_10m_max

Example: current weather

GET https://api.open-meteo.com/v1/forecast?latitude=25.05&longitude=121.53
    &current=temperature_2m,relative_humidity_2m,apparent_temperature,precipitation,weather_code,wind_speed_10m
    &timezone=auto
{
  "latitude": 25.06, "longitude": 121.52,
  "timezone": "Asia/Taipei", "utc_offset_seconds": 28800, "elevation": 12.0,
  "current_units": {"temperature_2m": "°C", "wind_speed_10m": "km/h", "weather_code": "wmo code"},
  "current": {
    "time": "2026-07-03T15:00", "interval": 900,
    "temperature_2m": 31.8, "relative_humidity_2m": 63,
    "apparent_temperature": 37.6, "precipitation": 0.0,
    "weather_code": 1, "wind_speed_10m": 5.1
  }
}

Example: 3-day daily forecast

GET https://api.open-meteo.com/v1/forecast?latitude=25.05&longitude=121.53
    &daily=weather_code,temperature_2m_max,temperature_2m_min,precipitation_sum,precipitation_probability_max,sunrise,sunset
    &timezone=auto&forecast_days=3
{
  "daily_units": {"temperature_2m_max": "°C", "precipitation_sum": "mm"},
  "daily": {
    "time": ["2026-07-03", "2026-07-04", "2026-07-05"],
    "weather_code": [95, 95, 96],
    "temperature_2m_max": [33.6, 33.5, 33.2],
    "temperature_2m_min": [26.0, 25.7, 26.1],
    "precipitation_sum": [1.5, 4.3, 4.2],
    "precipitation_probability_max": [100, 99, 82],
    "sunrise": ["2026-07-03T05:08", "..."],
    "sunset": ["2026-07-03T18:47", "..."]
  }
}

Response shape: hourly/daily data comes as parallel arraystime[i] pairs with temperature_2m_max[i]. Units for every requested variable are echoed in *_units. Timestamps are ISO 8601 in the requested timezone (local time when timezone=auto), without a UTC offset suffix.

Geocoding API

GET https://geocoding-api.open-meteo.com/v1/search?name=Taipei&count=5&language=en&format=json

Parameters: name (place name, fuzzy for ≥3 chars), count (1–100, default 10), language (lowercase code: en, zh, ja, de...).

{
  "results": [
    {
      "id": 1668341, "name": "Taipei",
      "latitude": 25.05306, "longitude": 121.52639,
      "country": "Taiwan", "country_code": "TW",
      "admin1": "Taiwan", "timezone": "Asia/Taipei", "population": 7871900
    }
  ]
}

Pick the first result unless the user's context suggests otherwise (check country/admin1 when names are ambiguous, e.g. Paris TX vs Paris FR; results are ordered by relevance and population). No results key at all means no match — retry with a simpler query (city name only, no district/street; the geocoder matches localities, not addresses).

WMO weather codes

weather_code values (WMO 4677 subset) — condensed table:

CodeMeaning
0Clear sky
1 / 2 / 3Mainly clear / partly cloudy / overcast
45 / 48Fog / depositing rime fog
51 / 53 / 55Drizzle: light / moderate / dense
56 / 57Freezing drizzle: light / dense
61 / 63 / 65Rain: slight / moderate / heavy
66 / 67Freezing rain: light / heavy
71 / 73 / 75Snowfall: slight / moderate / heavy
77Snow grains
80 / 81 / 82Rain showers: slight / moderate / violent
85 / 86Snow showers: slight / heavy
95Thunderstorm
96 / 99Thunderstorm with slight / heavy hail

Code examples

import requests

def get_weather(place: str) -> dict:
    geo = requests.get(
        "https://geocoding-api.open-meteo.com/v1/search",
        params={"name": place, "count": 1}, timeout=10,
    ).json()
    if "results" not in geo:
        raise ValueError(f"Place not found: {place}")
    loc = geo["results"][0]
    r = requests.get(
        "https://api.open-meteo.com/v1/forecast",
        params={
            "latitude": loc["latitude"], "longitude": loc["longitude"],
            "current": "temperature_2m,weather_code,wind_speed_10m",
            "daily": "temperature_2m_max,temperature_2m_min,precipitation_probability_max",
            "timezone": "auto",
        }, timeout=10,
    )
    r.raise_for_status()
    return r.json()
const geo = await (await fetch(
  `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(place)}&count=1`
)).json();
const { latitude, longitude } = geo.results[0];
const weather = await (await fetch(
  `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}` +
  `&current=temperature_2m,weather_code&timezone=auto`
)).json();

Errors

Errors return HTTP 400 with {"error": true, "reason": "<message>"} — e.g. missing longitude, an unknown variable name, or an out-of-range date. Read reason; it states exactly which parameter is wrong.

Practical tips

  • Request only the variables you need — response size and quota cost scale with variable count and day range.
  • Always pass timezone=auto when using daily (required) or showing times to a user; otherwise times are GMT and daily aggregation boundaries are wrong.
  • "Will it rain?" → prefer precipitation_probability (hourly) or precipitation_probability_max (daily) over raw precipitation amounts.
  • Yesterday/last week → use past_days on the forecast endpoint. Older than ~3 months → use the archive endpoint (see references/other-apis.md). Archive data lags real time by ~5 days.
  • The returned latitude/longitude are the model grid cell center (~1–11 km grid), so they differ slightly from the request — that's normal.
  • interval in current is the data refresh interval in seconds; current conditions are model data, not station readings.
  • Batch multiple locations in one call: latitude=25.05,24.14&longitude=121.53,120.68 returns a JSON array of result objects.
  • Free tier is non-commercial use only; commercial use needs a paid API key (&apikey= on customer- prefixed endpoints). No key is needed otherwise.

For the complete variable catalog read references/weather-variables.md; for historical, air-quality, marine, elevation, flood, climate, and ensemble endpoints read references/other-apis.md.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.