Python Windy API package for interacting with the Windy API. Currently only supports access to the point forecast API.
- Point Forecast API: Get detailed weather forecasts for any geographic location using latitude/longitude coordinates
- Multiple Weather Models: Support for 7+ weather forecast models including GFS, ICON EU, GFS Wave, NAM regional models, and CAMS air quality
- Comprehensive Parameters: Access 20+ weather parameters including temperature, wind, precipitation, humidity, clouds, pressure, CAPE, and more
- Automatic Validation: Built-in parameter validation ensures only compatible parameters are requested for each model
- Async Support: Full async/await support for concurrent API requests with
get_point_forecast_async() - Type Safety: Strongly typed with Pydantic models for reliable data validation and IDE autocomplete
- Intuitive Data Access: Clean accessor pattern for accessing forecast data - use
response.temp["surface"] - Clean Representations: Response objects display in a clean, readable format showing only high-level parameters
- Error Handling: Clear error messages and exceptions for robust application development
python -m pip install windy_apiFrom source:
git clone https://github.com/stedonnelly/windy-api
cd windy-api
python -m pip install .from windy_api import WindyAPI
# Initialize the client with your API key
api = WindyAPI(api_key="your_api_key_here")
# Get point forecast for San Francisco
response = api.get_point_forecast(
latitude=37.7749,
longitude=-122.4194,
model="gfs",
parameters=["temp", "wind"]
)
# View the response structure
print(response)
# WindyForecastResponse(
# timestamps=37 entries,
# parameters=[temp, wind]
# )
# Access forecast data using clean accessor pattern
print(f"Timestamps: {response.ts}")
print(f"Temperature data: {response.temp['surface']}")
print(f"Temperature unit: {response.temp.units}")
print(f"Available levels: {response.temp.levels()}")
# Access wind components
print(f"Wind U component: {response.wind.u['surface']}")
print(f"Wind V component: {response.wind.v['surface']}")
print(f"Wind unit: {response.wind.u.units}")The following weather forecast models are supported:
gfs- Global Forecast System (default)iconeu- ICON EU regional modelgfs_wave- GFS Wave modelnamconus- NAM CONUS regional modelnamhawaii- NAM Hawaii regional modelnamalaska- NAM Alaska regional modelcams- CAMS air quality model
Common weather parameters you can request:
temp- Temperaturewind- Wind speed and direction (returnswind_uandwind_vcomponents)windGust- Wind gustsdewpoint- Dew point temperatureprecip- PrecipitationconvPrecip- Convective precipitationsnowPrecip- Snow precipitationcape- Convective Available Potential Energypressure- Atmospheric pressurerh- Relative humiditylclouds,mclouds,hclouds- Low/medium/high cloudsgh- Geopotential heightptype- Precipitation type
Upon submitting a request to the Windy API the request is validated. If a parameter is requested for a model that does not support it, the incompatible parameters will automatically be removed from the request on validation.
The response object provides a clean, intuitive accessor pattern for retrieving forecast data:
For parameters with multiple levels (e.g., temperature at different altitudes):
# Access data at specific levels
temp_surface = response.temp["surface"] # Temperature at surface
temp_850h = response.temp["850h"] # Temperature at 850 hPa
# Get the unit (same across all levels)
print(response.temp.units) # "K" (Kelvin)
# List all available levels
print(response.temp.levels()) # ["surface", "1000h", "950h", ...]
# Iterate over all levels
for level, data in response.temp.items():
print(f"{level}: {data}")For parameters that only have surface data:
# Access values and units directly
precip_values = response.precip.values
precip_unit = response.precip.units
pressure_values = response.pressure.values
pressure_unit = response.pressure.unitsSome parameters have multiple components:
# Wind has u (east-west) and v (north-south) components
wind_u = response.wind.u["surface"]
wind_v = response.wind.v["surface"]
print(response.wind.u.units) # "m*s-1"
# Waves have height, period, and direction
wave_height = response.waves.height.values
wave_period = response.waves.period.values
wave_direction = response.waves.direction.values
print(response.waves.height.units) # "m"# Request multiple weather parameters
response = api.get_point_forecast(
latitude=40.7128,
longitude=-74.0060,
model="gfs",
parameters=["temp", "dewpoint", "pressure", "rh", "precip"]
)
# View available parameters
print(f"Available parameters: {response.available_parameters()}")
# Access each parameter using the clean accessor pattern
for i, timestamp in enumerate(response.ts):
print(f"Time: {timestamp}")
print(f" Temperature: {response.temp['surface'][i]} {response.temp.units}")
print(f" Dewpoint: {response.dewpoint['surface'][i]} {response.dewpoint.units}")
print(f" Pressure: {response.pressure.values[i]} {response.pressure.units}")
print(f" Relative Humidity: {response.rh['surface'][i]} {response.rh.units}")
print(f" Precipitation: {response.precip.values[i]} {response.precip.units}")# Wind returns u and v components
response = api.get_point_forecast(
latitude=51.5074,
longitude=-0.1278,
model="gfs",
parameters=["wind", "windGust"]
)
# Access wind components using the accessor pattern
wind_u_data = response.wind.u["surface"] # East-west component
wind_v_data = response.wind.v["surface"] # North-south component
wind_gust_data = response.windGust.values # Wind gusts
# Get units
print(f"Wind unit: {response.wind.u.units}")
print(f"Gust unit: {response.windGust.units}")
# Check available levels for wind
print(f"Available wind levels: {response.wind.u.levels()}")import asyncio
from windy_api import WindyAPI
async def get_forecasts():
api = WindyAPI(api_key="your_api_key_here")
# Fetch multiple locations concurrently
responses = await asyncio.gather(
api.get_point_forecast_async(37.7749, -122.4194, "gfs", ["temp"]),
api.get_point_forecast_async(40.7128, -74.0060, "gfs", ["temp"]),
api.get_point_forecast_async(51.5074, -0.1278, "gfs", ["temp"])
)
return responses
# Run the async function
responses = asyncio.run(get_forecasts())import os
from dotenv import load_dotenv
from windy_api import WindyAPI
# Load API key from .env file
load_dotenv()
api = WindyAPI(api_key=os.getenv("WINDY_API_KEY"))
response = api.get_point_forecast(
latitude=48.8566,
longitude=2.3522,
model="iconeu", # Use ICON EU model for Europe
parameters=["temp", "precip", "wind"]
)from httpx import HTTPStatusError
try:
response = api.get_point_forecast(
latitude=37.7749,
longitude=-122.4194,
model="gfs",
parameters=["temp"]
)
except HTTPStatusError as e:
print(f"API request failed: {e.response.status_code}")
print(f"Response: {e.response.text}")
except ValueError as e:
print(f"Invalid parameters: {e}")To use this library, you need a Windy API key. Visit Windy API to register and obtain your API key.
Important: This library is not affiliated with or endorsed by Windy.com. It is an unofficial Python wrapper for the Windy Map & Point Forecast API.
By using this library, you agree to comply with all of Windy's official Terms of Use for their Map & Point Forecast API. This wrapper does not modify or relax any of Windy's terms — it simply provides Python bindings for easier integration.
- You must keep your API key confidential — Never commit it to GitHub, share it publicly, or embed it in client-side applications
- Private Application keys must be held exclusively and cannot be shared with third parties
- Use environment variables to store your key securely (see example above)
From Windy's Terms: "API Keys for the Private Application are considered confidential and must be held exclusively. Allowing use of an API Key to a Private Application by any third party is forbidden. Usage of an API Key to a Private Application by any third party shall be considered a material breach of the Agreement."
Windy explicitly prohibits storing, extracting, or creating derivative weather databases:
- ❌ No long-term storage of weather data
- ❌ No creating weather databases or derived datasets
- ❌ No bulk downloading or archiving forecast data
- ❌ No reconstructing original meteorological model data
From Windy's Terms: "Users cannot store, extract, modify, distribute, use the weather data or other content of the Services, create any weather works or databases derived therefrom"
If you build an application that displays weather data to end users, you must include:
- The Windy logo (unscaled, 100% opacity, clickable with hyperlink to https://www.windy.com)
- Text attribution: "Contains data from the Windy database"
- Additional data source credits in Help or About sections
Example Attribution (HTML):
<a href="https://www.windy.com" target="_blank">
<img src="https://www.windy.com/img/logo300.png" alt="Windy Logo" />
</a>
<p>Contains data from the Windy database</p>You cannot create applications that:
- ❌ Replicate Windy's services or aim to compete directly with Windy
- ❌ Provide Windy API data as a service to third parties
- ❌ Act as an API proxy or forwarding service
From Windy's Terms: "The User is not allowed to create User Applications that would aim to replicate the Services or other services of the Provider."
- Trial Version: 500 sessions/day maximum (development purposes only, not for production)
- Professional Version: 10,000 sessions/day (expandable upon request, requires paid plan)
The code in this repository is licensed under the MIT License, but the Windy API data is not. All weather data remains the property of Windy.com and is governed by their Terms of Use.
- Use environment variables for API keys (never hardcode them)
- Cache responsibly — keep cached data in-memory or with very short TTL
- Add attribution if you display data to users
- Respect rate limits — implement backoff strategies for failed requests
- Review Windy's terms before deploying to production
See CONTRIBUTING.md for instructions on how to contribute.
Distributed under the terms of the MIT license.