Reading Alessia’s recent post about her experiments with beacons reminded me of a post that I have been meaning to write for a while, regarding my previous dabbling with building location-aware applications. Beacons are a powerful tool by which to provide fine-grained location services to applications, but need to be used carefully, and really need to be part of a larger mix of technologies in order to provide the richest experiences. In this post, I will look at the weaknesses I have previously encountered using beacons, and outline some of the strategies I have used to mitigate those weaknesses.
The Problem with Beacons
Beacons provide excellent fine-grained location awareness… if the user has Bluetooth turned on, and if the application is actively scanning for beacons. These are some pretty big ‘ifs’, especially the latter. While both Android and iOS support scanning for iBeacons in the background (Android via the creation of a Service, and iOS using the CoreLocation APIs), scanning in the either the background or the foreground is a significant drain on battery power, and having your app drain power by constantly scanning for beacons in the background (and therefore offering no visible benefit to the user) is going to get the app uninstalled pretty quickly. The Android developer’s guide for Bluetooth Low-Energy explicitly calls out scanning strategies in order to minimize power consumption.
In addition, beacons are dumb. Generally most beacons simply broadcast an identifier, and perhaps a very small amount of data. As a result of this, applications are mostly left to ‘figure it out’ on their own. This is fine for simple applications, or demos, as it isn’t hard to just store a beacon identifier, or list of beacon identifiers that you check against upon the discovery of an object, then take some pre-determined action. It becomes more of an issue in the rollout of larger campaigns using beacons, as such a campaign is inevitably going to require change at some point. That change could take the form of changing behaviour on discovery of beacons, additional beacons as the campaign gets rolled out more widely, or simply wear and tear, as beacons are replaced when they run out of power, damaged, etc.
These issues indicate that in order to provide a scalable location-aware capability for a mobile device, a more holistic approach is required, one that influences user behaviour (prompts them to bring the app into the foreground/turn on Bluetooth) as well as facilitating a complete beacon infrastructure.
Complementing Fine-grained Location with Coarse-grained Location
The first issue of Beacons, in that you can’t reliably scan for them in the background, can be mitigated encouraging a user to open the app and turn on Bluetooth when they are in the general vicinity of beacons. There are obviously behavioural approaches by which to do this, for instance, in the case of Alessia’s fitness tracker application, it makes sense that a user would have this open while at the gym. My interest is more upon the technical approaches that are possible (surprising right?). The fine-grained capability of beacons can be complemented with a coarse-grained location awareness in order to prompt the user that they can obtain an enriched experience while they are in a specific area, be that a store, shopping complex, building, etc.
Both iOS and Android support coarse-grained location services in the background, which allow an application to register an interest in an area and receive a callback when that area is entered, prompting, normally via notification, the user to open the app. This notification could link to an in-store/on-site version, with features designed to enhance that physical location.
This coarse-grained capability is often referred to as geofencing or region monitoring, and is documented here for Android and here for iOS. From my testing, it does slightly increase power consumption (and get slightly annoying when it welcomes you to the office each day…), though is significantly less taxing than scanning using Bluetooth. The location services (at least in Android) also can leverage WiFi location information, which is significantly reduces the likelihood that required services are turned off, as although many users typically have Bluetooth turned off, the same is not true of WiFi.
While geofences have reduced power consumption, this comes at a bit of a cost, as the background task is run sporadically and enter/exit events are therefore a little delayed. In my testing, I had a geofence on my office building for a couple of days, and I received events anywhere from entering the lobby, in the elevator, to after being seated at my desk for several minutes. You can tune this on Android, but not iOS, by setting the notification responsiveness, but this comes with a power consumption trade-off.
There is also some consideration for setting geofences dynamically, or to dynamically remove themselves. If for instance, you have some sort of event-oriented application, which allows users to register for events and use their phone to sign-in or something similar, then any geofences will likely only be relevant for a short time, from an hour or so before the event start time until the event finishes. As a result, in order to avoid consuming power monitoring location (either via WiFi scanning or using GPS information), it makes sense to only create the geofences for the relevant time periods, then tear them down when they cease to be relevant (after the user has interacted with them, or when the event is over). This can be achieved using the AlarmManager class in Android, and the NSTimer class in iOS in order to create a geofence at a scheduled time.
Obviously this is inappropriate if you are creating an application which wants to deliver an in-store experience, as your store hardly appears for a day before disappearing. In this case, the geofences to check can be minimized by loading only geofences in the immediate vicinity of the user. When the user opens the application, a check is made of their location, and if no geofences are loaded, or if the user’s location has changed significantly, the surrounding geofences are obtained and loaded for monitoring. In this manner, even if a retailer has thousands of sites, only a small number of geofences are being monitored at once. In the case of iOS, this is a mandatory approach, as a single application has a hard limit of 20 regions to monitor at a single time.
Dynamically loading Beacon information
Similarly to loading geofence information, discussed above, any sustained beacon campaign is going to require beacon information to be resolved dynamically. There are several possible approaches to this, but all require supplementing the mobile device and beacons with a set of beacon/location APIs, provided out of a central service.
A naive method by which to handle this is to, upon encountering a beacon, ask the beacon API which behaviour is appropriate. i.e. Upon encountering beacon 12345-54321 (obviously real beacon identifiers are slightly more complicated), the application might call:
GET /beacons/12345-54321
The response to this could be a JSON object which describes whether to do anything in response to this beacon, and the behaviour, message, or just the specific information required if the application is listening for the beacon.
This approach makes managing the beacons simple, as they essentially represent entries in a database, where behaviour can be changed by updating the entry, old beacons can be retired by removing the entry, and new beacons added by creating new entries. This approach does ensure beacon information is always current, but requires the application to have constant internet access, and makes it needlessly chatty, especially if there is no filter on the beacons which are detected and it calls out for every beacon discovered, whether it is associated with your campaign or not.
An approach which mitigates this is to store lists of known beacons locally on the device, and on application start (since you probably don’t want to scan for beacons in the background, this level of frequency is fine) request any updates to the current version of the beacon list i.e. (where 122 is the current version stored locally)
GET /beacons?local-version=122
A response to this could be 304 Not Modified (which is an accurate though confusing use of HTTP status codes) or a response object representing the list of beacons if the list is out of date. While such a list will likely still be smaller (in terms of payload size) than most images, it may become slightly unwieldy, or at least inelegant for larger beacon campaigns. A preferable approach may be to instead return a diff of the provided version number and the current i.e.
{ local-version: 122, current-version: 124, changes:{ removed:[ {identifier:"12345-54321"} ], updated:[ { identifier:"12346-64321", location:"Albion Store", message:"While in the Albion store, check out our new demo area." } ], added:[ { identifier:"12347-74321", location:"Western Store", message:"Enjoy 20% off to celebrate the opening of our new store!" } ] } }
The client application is then able to update their local copy of the beacon list with these changes, and consult that list whenever they encounter a beacon. Constructing a diff of changes to be returned by the API could be done dynamically, or calculated on each change, depending ultimately on a tradeoff between compute time and storage. It may be that responses ought to be crafted based upon the user’s identity information, and in that case, returning fixed messages is a poor fit. Instead a list of available services for that location may be more appropriate, then the precise message selected based upon some cross-reference with a user’s interests or similar.
As for geofences above, the list of beacons could be minimised by only returning those beacons in the immediate area. Leveraging geofences for alerting could also be combined with dynamically populating beacon lists, and upon entering a geofence, the information for the beacons within that geofence pulled to the local device.
Beacons provide a powerful capability to connect to users in a manner that is applicable to their precise situation and location, but leveraging this capability requires surrounding them with complementary technical solutions, as well as the behavioural component of crafting a user experience in which they feel valuable, appropriate and nonintrusive. Hopefully this post has provided some useful techniques by which a beacon campaign can leverage these technical approaches, such as utilising a coarse grained location approach to minimize power consumption and encourage user engagement, and creating specific location services that the client application can leverage to ensure beacons remain valid and up-to-date. Combined, I feel that beacons can present a very powerful tool for user engagement, but without, I feel beacons have too many inherent weaknesses to be more than a novelty.