Cast content to Mirror from a mobile app

Mirror Display SDK for iOS and Android allows your mobile app to take control of the nearby screen. The SDK simply sends display instructions to Mirror over Bluetooth. It can happen with the app both in the foreground and the background.

An airport app could highlight the user’s flight info as they approach the airport display. A conference app could show the upcoming talks that the user has previously bookmarked. Or how about a quiz app, where the question is shown on the big screen, and the host sees the answer on their phone or tablet?

What’s ahead (aka Table of Contents)

You will need…

  • 1 x iPhone 5 or newer, or 1 x smartphone with Android 4.3 or above
    • iOS and Android simulators don’t support Bluetooth
  • 1 x Estimote Mirror
  • 1 x TV or other display with HDMI and USB ports
    • you can twist and bend your Mirror to make it fit into the ports
    • alternatively, you can power it from your computer’s USB port, or use a USB wall charger
    • use a USB extension cable if needed

Quick start

1. Integrate Display SDK


Install via CocoaPods:

  • $ pod init in the project root directory
  • Edit your Podfile to include the following repositories under your project target
    pod 'EstimoteMirror'
    pod 'EstimoteBluetoothScanning'
    pod 'EstimoteProximitySDK'
  • $ pod install

You can check out one of the bundled Examples’ Podfile to see what it should look like.

If you want your app to cast content to Mirror in the background, also enable the “Uses Bluetooth LE accessories” Background Mode in your project’s settings, on the Capabilities tab.


Add Estimote’s Maven repo to your project’s build.gradle:

allprojects {
    repositories {
        // add this:
        maven { url  "" }

Then add both Display SDK and Proximity SDK dependency to your module’s build.gradle:

dependencies {
    // ...
    implementation 'com.estimote:display-sdk:0.2.0'
    implementation 'com.estimote:proximity-sdk:1.0.1'

    // Use Estimote's support library - Mustard
    // for checking location permission requests
    implementation 'com.estimote:mustard:0.2.1'

Info: To provide contextual experience with Estimote Mirror based on proximity zones, we will make use of Proximity SDK capabilities.

For more information, You can visit iOS or Android Proximity SDK tutorial.

2. Customize a pre-defined view

Mirror and the Display SDKs come with a bunch of built-in views, which you can immediately start using and showing on the big screen. Here, we’ll use the Poster view.


In your view controller’s viewDidLoad, add:

override func viewDidLoad() {
    let poster = Poster() { p in
        p.header = "Hello, world!"
        p.body = "Programmable screen is here."
        p.image = .preloaded(path: "shoe_big.jpg") = PosterStyle() { ps in
          ps.textAlign = .center
          ps.textPosition = Position(
              horizontal: .center, vertical: .bottom(offset: 80))
          ps.imagePosition = Position(
              horizontal: .center, vertical: .top(offset: 80))


In your activity’s onCreate, add:

protected void onCreate(Bundle savedInstanceState) {

    PosterViewData posterData = new PosterViewData.Builder()
        .setHeader("Hello, world!")
        .setBody("Programmable screen is here.")

    PosterViewStyle posterStyle = new PosterViewStyle.Builder()
        .setTextPosition(new Position(, Vertical.bottom(80)))
        .setImagePosition(new Position(,

    PosterView poster = new PosterView(posterData, posterStyle);

3. Display a view in defined proximity zone

Once we have our view defined, it’s the time for showing it on the screen when the the device comes in range.

Make use of Estimote’s Proximity for iOS or Proximity for Android to trigger view displaying in particular device range. Once you enter specified zone, pass the defined view to MirrorClient object and trigger its’ displaying with display method.


In your view controller’s code:

// create and store a strong reference to a MirrorClient
let mirrorClient = MirrorClient(appID: "your-app-id", appToken: "your-app-token")

override func viewDidLoad() {
    let poster = /* ...
    ... code from the previous step
    ... */

    // prepare credentials for ProximitySDK
    let credentials = CloudCredentials(appID: "your-app-id", appToken: "your-app-token")
    // initialize a ProximityObserver instance
    self.proximityObserver = ProximityObserver(credentials: credentials, onError: { error in
    // create a mirror tagged zone
    let mirrorZone = ProximityZone(tag: "mirror", range: ProximityRange.near)
    mirrorZone.onEnter = { zoneContext in
        print("Enter mirror")

        // execute a display action once you get inside the zone
        self.mirrorClient.display(sneakersBanner, onMirror: zoneContext.deviceIdentifier)



protected void onCreate(Bundle savedInstanceState) {

    PosterViewData posterData = /* ...
    ... code from the previous step
    ... */
    final PosterView posterView = new PosterView(posterData, posterStyle);

    // add this at the end of the method:

    //Create a MirrorClient object
    final MirrorClient mirrorClient = new MirrorClient.Builder(this).build();
    //Prepare your Estimote Cloud credentials
    EstimoteCloudCredentials cloudCredentials = EstimoteCloudCredentials(YOUR_APP_ID_HERE, YOUR_APP_TOKEN_HERE);

    //Build ProximityObserver with Cloud credentials
    //You can find here how to build it:
    ProximityObserver proximityObserver =
                new ProximityObserverBuilder(applicationContext, cloudCredentials)
                        .onError(new Function1<Throwable, Unit>() {
                            public Unit invoke(Throwable throwable) {
                                return null;

    //Define a near proximity zone:
    ProximityZone nearZone = new ProximityZoneBuilder()
                .onEnter(new Function1<ProximityZoneContext, Unit>() {
                    public Unit invoke(ProximityZoneContext proximityZoneContext) {

    //Start proximity observation for declared Proximity Zone
    ProximityObserver.Handler observationHandler = proximityObserver.startObserving(nearZone);

protected void onDestroy() {

That’s it! Run the app on your device, and go near the screen. Your poster should pop up shortly.

Important: Remember to check if Bluetooth is on, and to ask for the ACCESS_COARSE_LOCATION runtime permission. This is required for Bluetooth scanning to work.

You can use Estimote’s support library called Mustard. Check Estimote’s guide how to request location permissions using our library.

For more information, see the Request App Permissions Android guide.

What built-in views are available?

We’re starting out with a small set, and expect to enlarge the collection in the future updates. Let us know on forums and/or Display SDKs GitHub what other built-in views you’d like to have at your disposal!


A simple image + text view.

Includes customizable fonts, colors, background, and the text and image positions.


A simple table view, for some row-by-row content.

Includes customizable fonts, colors, background, table header, rows and columns.

Can I build my own view?

If the built-in views are not enough, then…

  • (a) let us know! Tweet at @Estimote, send an email to, or post on our forums. We need your feedback to know what new views/options to add.

  • (b) You can build your own UI with a custom Mirror template. Templates are HTML5 pages/web apps with access to Mirror JavaScript API, which allows them to receive data from mobile apps, and more.

Build your own template