A type-safe TypeScript/JavaScript library for the Open-Meteo Weather API. This library uses the JSON API format and transforms the data into an easy-to-use structure (for me at least) with full type safety.
If you need maximum performance, you should check out their official library which uses FlatBuffers. This library uses JSON over HTTP and focuses on developer experience and type safety.
- Fully Type-Safe: Response types automatically match your requested variables
- Transformed Data: Converts Open-Meteo's parallel arrays into arrays of objects
- Timestamps in Milliseconds: Unix timestamps converted to JavaScript milliseconds (ready for
new Date()) - Type-Safe Units: Units included for all variables with full type safety
# Using Bun
bun add @alanko0511/open-meteo-js
# Using npm
npm install @alanko0511/open-meteo-js
# Using pnpm
pnpm add @alanko0511/open-meteo-js
# Using Yarn
yarn add @alanko0511/open-meteo-jsimport { forecastAPI } from "@alanko0511/open-meteo-js";
const forecast = await forecastAPI({
latitude: 52.52,
longitude: 13.41,
hourly: ["temperature_2m", "precipitation", "wind_speed_10m"],
daily: ["temperature_2m_max", "temperature_2m_min"],
current: ["temperature_2m", "weather_code"],
});
// TypeScript knows the exact structure
console.log(forecast.hourly[0].temperature_2m); // number
console.log(forecast.hourly[0].precipitation); // number
console.log(forecast.daily[0].temperature_2m_max); // number
console.log(forecast.current.weather_code); // number
// Units are also type-safe
console.log(forecast.hourly_units.temperature_2m); // string (e.g., "°C")
console.log(forecast.daily_units.temperature_2m_max); // string
// These would be TypeScript errors:
// console.log(forecast.hourly[0].cloud_cover); // Error: not requested
// console.log(forecast.hourly_units.cloud_cover); // Error: not requestedThis library transforms the data from parallel arrays to arrays of objects:
Open-Meteo Format (parallel arrays):
{
"hourly": {
"time": [1234567890, 1234571490, ...],
"temperature_2m": [15.2, 15.5, ...],
"precipitation": [0, 0.1, ...]
}
}This Library (array of objects):
{
"hourly": [
{
"time": 1704067200000, // Unix timestamp in milliseconds
"temperature_2m": 15.2,
"precipitation": 0
},
{
"time": 1704070800000, // Unix timestamp in milliseconds
"temperature_2m": 15.5,
"precipitation": 0.1
}
],
"hourly_units": {
"temperature_2m": "°C",
"precipitation": "mm"
}
}Note: Time values are Unix timestamps in milliseconds (JavaScript standard). You can easily convert them to Date objects:
const date = new Date(forecast.hourly[0].time);const forecast = await forecastAPI({
latitude: 52.52,
longitude: 13.41,
hourly: ["temperature_2m"],
timezone: "Europe/Berlin",
temperature_unit: "fahrenheit",
wind_speed_unit: "mph",
precipitation_unit: "inch",
forecast_days: 7,
past_days: 1,
});You can use the commercial Open-Meteo API or self-hosted instances by providing configuration options:
When you provide an API key, the library automatically uses the commercial API endpoint (https://customer-api.open-meteo.com/v1):
const forecast = await forecastAPI(
{
latitude: 52.52,
longitude: 13.41,
hourly: ["temperature_2m"],
},
{
apiKey: "your-api-key-here",
}
);For self-hosted Open-Meteo instances, specify a custom base URL:
const forecast = await forecastAPI(
{
latitude: 52.52,
longitude: 13.41,
hourly: ["temperature_2m"],
},
{
baseUrl: "https://your-domain.com/v1",
}
);You can also customize the request timeout (defaults to 30 seconds):
const forecast = await forecastAPI(
{
latitude: 52.52,
longitude: 13.41,
hourly: ["temperature_2m"],
},
{
timeout: 60000, // 60 seconds
}
);temperature_2m- Temperature at 2 metersrelative_humidity_2m- Relative humidity at 2 metersdew_point_2m- Dew point at 2 metersapparent_temperature- Apparent temperatureprecipitation_probability- Precipitation probabilityprecipitation- Total precipitation (rain + showers + snow)rain- Rainshowers- Showerssnowfall- Snowfallsnow_depth- Snow depthweather_code- WMO Weather codepressure_msl- Sea level pressuresurface_pressure- Surface pressurecloud_cover- Total cloud covercloud_cover_low- Low cloud covercloud_cover_mid- Mid cloud covercloud_cover_high- High cloud covervisibility- Visibilityevapotranspiration- Evapotranspirationet0_fao_evapotranspiration- Reference evapotranspirationvapour_pressure_deficit- Vapour pressure deficitwind_speed_10m- Wind speed at 10mwind_speed_80m- Wind speed at 80mwind_speed_120m- Wind speed at 120mwind_speed_180m- Wind speed at 180mwind_direction_10m- Wind direction at 10mwind_direction_80m- Wind direction at 80mwind_direction_120m- Wind direction at 120mwind_direction_180m- Wind direction at 180mwind_gusts_10m- Wind gusts at 10mtemperature_80m- Temperature at 80mtemperature_120m- Temperature at 120mtemperature_180m- Temperature at 180msoil_temperature_0cm- Soil temperature at 0cmsoil_temperature_6cm- Soil temperature at 6cmsoil_temperature_18cm- Soil temperature at 18cmsoil_temperature_54cm- Soil temperature at 54cmsoil_moisture_0_1cm- Soil moisture 0-1cmsoil_moisture_1_3cm- Soil moisture 1-3cmsoil_moisture_3_9cm- Soil moisture 3-9cmsoil_moisture_9_27cm- Soil moisture 9-27cmsoil_moisture_27_81cm- Soil moisture 27-81cm
weather_code- WMO Weather codetemperature_2m_max- Maximum temperaturetemperature_2m_min- Minimum temperatureapparent_temperature_max- Maximum apparent temperatureapparent_temperature_min- Minimum apparent temperaturesunrise- Sunrise timesunset- Sunset timedaylight_duration- Daylight durationsunshine_duration- Sunshine durationuv_index_max- Maximum UV indexuv_index_clear_sky_max- Maximum UV index (clear sky)rain_sum- Rain sumshowers_sum- Showers sumsnowfall_sum- Snowfall sumprecipitation_sum- Precipitation sumprecipitation_hours- Precipitation hoursprecipitation_probability_max- Maximum precipitation probabilitywind_speed_10m_max- Maximum wind speedwind_gusts_10m_max- Maximum wind gustswind_direction_10m_dominant- Dominant wind directionshortwave_radiation_sum- Shortwave radiation sumet0_fao_evapotranspiration- Reference evapotranspiration
temperature_2m- Current temperaturerelative_humidity_2m- Current relative humidityapparent_temperature- Current apparent temperatureis_day- Is it day or nightprecipitation- Current precipitationrain- Current rainshowers- Current showerssnowfall- Current snowfallweather_code- Current weather codecloud_cover- Current cloud coverpressure_msl- Current sea level pressuresurface_pressure- Current surface pressurewind_speed_10m- Current wind speedwind_direction_10m- Current wind directionwind_gusts_10m- Current wind gusts
The response type adapts based on what variables you request:
// Request only temperature
const response1 = await forecastAPI({
latitude: 52.52,
longitude: 13.41,
hourly: ["temperature_2m"],
});
// Works:
// response1.hourly[0].temperature_2m
// response1.hourly_units.temperature_2m
// Type errors:
// response1.hourly[0].precipitation
// response1.hourly_units.precipitation
// Request temperature and precipitation
const response2 = await forecastAPI({
latitude: 52.52,
longitude: 13.41,
hourly: ["temperature_2m", "precipitation"],
});
// Works:
// response2.hourly[0].temperature_2m
// response2.hourly[0].precipitation
// response2.hourly_units.temperature_2m
// response2.hourly_units.precipitation
// Request only daily variables
const response3 = await forecastAPI({
latitude: 52.52,
longitude: 13.41,
daily: ["temperature_2m_max"],
});
// Works:
// response3.daily[0].temperature_2m_max
// Type errors:
// response3.hourly
// response3.currentUnits are automatically included for all requested variables and are also type-safe:
const forecast = await forecastAPI({
latitude: 52.52,
longitude: 13.41,
hourly: ["temperature_2m", "wind_speed_10m"],
temperature_unit: "fahrenheit",
wind_speed_unit: "mph",
});
console.log(forecast.hourly_units.temperature_2m); // "°F"
console.log(forecast.hourly_units.wind_speed_10m); // "mph"
// forecast.hourly_units.precipitation // Type error - not requestedAll time values are returned as Unix timestamps in milliseconds (JavaScript standard):
const forecast = await forecastAPI({
latitude: 52.52,
longitude: 13.41,
hourly: ["temperature_2m"],
});
// Time is a number (milliseconds since Unix epoch)
const timestamp = forecast.hourly[0].time; // e.g., 1704067200000
// Convert to Date when needed
const date = new Date(timestamp);
console.log(date.toISOString()); // "2024-01-01T00:00:00.000Z"
// Or use directly with Date methods
const hours = new Date(forecast.hourly[0].time).getHours();The library uses ky for HTTP requests, which throws HTTPError for non-2xx responses:
import { HTTPError } from "ky";
try {
const forecast = await forecastAPI({
latitude: 52.52,
longitude: 13.41,
hourly: ["temperature_2m"],
});
} catch (error) {
if (error instanceof HTTPError) {
// API error (e.g., invalid coordinates, rate limiting)
console.error("API error:", error.response.status);
const body = await error.response.json();
console.error("Reason:", body.reason);
} else {
// Network or other errors
console.error("Request failed:", error);
}
}