A tinted screenshot showing a preview of the app with weather in Brooklyn, New York.

Weather web app: web API tutorial

Finished project

I’m a big fan of web APIs. I’ve made my own, I’ve used them to make online bots; they are fun to play with and can give you inspiration for new projects to work on.

I wrote the original weather web app tutorial about five years ago using Mozilla’s Thimble online code editor. Now that Mozilla is moving Thimble projects to Glitch, I decided to rewrite it. (I’m also a big fan of Glitch.)

How nice.

Let’s begin

This tutorial requires you to have at least a basic understanding of HTML, CSS, and JavaScript. We are going to cover a few concepts:

  • Some basic HTML and CSS
  • JavaScript and AJAX, which is pretty much just HTML, CSS, and JavaScript working together
  • JSON, and JSONP, two formats used for transferring information on the web
  • Signing up for an API key, which you need to be able to make API calls
  • And, of course, making API calls

We will be using Glitch to create and host our web app. Glitch is a really amazing site and a community, and I recommend checking it out outside of this tutorial. Note that you don’t need to sign up for an account to follow along, but your app will be removed after five days.

Let’s start by creating a new web app on Glitch.

Take a moment to read through the README.md file that shows up when you create a new app on Glitch. You can later edit this file to talk about the app you made, but for now let’s keep it as it is.

Let’s go ahead and open index.html in the left sidebar and lay out the structure of our app.

I’d like the page to show the name of the city, the weather, a little information about where we got our data from, and a link to the image we’re using to give credit to its author.

Let’s remove the h1 and p tags and replace them with the following HTML.

  <h1 id="city">Loading...</h1>
  <p id="weather"></p>

We can use the h1 tag for the city name, p tag for weather information, and the footer for credits for our app.

So far so good. But before we can move to the next section, we need to learn a bit more about APIs and API keys.

Keys and secrets

We are going to be using three services in our app:

  • we will use FreeGeoIP.app to get our app’s visitor’s location
  • then we’ll use OpenWeatherMap‘s API to get weather in that location
  • and finally, we’ll search Flickr for images that match the location and weather

Generally speaking, when a website offers an API, they can either let anyone use it without restrictions, or they can enforce certain rules, such as how many API calls you can make per minute, how much data, or what kind of data you can access. To use such restricted APIs you might have to sign up for an account with the API provider, and sometimes also obtain an API key, an API secret, an app ID, an API token, or a combination of these. They all work much like passwords, confirming you are the authorized user of the API. In some case you might also be able to set up a list of domains that are allowed to use the API with your specific API key.

To get an API key from Flickr, visit their App Garden and choose the non-commercial key. After you fill out the application, you should receive your API key (and an API secret, which you won’t need for this tutorial). You can also go to your apps page to get the key later.

Similarly, you will need to sign up for an account at OpenWeatherMap. You can see your API key in your account settings.

And FreeGeoIP.app happens to provide a free tier that doesn’t require an API key.

Now that we have our API keys we can go back to our app in Glitch.

An introduction to “fetch”

We are going to make our API calls using the fetch JavaScript method. Feel free to read through the documentation, but let me show you a quick example.

In the Glitch editor, select the script.js file in the left sidebar. You can replace the file’s content with the following JavaScript code:

  .then((response) => response.json())
  .then((data) => console.log(data));

Let’s go through this code line by line to see what’s happening here. First, make a request to the HelloSalut API.


We will then take the response we receive and parse it into a JSON object.

.then((response) => response.json())

And finally, we can use this JSON object to inspect the returned data.

.then((data) => console.log(data));

You can also open the URL I used for the API call directly in your browser to see what the API returns, which is the following text:


(The language changes based on your browser’s settings and your location. This is what you’d see if your browser’s language is set to English, or you’re in an English speaking country.)

The Flickr API works a little bit differently and instead of JSON it works with JSONP (JSON with Padding). The difference between these two formats is that JSONP returns a name of a function in its response and this function will handle the response data in your code.

This will make more sense as we work through the project, no worries.

Let’s put our JavaScript API example code inside a function and call it makeApiCall, so that we can reuse it. We just need to remove the specific URL and pass it as an argument instead. And we are going to define our helper function as an async function, to make the syntax a bit easier to read.

Your makeApiCall function should look like this:

const makeApiCall = async (url) => {
    let results = [];
    try {
        const resp = await fetch(url);
        return await resp.json();
    } catch (error) {
        return results;

And now you can use it to make an API call and handle the returned data.

makeApiCall('https://stefanbohacek.com/hellosalut/?mode=auto').then(data => {
  document.getElementById('city').innerHTML = data.hello;  
  document.getElementById('weather').innerHTML = data.code;  


Now we can replace the stefanbohacek.com URL with https://freegeoip.app/json/.

makeApiCall('https://freegeoip.app/json/').then(data => {
  document.getElementById('city').innerHTML = data.city;  

You can click the Show button above the code editor to preview your app.

Quick note here. If you’re using an ad-blocking browser plugin, it might block requests to APIs that detect user’s location. If you run into this, you will either need to disable the plugin on your page, or you can try finding a different service.

Not a bad start.

You can also use console.log(data) inside your callback function to see what information the returned data object has. (See how to open your browser console.)

- city
- country_code
- country_name
- ip
- latitude
- longitude
- metro_code
- region_code
- region_name
- time_zone
- zip_code

We can use the latitude and longitude information to call the OpenWeatherMap API and ask for weather in that location. (You can find your OpenWeatherMap API key here.)

makeApiCall('https://freegeoip.app/json/').then(data => {
  document.getElementById('city').innerHTML = `${data.city}, ${data.region_name}`

  makeApiCall(`https://api.openweathermap.org/data/2.5/weather?lat=${data.latitude}&lon=${data.longitude}&units=imperial&APPID=YOUR_OPENWEATHERMAP_APP_ID`).then(data => {
    document.getElementById('weather').innerHTML = data.weather[0].description;  

Look at that, we are nearly there. Let’s have a look at Flickr now.

As I said before, Flickr’s API uses JSONP, or JSON with Padding. There is a few ways how to handle JSONP responses, here I am going to dynamically add a <script> tag that will load the API as if it was a script file and run the function that handles the data.

const loadBackground = (latitude, longitude, weather) => {
    let scriptElement = document.createElement('script');
    scriptElement.src = `https://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=YOUR_FLICKR_API_KEY&lat=${latitude}&lon=${longitude}&accuracy=1&tags=${weather}&sort=relevance&extras=url_l&format=json`;

If you open the URL we are using for the script tag in your browser, you will see that this script is calling a function called jsonFlickrApi and passes the images to it. So let’s add our jsonFlickrApi function now. (Your Flickr API key can be found here.)

const jsonFlickrApi = (data) => {
  const photo = data.photos.photo[0];
  document.body.style.backgroundImage = `url('${photo.url_l}')`;

Again, you can use console.log(data) for this code to make sense, but all we’re doing is accessing the first photo in the data.photos object that Flickr returned and setting it as a background for our page.

Now let’s add the loadBackground function inside the callback function for our second API call. We should also define variables to store some of the API data so that we can pass it to other functions. Something like this will do the trick.

makeApiCall('https://location-weather-api.glitch.me/weather?api_key=1c66c7e9-129e-49b1-95de-f4f5d706d914').then(data => {
  const location = `${data.location.city}, ${data.location.region}`;
  const weather = data.weather.weather[0].main;
  const weatherDescription = data.weather.weather[0].description;
  const temperature = data.weather.main.temp;

  document.getElementById('city').innerHTML = location;
  document.getElementById('weather').innerHTML = `${Math.round(temperature)}°F, ${weatherDescription}`;

  makeApiCall(`https://location-weather-api.glitch.me/background?api_key=1c66c7e9-129e-49b1-95de-f4f5d706d914&weather=${weather}&latitude=${data.location.lat}&longitude=${data.location.lon}`).then(data => {
    const imageSourceLink = document.getElementById("image-source");

    if (data && data.photos && data.photos.pages > 0) {
    const photo = data.photos.photo.filter(photo => photo.url_l)[0];

    document.body.style.backgroundImage = `url('${photo.url_l}')`;
    } else {
      document.body.style.backgroundImage =


We just need to add a little bit of CSS to make the background stretch across the whole page without repeating. Also, we can make the text stand out from the background by setting the color to white and giving it a subtle shadow. This will do the trick.

html, body{
  height: 100%;
  overflow: hidden;

  background-size: cover;
  background-position: center;
  font-family: sans-serif;
  color: white;
  text-shadow: 1px 1px 10px rgba(0, 0, 0, 0.4);  

You just made a nice little weather web app, nicely done! You can play around with the styles, make the text larger, see other ways to make it stand out from the background, maybe show more details on the weather, or show a random photo rather than the first one. You could also look into Geolocation API which is supported by many browsers.

I made my own weather web app (source code) if you’d like to see some inspiration. Note that I made my own API that calls the other APIs I used in this tutorial. This way I can keep my API keys private, and add more features later, like caching. (Look out for a follow up tutorial!)

If you get stuck during this tutorial, feel free to reach out either through email or on Twitter, I’ll be happy to help. And be sure to share what you made with me!

More tutorials

A tinted, zoomed in screenshot of a JSON object showing server information about a Mastodon instance.
A tinted screenshot of two charts, one showing the popularity of various fediverse platforms (with Mastodon far ahead of the rest), and the other chart showing distribution of domain creation dates, mostly clustered around 2023.
A tinted screenshot showing the @mtaupdates Mastodon profile and a few example posts with subway status alerts.

💻 Browse all