iBeacon Bluetooth Checkins in Action

One of Belly’s most interesting challenges is improving the customer experience at the point of checkin. Part of this is reducing the friction of checking in while ensuring that Belly businesses are rewarding their purchasing customers. Seamlessly communicating between device two foreign devices securely is an interesting problem. QR codes have been our De facto method, but there’s an interesting amount of technologies at play in our field (high frequency sound transmission, GPS geofence polling, NFC, manually entered phone number or email address, etc.). We’ve looked at most of them, but they all seem to fall short due to tradeoffs with technical and market adoption or quality assurance.

Apple pushing Bluetooth 4.0 (BTLE) allows for some interesting new use cases and allows for automatically triggered background actions for application developers to take advantage of. This means that an application can execute code for a short period when it receives a push notification from another iBeacon transmitting device. The proximity of these devices can be approximated by using the strength of the signal received by the device.

We put together a quick hacktime demo to demonstrate iBeacon’s functionality and would like to share a potential use case here. iBeacon is a compelling new opportunity to build and develop new products and functionality, and Belly has a clear opportunity to leverage it with our iPads in retail stores. We wanted to show a quick demo here, but have many more updates for iBeacon that are yet to be announced.

To checkin on our in-store tablets, a user must currently tap the screen, and then scan the generated QR code on the device scanner. Utilizing iBeacon drastically reduces this checkin friction and would allow us to securely prefetch information about nearby devices before a Belly user reaches the checkin terminal (the device’s name, the user’s ID and Email, and a one-time-use Access Token). We can use this information of nearby devices to allow quick scan-free checkins for our users.

Enabling iBeacon

Setting up iBeacon by itself isn’t too complicated. There are a few examples around the net, but we’ll provide ours here. iBeacon itself lives in CoreLocation. We created a BluetoothCheckinManager class that handles all of the iBeacon/BTLE code.

To start broadcasting a beacon, Import <CoreLocation/CoreLocation.h> and <CoreBluetooth/CoreBluetooth.h. You’ll also need to implement the protocol CBPeripheralManagerDelegate, and then initialize the beacon.

NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:BELBeaconUUID];
self.beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid
self.peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil];
self.peripheralData = [self.beaconRegion peripheralDataWithMeasuredPower:nil];

You’ll need to generate a UUID ahead of time and have a format setup for your beacon identifier. Some beacons can do different things depending on the context of the identifier. We used reverse domain notation here (ie: “com.belly.merchant.checkinRegion”).

Now you just need to check if Bluetooth is on before you broadcast. -(void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral will get a callback. Once you know the state of the device you should start or stop advertising.

-(void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral {
    if (peripheral.state == CBPeripheralManagerStatePoweredOn)  {
        [self.peripheralManager startAdvertising:self.peripheralData];
    } else if (peripheral.state == CBPeripheralManagerStatePoweredOff)  {
        [self.peripheralManager stopAdvertising];

Now you need listen on a second device, which in this case is a user’s iPhone. Just like listening for a GPS change, you listen for an event when the device enters or leaves the iBeacon range. Just like before you need to setup a UUID and a beacon region. We did this with a location management class.

NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:BELBeaconUUID];
self.beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid identifier:BELBeaconIdentifier];

The next thing you need to add here is to tell your location manager to pay attention for you beacon region.

[self.locationManager startRangingBeaconsInRegion:self.beaconRegion];

You’ll now get a delegate call back to -(void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region when you enter a beacon range. The beacons array will contain any number of beacons near you (in our case only one). The CLBeacon object contains some basic information about the beacon so you can make smart choices. In our case we use it to identify the iPad.

This is great for one way communication like we mentioned because you can set it to “wake your app up”. The Belly app requires a bit more work to connect with our API to get user information and a checkin token. The BTLE Transfer open source Apple project is great and does two way low energy bluetooth communication.

The BTLE Transfer project is a lot to all go over, and most of this code handles setting up the two way communication, so I’ll cut to the parts you’re probably interested in. The two files BTLECentralViewController.m and BTLEPeripheralViewController.m contain the bulk of the Bluetooth code.

- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error on line 252 of BTLECentralViewController.m has an example of pulling data out of the connection.

- (void)sendData on line 264 in BTLEPeripheralViewController has an example of sending the data. We based most of our code around what’s in these two files. You don’t need to know much about Bluetooth to get something working, using these two files as a road map.

Using iBeacon In The Client

Our HTML5 app subscribes to a channel that receives nearby device events from the native Bluetooth Beacon. These events happen very rapidly with a record of which device was found. We maintain a Backbone Collection of Nearby Devices that handles the event channel. For every device that is active, we look through the collection to see if that user is already active. If device is already active, we use the Keepalive pattern to ensure that we keep a record of that device. The Nearby Device model is automatically pruned from the collection after 5 seconds since it was last active. The CoffeeScript implementation of this is below:

class App.NearbyDevices extends Backbone.Collection
  model: App.NearbyDevice
  initialize: -> @listen()
  listen: =>
    App.exec(@success, @error, 'BellyBeacon', 'startListening', [])
  success: (data) =>
    model = @get(data['userID']) # idAttribute of the Backbone model is userID

    # If the model does not exist, create a new one and add to the collection
    if not model
      model = new App.NearbyDevice(data)
      model.set(data) # Update the model if the Auth Token or device name changes

    model.touch() # Reset expiration keepalive timer

    @listen() # Listen for another BellyBeacon Event

  error: (data)=>
class App.NearbyDevice extends Backbone.Model
  idAttribute: "userID"
  touch: =>
    clearTimeout(@expires)  if @expires # We're active, so clear previous timeout
    @expires = setTimeout(@prune, 5000) # Create a new timeout to prune

  prune: =>
    @trigger('destroy', @) # Remove self from the collection

The views in our HTML5 app listen for add and remove events on an instance of the App.NearbyDevices Collection to show or hide the “X Devices” tab seen in the screenshot above. When the popout tab is tapped, a popup modal appears with a list of the nearby devices where the user can select their device name to quickly checkin (side note: this checkin is unverified so the user still receive points but isn’t able to redeem someone else’s rewards).

The video below shows the whole hacktime demo working in action:

Ask a question or share this article, we’d love to hear from you!