Code-based Actions: Create a location-aware chatbot

You can use the location of your users to find the nearest store location.

Imagine a virtual assistant on WhatsApp or Facebook Messenger that is able to tell your customer where the closest repair service, service point, or collection point is.

In this knowledge base article, we will demonstrate how to use the location of the user to find the nearest store. To find a store or location that is close by, we will need two things:

  1. Location or Address of the User
  2. Store Locator API

Location or Address of the User

Within Flow you can use the Location trigger and an Any Text trigger to obtain input that we can use. Even though sharing a location is cool, some users prefer entering an address as they don't want to share their current location. Therefore, it is recommended to use both options.

As most store locators work with latitude and longitude as input, we need to convert a shared location or an address to a long and lat value.

Location

When using the Location trigger you will receive the latitude and longitude values. Read more in the location or use the code below to create an Action and convert the location of the user to a latitude and longitude value.

async payload => {

  var lat = "-"  
  var long = "-"

  // If the user shares location  
  if(Array.isArray(payload.params.location)) {  
    lat = payload.params.location[0].value.lat  
    long = payload.params.location[0].value.long  
  }

Address

A second option to obtain the latitude and longitude values is to use an address entered by the user. But how do we convert that into a latitude and longitude value?

A simple solution is to use the Google Maps Geocoding API. Read more about Google Maps Geocoding API or use the code below and add it to your existing Action.

if(Array.isArray(payload.params.address)) {
try {
const {
  params,
  user
} = payload

const { address } = params

const lastAddress = address[address.length - 1].value

// For this example we show the API key in code
// but best practice is to use Configuration
// https://flow.ai/docs/actions/code_configuration
const key='YOUR SECRET API KEY'

// Construct a Google API URL
const url=encodeURI(`https://maps.googleapis.com/maps/api/geocode/json?address=${lastAddress}&key=${key}&language=${user.profile.locale || 'en'}`)

// Call the API
const { data } = await request(url)
const { status, results } = data

lat = results[0].geometry.location.lat
long = results[0].geometry.location.lng
   } catch(err) {  
    console.error(err)  
    // This is not good..  
    reply(new Message('Here you will find the closest stores: <https://flow.ai/'>))  
  }

  }

Locate the nearest store

To locate the nearest store, you have two options: Use an existing API of your company or calculate the distance to the location.

Some things to keep in mind during your design:

  • Ensure you sort your results based on distance
  • You need to display one or multiple results
  • You can display multiple results in Carousel (if supported by your channel)
  • You must cover the edge cases

Store Locator API

Some retailers already have a store locator API in place. If that's the case you should be able to make an API call to that service and include the user's latitude and longitude. A store locator API usually returns an array of available locations that need to be mapped to a Text Reply.

Calculate distance within Flow

Not all companies have a Store locator API in place. In this case, we can calculate the distance in the same Flow Action as it allows you to create advanced logic.

To calculate the distance between 2 locations, you will need the latitude and longitude of both the coordinates. A simple database that contains locations as rows should be sufficient to calculate the distance. We can retrieve locations with their longitude and latitude and calculate the distance between the user and the location by using the function below. Read more about geodatasource.

// Function to calculate distance
function distance(lat1, lon1, lat2, lon2, unit) {  
    var radlat1 = Math.PI _ lat1/180  
    var radlat2 = Math.PI _ lat2/180  
    var theta = lon1-lon2  
    var radtheta = Math.PI _ theta/180  
    var dist = Math.sin(radlat1) _ Math.sin(radlat2) + Math.cos(radlat1) _ Math.cos(radlat2) _ Math.cos(radtheta);  
    if (dist > 1) {  
        dist = 1;  
    }  
    dist = Math.acos(dist)  
    dist = dist _ 180/Math.PI  
    dist = dist _ 60 _ 1.1515  
    if (unit=="K") { dist = dist _ 1.609344 }  
    if (unit=="N") { dist = dist \* 0.8684 }  
    return dist  
}

Map result to text reply

After having an array of locations sorted by distance to the user, we can map these results to a Text Reply.

// Map sorted array of objects to reply

  // Fallback default  
  var message = (`To find a location have a look at www.flow.ai`)  
  // Bij gevonden locaties  
  if (arrOfObj.length > 0) {  
      message = (`These are the closest locations:`)  
      for (var i in arrOfObj) {  
        message += `\n ${arrOfObj[i]["City"]}, ${arrOfObj[i]["address"]}`  
      }  
  } 

  reply(new Message(message))

Covering any edge cases

Your API, both the Google API and your Store Locator API might work while testing but what do you do:

  • If the API returns an error
  • If the API did not give any valid results
  • If the API returns multiple addresses

For the above use cases, we can return a text message with a link for the user to find the nearest store using Google Maps.

Read more