# Build a weather widget with free APIs

Page: https://free-web-services.com/guides/weather-widget/

A small web page where a visitor types a city and gets the current weather and a three-day forecast. It uses two free APIs from Open-Meteo, needs no API key and no server: the browser calls the APIs directly.

## What you need

[Open-Meteo](https://free-web-services.com/web-services/geo/weather/open-meteo.html) offers a forecast API and a geocoding API that turns a place name into coordinates. Both are free without a key and allow calls from any web page (CORS), so a plain HTML file is enough. The free use is for non-commercial projects; see the end of this guide for a commercial site.

## Step 1: find the city

The geocoding API searches places by name. `count=1` asks for the best match only. The answer has `latitude`, `longitude`, `name` and `country` for each result, or no `results` at all when nothing matches.

```sh
curl 'https://geocoding-api.open-meteo.com/v1/search?name=Amsterdam&count=1'
```

## Step 2: get the weather

The forecast API takes the coordinates and the values you want. `current` asks for the weather right now, `daily` for one value per day, and `timezone=auto` gives the days in the local time of the place. `weather_code` is a WMO weather code: 0 is a clear sky, 61 light rain, 95 a thunderstorm.

```sh
curl 'https://api.open-meteo.com/v1/forecast?latitude=52.37&longitude=4.89&current=temperature_2m,weather_code,wind_speed_10m&daily=temperature_2m_max,temperature_2m_min&timezone=auto&forecast_days=3'
```

## Step 3: the complete page

Save this as an HTML file and open it in a browser. The script looks up the city, fetches the forecast and writes the result as text, so nothing a visitor types can end up as HTML on the page.

```html
<form id="weather-form">
  <input id="city" placeholder="City, e.g. Amsterdam" required>
  <button>Show weather</button>
</form>
<p id="weather"></p>

<script>
const weatherCodes = {
  0: 'clear sky', 1: 'mainly clear', 2: 'partly cloudy', 3: 'overcast',
  45: 'fog', 48: 'fog', 51: 'light drizzle', 53: 'drizzle', 55: 'heavy drizzle',
  61: 'light rain', 63: 'rain', 65: 'heavy rain', 71: 'light snow', 73: 'snow',
  75: 'heavy snow', 80: 'rain showers', 81: 'rain showers', 82: 'heavy showers',
  95: 'thunderstorm'
};

async function findCity(name) {
  const url = 'https://geocoding-api.open-meteo.com/v1/search?count=1&name=' + encodeURIComponent(name);
  const data = await (await fetch(url)).json();
  if (!data.results) {
    throw new Error('No place found called ' + name);
  }
  return data.results[0];
}

async function getWeather(latitude, longitude) {
  const url = 'https://api.open-meteo.com/v1/forecast?latitude=' + latitude + '&longitude=' + longitude
    + '&current=temperature_2m,weather_code,wind_speed_10m'
    + '&daily=temperature_2m_max,temperature_2m_min&timezone=auto&forecast_days=3';
  return (await fetch(url)).json();
}

document.getElementById('weather-form').addEventListener('submit', async (event) => {
  event.preventDefault();
  const output = document.getElementById('weather');
  try {
    const city = await findCity(document.getElementById('city').value);
    const weather = await getWeather(city.latitude, city.longitude);
    const now = weather.current;
    const days = weather.daily.time.map((day, i) =>
      day + ': ' + weather.daily.temperature_2m_min[i] + ' to ' + weather.daily.temperature_2m_max[i] + ' °C');
    output.textContent = city.name + ', ' + city.country + ': ' + now.temperature_2m + ' °C, '
      + (weatherCodes[now.weather_code] || 'weather code ' + now.weather_code)
      + ', wind ' + now.wind_speed_10m + ' km/h. ' + days.join('; ') + '.';
  } catch (error) {
    output.textContent = error.message;
  }
});
</script>
```

## Going further

Show the weather where the visitor is: the browser's own `navigator.geolocation.getCurrentPosition()` gives coordinates, with the visitor's permission, and you can skip step 1.

Do not ask the forecast again on every page view. Keep the answer for a place for, say, 30 minutes, in `localStorage` or on your server; forecasts do not change by the minute.

For a commercial site, use [MET Norway Weather API](https://free-web-services.com/web-services/geo/weather/met-norway-weather-api.html): it is free also for commercial use, under an open licence that asks for attribution, a User-Agent that names your app and cached results, so call it from your server. For official US forecasts and weather alerts there is the [National Weather Service API](https://free-web-services.com/web-services/geo/weather/national-weather-service.html).

## The APIs in this guide

- [Open-Meteo](https://free-web-services.com/web-services/geo/weather/open-meteo.md)
- [MET Norway Weather API](https://free-web-services.com/web-services/geo/weather/met-norway-weather-api.md)
- [National Weather Service API](https://free-web-services.com/web-services/geo/weather/national-weather-service.md)

Updated November 1st, 2026
