Using Geolocation and Open Exchange Rate to Convert Currency

The Internet is many things; one of them just happens to be a global e-commerce platform. Since the early 2000s, one of the Internet's many promises has been the immediate expansion of a company's customer base. Local companies are no longer bound to the tether of their physical location; they can serve customers across their country and even around the world.

But with growth comes complexity. Serving a global audience requires a company to adapt their systems for a global economy. That could be a daunting task even five years ago, but it is now relatively simple with services like ipdata and Open Exchange Rates.

In this article, you will build a simple page that converts product prices to the visitor's local currency in real time using the ipdata and Open Exchange Rates APIs.

Getting Started

We need API keys before we can do anything. If you don't already have an ipdata account, sign up for a free account. Next, create an account at Open Exchange Rates. Their pricing page does not prominently display their free plan, but don't fear—it's forever free.

For this article, we'll build a simple web page that uses plain ‘ol JavaScript to display a list of products and their respective prices in the visitor's currency. The only library you'll use in this project is the money.js library for converting our product price to the visitor's local currency.

The overall process is simple:

  • fetch product data (it's just a static .json file to emulate a local service)
  • fetch the visitor's location data from ipdata's API
  • fetch the currency exchange information from Open Exchange Rates
  • display the product data with the converted currency values

Because the page issues HTTP requests, it must be served from an HTTP server. Any HTTP server will do. If you don't have easy access to one, the (lite-server NPM package)[https://github.com/johnpapa/lite-server] can get you up and running with a simple HTTP server with no configuration.

Building the Product Page

You'll emulate the products “service” with a simple JSON file. Create a new file called data.json, and type the following:

[
    { "name" : "Guitar", "price" : 1500 },
    { "name" : "Piano", "price" : 5000 },
    { "name" : "Cello", "price" : 15000 }
]

Next, create an HTML file with the following markup:

<html lang="en">
<!DOCTYPE html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Musical Instruments</title>
</head>
<body>


    <script src="https://openexchangerates.github.io/money.js/money.min.js"></script>
</body>
</html>

As you can see, the only dependency in this page is the Open Exchange Rate’s money.js library. Of course, you could use the respective JavaScript libraries for the ipdata and Open Exchange Rate services, but you will directly interact with those web APIs using fetch().

Now you need someplace to display the product list. You could build everything using JavaScript, but doing so without a UI-focused library is an exercise in tedium. Instead, add the following table to the body of the page. Later, you will programmatically insert rows into the table.

<table id="product-table">
    <thead>
        <tr>
            <th>Name</th>
            <th>Price</th>
        </tr>
    </thead>
    <tbody></tbody>
</table>

Fetching Data

Now it’s time to fetch your data. For the sake of simplicity, use async/await when calling fetch(). All modern browsers support async/await, and it saves you from the Promise callback hell that is associated with multiple asynchronous operations.

Begin by defining an immediately invoked asynchronous function, as shown in the following code:

(async function() {
    // all of our JavaScript code here
})();

The Fetch API is a huge improvement over XMLHttpRequest, but it can still be tedious to use when working with HTTP resources that return JSON. However, a helper function that fetches data and returns the resulting parsed JavaScript object can be beneficial. The following fetchJson() function does just that:

async function fetchJson(url) {
    let res = await fetch(url);
    return await res.json();
}

It simply fetches the provided URL and uses the response object’s json() method to transform the JSON structure into a usable JavaScript object.

Next, fetch your data with the following three lines:

let products = await fetchJson('data.json');
let location = await fetchJson('https://api.ipdata.co?api-key=<YOUR_API_KEY>&fields=currency');
let exchange = await fetchJson('https://openexchangerates.org/api/latest.json?app_id=<YOUR_API_KEY>');

This code fetches the product data, the visitor’s location information, and the latest currency exchange information. This code is straight-forward, but let's focus on the ipdata request.

First, ipdata’s API returns location-based information about the device that issued the request. In this case, that is the user’s browser, and that is exactly what we want. Remember, you are converting product prices to the user’s currency based upon their current location, and you automatically get that with just issuing a "blank" request.

Second, you don’t need to know everything about the user’s location; the only thing you really care about is the currency information. Therefore, use the fields query parameter to tell the API that you only want the currency object in the returned JSON structure. This saves bandwidth and resources on the device.

Displaying the Products

Before using the money.js library, you need to initialize its base and rates information. It’s just takes two lines of code using data from the Open Exchange Rates API:

fx.base = exchange.base;
fx.rates = exchange.rates;

Next, get a reference to the <tbody/> in the table and start iterating over the products, like this:

let tbody = document.getElementById('product-table').tBodies[0];

products.forEach(function(p) {
   // more code here    
});

The goal here is to use the tbody object to create a new row for each iteration through the products array. While that sounds like a lot of tedious DOM code, it’s actually quite simple. The API for working with tables and their related objects are very intuitive, as shown in the following example:

products.forEach(function(p) {
    let row = tbody.insertRow();

    let nameCell = row.insertCell();
    let priceCell = row.insertCell();

    nameCell.innerHTML = p.name;
    // price cell here    
});

In this code, you create a new row using insertRow(). This automatically creates the resulting <tr/> element and appends it to the <tbody/> element. Using the newly created row object, you can then create the cells for that row using the insertCell() method. This method automatically creates the necessary <td/> element and appends it to the row. Don’t you wish the rest of the DOM API is as easy to use?

The final piece of this puzzle is the price. The money.js library provides multiple ways to convert values from one currency to another. For this project, use the fluent approach, shown below:

fx(price).from(‘FROM_CURRENCY_CODE’).to(‘TO_CURRENCY_CODE’)

For this project, the user is whoever is viewing the page (you, in this case). So, if you’re going to convert the price to your own currency, FROM_CURRENCY_CODE needs to be a currency that is not yours. This example uses the euro (code: EUR) as the starting currency, but feel free to use whichever currency you want. To plug in your values, the code will look like the following:

fx(p.price).from('EUR').to(location.currency.code).toFixed(2);

Conversions rarely result in clean numbers; chances are very good that the resulting amount will have more than two decimal places. Therefore, call toFixed() to constrain the result to two decimal places.

But converting the price is only part of the solution; you also need to include the correct currency symbol. Thankfully, you already have that from the ipdata API. Just use the currency.symbol property and concatenate it with the conversion result, like this:

priceCell.innerHTML = location.currency.symbol + '' + 
    fx(p.price).from('EUR').to(location.currency.code).toFixed(2);

So the JavaScript code in its entirety is the following:

(async function() {
    async function fetchJson(url) {
        let res = await fetch(url);

        return await res.json();
    }

    let products = await fetchJson('data.json');
    let location = await fetchJson('https://api.ipdata.co?api-key=<YOUR_API_KEY>&fields=currency');
    let exchange = await fetchJson('https://openexchangerates.org/api/latest.json?app_id=<YOUR_API_KEY>');

    fx.base = exchange.base;
    fx.rates = exchange.rates;

    let tbody = document.getElementById('product-table').tBodies[0];

    products.forEach(function(p) {
        let row = tbody.insertRow();

        let nameCell = row.insertCell();
        let priceCell = row.insertCell();

        nameCell.innerHTML = p.name;
        priceCell.innerHTML = location.currency.symbol + '' + 
            fx(p.price).from('EUR').to(location.currency.code).toFixed(2);
    });
})();

Save the file and request it from your HTTP server. You should see the products displayed in the page with the prices converted to your currency.

Personalizing Experiences

The web is a global community, and it can certainly feel cold and inhuman, but using location data to personalize your user’s experiences goes a long way toward developing a relationship with your users. Converting product and service prices in real-time is just one way that location data can help us build meaningful experiences. No matter what kind of site you’re building, use location data to help your users feel at home. They’ll more than likely come back.