[ { "title":"Meraki", "url":"/meraki/" }, { "title":"Explore", "url":"/meraki/explore/" }, { "title":"Wayfinding with Mapwize" } ] Code Exchange https://developer.cisco.com/codeexchange/platforms/meraki _blank

Wayfinding with Mapwize

Individuals often have a hard time finding their way indoors, as services like Google Maps only work in shopping malls and airports. Mapwize’s indoor mapping platform allows you to use Meraki access points to navigate buildings like shopping malls, hospitals and more. This article will teach you how to create a custom map with Mapwize’s open-source platform and deploy it alongside Meraki access points and the Scanning API.

Launch Demo

Indoor Location from Meraki

Wayfinding with Meraki is so easy anyone in IT can do it with experience in using a linux command line.  Every WiFi-enabled device coming in the vicinity of the wifi infrastructure will be positioned by Meraki. The network probe requests coming from the phones will be intercepted by the different access points and their signal strength will serve to triangulate the position. Each device is identified by its MAC address.

To protect the privacy of the user, most modern phones running iOS and Android will use random MAC addresses in their probe requests. However, all devices use the original unique MAC address when connecting to WiFi networks, making it easier to track devices after they connect.

Probe requests are sent by the phone to discover the network around them. Depending of its state (active, sleeping, energy-saving, in communication, …), the phone will not necessarily always send a probe request at the same interval. We can expect on average to have a probe request every minute but the Meraki infrastructure has no control over the device.

The procedure works as such:

  • The location of the device is computed by the Meraki cloud
  • Those locations are sent as notifications to a listener server (see below)
  • The listener decodes the location and stores it in a Redis database using the local IP as key. It can also send it to any other system or database for further processing.
  • The device connects, thans to web sockets, to an emitter server and provides its local IP as userId.
  • The emitter server listens for changes in the Redis database and sends the right location to the right user matching the local IP
  • The web app or mobile app displays the map and the location of the device.

Alternative Solutions

There are 3 possibilities to use Meraki for Indoor Location:

  1. Get device location from the infrastructure: the device’s location is calculated by the Meraki cloud based on the signal strength of the signals received by multiple access-points.
  2. Have the device calculate its position based on the WiFi signal strength of the surrounding access points. This is sometimes called fingerprinting.
  3. Have the device calculate its position based on the bluetooth signal strength of Bluetooth iBeacons embedded in the Meraki access points.

For this lab we will use Option 1 as it does not require a mobile app to be installed and is supported on both iOS and Android. Option 2 requires the mobile phone to be able to scan for WiFi access point, which is not supported on iOS. Option 3 can provide lower latency but it will not work in a web-browser and requires a mobile app i

nstalled on the device.

Here are some pros and cons between options 1 and 3:

Infrastructure iBeacons
Gets the position of all WiFi enabled devices An app need to be installed on the device
User need to be connected to the WiFi to be able to retrieve its position User does not need to be connected to the WiFi
A new location is computed on average every minute and depends on phone state A new position can be computed every second


On iOS and Android, it is impossible for an app to retrieve the MAC address of the device, also for privacy reasons, so Option 1 requires connecting to the WiFi to use a mobile app. Connecting to the network allows will enable the app to identify the location of a specific device is using the LAN IP address of the device.

Indoor Location using iBeacons

All Meraki access points can be configured to emit a iBeacon bluetooth signal. Those signals can be heard by the mobile phones and used to compute the device’s location. See the Bluetooth Beaconing section in the Meraki documentation

In order to do so, an iBeacon SDK needs to be included in your app. This framework proposes a BasicBeaconIndoorLocationProvider available for both iOS and Android. Other providers exists with more comprehensive features.

In order to use the BasicBeaconIndoorLocationProvider, the steps are the following:

  • Using the configurator (see below), import the floor plan configuration from Meraki to Mapwize. Set the floor of each floor plan and re-align it if necessary.
  • Import the position of the access points in Mapwize with their iBeacon UUID, major and minor settings.
  • Add the BasicBeaconIndoorLocationProvider in your mobile app and make sure the API key used has read access to your venue.

Build your own Wayfinding App

We’ll walk through the requirements to set up your computer, get location data from Meraki, import maps from Meraki, setup the opensource IndoorLocation.io listener and emitter for Meraki data, and display your device’s location on a map. Further work will be needed to track assets or send notifications to a chat room. We will be using the IndoorLocation.io open source project provided by our technology partner Mapwize.io

The objectives of this guide is to help you:

  • Learn about location-based services inside buildings
  • Listen for Meraki location notifications
  • Build a simple indoor navigation wayfinding mapping app using Mapwize
  • Display a device location on the venue map for asset tracking
  • Get a notification on WebEx Teams when a device enters or leaves an area


The following tools will be required to follow this guide. Please ensure your have them installed on your computer.

Also, you’ll need the following accounts. Don’t hesitate to sign-up – they are both free.

Optional: If you have some experience with mobile development, on either iOS or Android, or if you want to get started compiling your first simple app, bring XCode or Android Studio as well as your mobile device and a USB cable.

SDK for Mobile Apps

If you want to get the user’s position in a mobile app and display it on the map, you will need to use the SocketIndoorLocationProvider modules which are  available for both iOS and Android.


Exporting data from Meraki

The section explains how to get the required data from Meraki into Mapwize. A configurator tool is provided to import data from Meraki to Mapwize and create the configuration file required to run the Meraki listener server.

The configurator is a command line tool developed in NodeJS. Before running it, you need to have node installed on your machine and install the dependencies using npm install

Getting the floor plans

  • Log in to your Meraki dashboard
  • Open the developer tools in your browser
  • In the Wireless menu of the Meraki dashboard, navigate to Map & floor plan
  • Search the source code of the webpage for the parameter similar to this: 
    Mkiconf.ng_id = "566890603095264237";
  • Copy the ng_id value and add to this URL: https://api.meraki.com/node_groups/{ng_id}/floorplans
  • Save the JSON response to a file on your computer.

Getting the list of access points

  • Log in to your Meraki dashboard
  • In the Wireless menu, navigate to Access points
  • On the top right, use the Download As button to download the list of AP as XML

You might wonder why we use XML in this case and not JSON as everywhere else? Simply because in the JSON export, the nodeId of the access points are not exported, while in the floor plans we got above, only the nodeId are available.

Getting the floor plans

  • Log in to your Meraki dashboard
  • In the Wireless menu, navigate to Map & floor plan
  • Display the source of the HTML page in your browser
  • Search the source for MKI.Current.get('ng').set(. You should find it twice. The one we need is the first one, around line 473, just after if (window.google_maps_loaded) {
  • Copy-paste the JSON that is inside MKI.Current.get('ng').set( **JSON** ); to a text file and save it on disk.

Getting the list of access points

  • Log in to your Meraki dashboard
  • In the Wireless menu, navigate to Access points
  • On the top right, use the Download As button to download the list of AP as XML

You might wonder why we use XML in this case and not JSON as everywhere else? Simply because in the JSON export, the nodeId of the access points are not exported, while in the floor plans we got above, only the nodeId are available. 

Importing data into Mapwize

This step creates a layer in Mapwize for each floor plan in Meraki. The layer’s name is Meraki - followed by the floor plan name. At first, these layers do not have a floor configured, as the floor data is not available in the Meraki API today. You need to edit each layer to update their floor properties.

As some alignment problems can be observed, you might also have to check that each layer image perfectly overlays the Mapwize layers for a better accuracy.

The command is described below:

./meraki-configurator/merakiFloorplansToMapwize.js --merakiFloorPlansConfig [FILEPATH_FOR_FLOORPLANS_JSON] --mapwizeUser [YOUR_MAPWIZE_EMAIL] --mapwizePwd [YOUR_MAPWIZE_PWD] --mapwizeApiKey [YOUR_MAPWIZE_API_KEY] --mapwizeOrganizationId [YOUR_MAPWIZE_ORGANIZATIONID] --mapwizeVenueId [YOUR_MAPWIZE_VENUEID]

Generate the configuration file

Once the layers are correctly configured in Mapwize, with right floor and alignment, use the command below to generate the JSON configuration file that will be used later by the listener.

./meraki-configurator/configureFromMapwize --merakiFloorPlansConfig [FILEPATH_FOR_FLOORPLANS_JSON] --mapwizeUser [YOUR_MAPWIZE_EMAIL] --mapwizePwd [YOUR_MAPWIZE_PWD] --mapwizeApiKey [YOUR_MAPWIZE_API_KEY] --mapwizeOrganizationId [YOUR_MAPWIZE_ORGANIZATIONID] --mapwizeVenueId [YOUR_MAPWIZE_VENUEID] --output [OUTPUT_PATH_FOR_LISTENER_CONFIGURATION]

Import the access points to Mapwize

This steps creates beacons in Mapwize based on the Meraki configuration. Please note that the beacons will be added in Mapwize based on the floor plan configuration done in Mapwize, with the floor and alignment given to the floor plans.

./meraki-configurator/merakiAccessPointsToMapwize --merakiFloorPlansConfig [FILEPATH_FOR_FLOORPLANS_JSON] --merakiAccessPointsConfig [FILEPATH_FOR_ACCESSPOINTS_XML] --mapwizeUser [YOUR_MAPWIZE_EMAIL] --mapwizePwd [YOUR_MAPWIZE_PWD] --mapwizeApiKey [YOUR_MAPWIZE_API_KEY] --mapwizeOrganizationId [YOUR_MAPWIZE_ORGANIZATIONID] --mapwizeVenueId [YOUR_MAPWIZE_VENUEID]

Aligning the Floorplans

The Meraki cloud provides a device location as a latitude and longitude pair. However, there are 2 reasons why an extra processing is required:

  • The provided location is missing a floor, which is critical for Indoor applications.
  • Often the alignment of the building floor plans on the world map done in Meraki is not done with indoor positioning in mind, and therefore will not match with the indoor map in your application.

A correction phase is then required :

  • Using the configurator provided below, the Meraki configuration (the floor plans and their alignments) are injected in Mapwize as layers.
  • In Mapwize, we configure a floor for each imported floor plan.
  • If required, we move the floor plan in Mapwize according to our indoor map.
  • Using the configurator provided below, we get a configuration file that will be used later by the listener to process every location received from Meraki.


In this step, we will create a venue in Mapwize using the Meraki floorplan configuration.

  1. First, make sure you have your Mapwize account ready or sign up for free at mapwize.io. Go to studio.mapwize.io and sign in.
  2. In your Mapwize account, create a venue for your building. When asked, draw a simple rectangle around the building, don’t worry about the exact shape.
  3. In the venue config screen, on the right side, scroll down to retrieve your venueId and organizationId.
  4. Go back to the home page then in the left venue select “API key” and create an API key.
  5. Download the Meraki floorplan configuration file for this lab. Normally you would get this data from the Meraki Dashboard.
  6. Clone the github.com/IndoorLocation/meraki-indoor-location repository on your machine.

git clone https://github.com/IndoorLocation/meraki-indoor-location

7. Use the configurator to inject the Meraki floorplan config to your Mapwize venue:

./meraki-configurator/merakiFloorplansToMapwize.js --merakiFloorPlansConfig [FILEPATH_FOR_FLOORPLANS_JSON] --mapwizeUser [YOUR_MAPWIZE_EMAIL] --mapwizePwd [YOUR_MAPWIZE_PWD] --mapwizeApiKey [YOUR_MAPWIZE_API_KEY] --mapwizeOrganizationId [YOUR_MAPWIZE_ORGANIZATIONID] --mapwizeVenueId [YOUR_MAPWIZE_VENUEID]

8. Go to Mapwize Studio, enter your venue and go to the Layers section. You’ll see that a “Meraki – xx” layer has been created. That’s the image that was used in Meraki, positionned precisely like in the Meraki portal.

9. As Meraki does not support configuration of floors in the Meraki Dashboard, you’ll need to manually edit the layer and set floor=2. Also, toggle the publish status to true. And save.

10. For this guide we will just have a single floor, but you can easily add multiple floors.

Setup the Listener server

The Mapwize Listener is a NodeJS server for receiving the Meraki Scanning API push notifications. Each notification will be received and processed into an IndoorLocation object. The computed IndoorLocation will be saved in a Redis database with the IP address as userId to be used by the emitter. Thanks to Redis, the emitter will be notified each time a key value has been changed.


  1. Now that the layer is correctly configured in Mapwize, with the right floor and alignment, we can generate the JSON configuration file for the listener
    • ../meraki-configurator/configureFromMapwize --merakiFloorPlansConfig [FILEPATH_FOR_FLOORPLANS_JSON] --mapwizeUser [YOUR_MAPWIZE_EMAIL] --mapwizePwd [YOUR_MAPWIZE_PWD] --mapwizeApiKey [YOUR_MAPWIZE_API_KEY] --mapwizeOrganizationId [YOUR_MAPWIZE_ORGANIZATIONID] --mapwizeVenueId [YOUR_MAPWIZE_VENUEID] --output [OUTPUT_PATH_FOR_LISTENER_CONFIGURATION]
  2. Now it’s time to start a local Redis database on your machine. The database will allow to store the last position received for each device.
    • redis-server
  3. We need to activate redis notifications for the system to work by using the following comand:
    • redis-cli config set notify-keyspace-events K$
    • The listener is available in the same Meraki IndoorLocation Github repository, in the listener directory.
  4. You can set the configuration of the listener directly in the config/all.js file or using environment variables.
  5. Assuming your Redis server is running with default configuration (localhost:6379 without auth), the only variable you’ll need are:
    • PORT: port used by the server (default: 3004)
    • SECRET: secret defined in the Meraki dashboard to authenticate the POST query (required)
    • VALIDATOR: token defined by Meraki to identify the source (required)
    • MAX_BODY_SIZE: Controls the maximum request body size (default: ’50mb’)
    • FLOOR_PLANS: serialized JSON with the output of the configurator (required)
    • MAC_ADDRESS_ENABLED: use the MAC address in addition to the IP address as a key in Redis (default: false)
    • REDIS_HOST: redis host (required)
    • REDIS_PORT: redis port (default: 6379)
    • REDIS_AUTH: redis password (required if set)
    • REDIS_MERAKI_NOTIF_TTL: redis key TTL in seconds (default: 3600)
    • DOCUMENT_DB_ENABLED: allow to log the indoorLocation along to the Meraki observation into a DocumentDB collection
    • DOCUMENT_DB_ENDPOINT: string connexion to the DocumentDB instance
    • DOCUMENT_DB_PRIMARY_KEY: primary access key to the DocumentDB instance
    • DOCUMENT_DB_DATABASE: DocumentDB database name
    • DOCUMENT_DB_COLLECTION: DocumentDB collection name
  6. By default, your listener will be running on localhost:3004.
  7. Note: To correctly serialize the Meraki configuration, you can execute
    • export FLOOR_PLANS=$(node -e 'var json = require("FILEPATH"); console.log(JSON.stringify(json));')
  8. Or if you want to put this variable into your clipboard instead to paste it in the config file, please execute
    • node -e 'var json = require("FILEPATH"); console.log(JSON.stringify(json));' | pbcopy
  9. And now you can start the listener server with
    • npm run start-listener
  10. Now you should start receiving notifications and your Redis database will be populated with locations. You can use RDM or your favourite Redis explorer to see the records.

Setup the Emitter server

Now that the location data is flowing to the Redis database, the next step is to setup the emitter server to allow other systems (apps or other components) to retrieve location updates for specific IP or MAC using websocket.

The Emitter server is the NodeJS server that will transmit the updated locations to the app using web socket. Each socket connection will lead to a redis subscription that will help to only get the IndoorLocation objects when the location of a user has been changed. These objects will be sent to the providers via a socket channel.

The emitter server is located in the same Meraki IndoorLocation Github repository, in the emitter directory.

  • We first need to correctly set the configuration parameters
    • Directly in the config/all.js file
    • Via environment variables
      • PORT: port used by the server
      • REDIS_HOST: redis host (required)
      • REDIS_PORT: redis port
      • REDIS_AUTH: redis password (required if set)
  • Start the server
    npm run start-emitter
  • Add the socketIndoorLocationProvider in your app and point the module to your emitter server URL.


  1. Set the configuration of the listener directly in the config/all.js file or using environment variables.
  2. Assuming your Redis server is running with default configuration (localhost:6379 without auth), you don’t need any particular configuration.
  3. Start the server using npm run start-emitter
  4. By default, your emitter will be running on localhost:3003.

Now you have everything you need to retrieve the location of any device using websocket.


See your location on the map

So now you can see your position on the map … or even the position of any device as long as you know the local IP address orthe MAC address.


The simplest way to see your location is to use maps.mapwize.io as there is nothing to code or compile.

  1. Go back to Mapwize Studio. From the home screen, on the left menu, go to the “Access groups”. Create a group containing all venues and all universes.
  2. Then head to “Access keys” and create a key for the access group you just created.
  3. Go to venues and then select your venue. Make sure that your venue is published by setting the published flag to true and saving it.
  4. Then, inside your venue, head to the URL generator and create an URL to see your venue using the access key you created.
  5. Open the link in your browser and you should be able to see the map of DevNet Create. But your location is not on it yet.
  6. To do so, add the indoorLocationSocketUrl and indoorLocationUserId parameters to your URL. It should look like this:
    • https://maps.mapwize.io/#/v/[VENUE_ALIAS]?k=[ACCESS_KEY]&indoorLocationSocketUrl=localhost:3003& indoorLocationUserId=[YOUR_LOCAL_IP_OR_MAC]
  7. To use your local IP address, you need to be connected to the Meraki Wi-Fi access points
  8. Refresh the page and you should see your position as provided by Meraki’s Scanning API.

View your location in a mobile app

If you want to see location in a mobile app, you can use the sample app to see your location.

The sample app is available for

You will need to set your credentials in SocketIndoorLocationProviderDemoApp and MapActivity. You need to change 2 things:

  • Set your API key in SocketIndoorLocationProviderDemoApp. (see below)
  • Set the URL of your emitter server in MapActivity on line 48. (see below)

In order to see your venue in the app, you’ll need to add the rights on your API key. To do so, go to Mapwize Studio and then to “API keys”. Edit the API key you already have and add your access group in it.

Using localhost in your app as socket URL is not going to work. The best option to solve that is to use ngrok. Ngrok will create a tunnel to your local machine that is available from the cloud. Run

ngrok http 3003

and use the address provided by ngrok in your app. You need to keep ngrok running on your maching for the connection to be maintained.

On mobile, your local IP address is used automatically to fetch your position. Therefore, your device must be connected to the Meraki network. Ask me for credentials.

Make the map look nicer

The map that you are seeing is the technical drawing that was used to configure Meraki. Usually, this is not the map you want to show your users.

My collague Manon has designed a better looking map of the venue. You can download the image here.

Go to Mapwize Studio, enter your venue and go to “Layers”. Create a new layer for the 2nd floor.

When created, drag and drop the image to import it. In the aligment editor, on the top left, select the Meraki layer from the list to display it as reference. Align the new floorplan with the Meraki one moving the pins. When done, import.

When the import job is finished, publish the layer by setting the published flag to true and saving.

Go to the layer list, select the Meraki one and unpublish it.

Refresh maps.mapwize.io or relaunch your app to see the difference.

If you want to build an interactive map, follow the Mapwize tutorials to app places and directions.

Advanced: build the full Mapwize app

If you want to go further with mobile development, you can build the open-source Mapwize mobile app adding the socketIndoorLocationProvider in it.

The source code of the Mapwize app is available for

Track assets

So far, you have seen how to retrieve locations and see them on a map. There are a lot of use cases where you would like to track assets and get notified when they move, enter or leave certain areas. One way to be notified is using Cisco Spark.p

Get a notification on WebEx Teams if an asset enters or leaves an area

Since an emitter server is available to share device positions, we are going to use it again and connect it to an alerter. Please make sure you have a Cisco WebEx Teams account and that you have a Cisco WebEx Teams client installed (desktop, mobile or web).

Navigate to developer.webex.com/getting-started.html. Make sure you are logged in, and follow the instructions to retrieve your token (scroll down a bit).

Then go to Mapwize Studio, enter your venue, and go to “Places”. Use the polygon tool on the top left of the map to create a polygonal place. Click on the map to create the polygon edges and close the polygon clicking on the first point again. Give a name to your place and select a place type (you can choose anything, it doesn’t matter). Save your place. Then edit it to view it’s id all the way at the end of the edition window.