Customize the UI of your Button on

Customize the UI of your Button

Note: This document is a work in progress and interfaces here may be subject to change prior to release. It does however accurately reflect the approach to accessing the data that we ourselves use to build Buttons & Commerce Cards.

Dropin Buttons provide a range of visual customization and can accommodate almost all uses. Should you require further flexibility you can access the underlying data that we use to build the Buttons and Commerce Cards as well as being able to invoke cards yourself. This guide will run you through the basics of building your own Button UI.

We'll begin by introducing some concepts and classes that we will use throughout this guide.

App Action

BTNAppAction is the main class that you will use when interacting with Button data. It consists of the objects that make up the Preview and Card which we will discuss in detail later.

Getting a BTNAppAction is simple. Create a context object as you would to populate a Button (outlined here) and call fetchAppActionWithButtonId:context:completion: with your Button ID and a callback handler. You can find your Button ID in the Button Dashboard where you'll also find more Context code samples.

// import Button

let venue: BTNLocation = "<#location_name#>", latitude: <#latitude#>, longitude: <#longitude#>)
let context: BTNContext = BTNContext.init(subjectLocation: location)

// Replace YOUR_BUTTON_APP_ID with your App ID from the Button Dashboard
Button.shared().configure(withApplicationId: "<#YOUR_BUTTON_APP_ID#>") { (configError: Error?) -> Void in
  if let error = configError {
    print("Error: \(error.localizedDescription)")

return true

// @import Button;

BTNLocation *venue = [BTNLocation locationWithName:@"Parm" latitude:40.723027 longitude:-73.9956459];
BTNContext *context = [BTNContext contextWithSubjectLocation:venue];

[[Button sharedButton] fetchAppActionWithButtonId:@"<#YOUR_BUTTON_APP_ID#>" context:context completion:^(BTNAppAction *appAction, NSError *error) {
  if (error) {
    NSLog(@"Error: %@", error.localizedDescription);
Note: Sometimes, there's no inventory available based on the context for the Button. In such cases, we recommend hiding your UI element (see `else` in code snippet above).

Key Methods

  • -preview
  • -invokeActionForListItem:
  • -invokePreviewAction
  • -fetchPreviewIconImageWithCompletion: - completes with the preview image
  • -trackButtonViewed

Advanced Methods

  • -header
  • -groups
  • -product
  • -footer


The `BTNPreview` object rendered as a button

The Preview object is the first component on the BTNAppAction that you will use. It consists of an icon -iconImage.URL (A in the image above) and a title -labelText.text (B in the image above) and is the object used to populate the default Button in our SDK.

A preview object can have an action (invokePreviewAction on BTNAppAction) if there's a direct action associated with it, but in most cases the preview itself will not have a default action & you will need to either use an action from one of the Inventory items or use the built-in Commerce Card to allow the user to choose one.

When the user views the BTNAppAction you should call -trackButtonViewed on the action to report the View for funnel analysis.

Key Methods

  • -iconImage.URL (note you can load the image via -[BTNAppAction fetchPreviewIconImageWithCompletion:])
  • -titleText.text (Optional)
  • -labelText.text

Button Commerce Card

Once you have displayed a preview, you can choose whether to show the underlying inventory or not. If you do want to show the user inventory you can either use the built-in Button Commerce Card or create your own. To make your own, continue reading this guide.

To display the Button Commerce Card for a BTNAppAction you can call -invokePreviewAction and the user will be presented with the built-in Button Commerce Card and UI flow. A simple way to achieve a custom Button is to render the Preview yourself and to call -invokePreviewAction from the onTouchUpInside event from your control. The remainder of the Button flow will run from that point on (Attended Installation, deep link etc..)

Types of Cards

An App Action will always have a preview, but from there on things can be a little different. The Card that it's designed to populate will dictate what data is available. For the purposes of this guide, there are two types of Card:

Grouped Inventory Card

BTNAppActions that represent a grouped inventory card will return an array of one or more BTNGroup objects from -groups. This contains the inventory items which are available for this BTNAppAction.

A card representing groups (New York, Boston etc...) and inventory (individual show locations)

The BTNHeader A object is available as -header and represents a heading describing the inventory.

The BTNGroup object B represents a number of inventory items C. The inventory items are individual actions each of which can be invoked by calling BTNAppAction -invokeActionForListItem:.

The Footer object D can also be invoked with -invokeFooterAction and is considered as an alternative or fallback action, the inventory items will be more detailed & useful for the user than the footer.


  • -titleText.text A
  • -subtitleText.text A


  • -labelText.text
  • -iconImage.URL

Inventory Items

BTNGroups are logical groups B of BTNListItems C which we recommend that you reflect in your UI. If BTNAppAction -groups returns one or more groups there is inventory available.

  • -titleText.text B
  • -items C

Each group has one or more Inventory items, there's no guarantee to minimum or maximum number of items so your UI should be flexible to handle this. The inventory items can be invoked BTNAppAction -invokeActionForListItem:, triggering either the action or an app installation that will trigger the action after installation completes.

An inventory item.

When displaying an Inventory item, the following fields are available to you. Calling BTNAppAction -invokeActionForListItem: will cause the Button SDK to invoke the action and perform an AttendedInstall if the app is not currently installed.

  • -titleText.text A
  • -subtitleText.text B
  • -iconText.text D
  • -iconImage.URL C

Product Card

Coming soon.

UI Guidelines

Merchants on the Button Marketplace expect that their brand be represented appropriately and within agreed upon guidelines. Before releasing a product using the Custom Button UI, you will need to contact us at to confirm partner approval.

More details on UI Guidelines coming soon.

Visual Customization

Buttons are rendered on the fly, but there is still room for customization. Maybe you need to change the size of the icon to match your other icons, or bump the left margin over ever so slightly. You can easily adjust the look of your Button using the provided appearance proxy attributes defined on BTNDropinButton.

As you can see above, the Button doesn't quite match the rest of the UI. We can change that with the following:

BTNDropinButton.appearance().contentInsets = UIEdgeInsetsMake(0.0, 16.0, 0.0, 15.0)
BTNDropinButton.appearance().iconSize = 26.0
BTNDropinButton.appearance().iconLabelSpacing = 13.0
BTNDropinButton.appearance().font = UIFont.systemFont(ofSize: 16.0)
BTNDropinButton.appearance().textColor =
[[BTNDropinButton appearance] setContentInsets:UIEdgeInsetsMake(0.0, 16.0, 0.0, 15.0)];
[[BTNDropinButton appearance] setIconSize:26.0];
[[BTNDropinButton appearance] setIconLabelSpacing:13.0];
[[BTNDropinButton appearance] setFont:[UIFont systemFontOfSize:16.0]];
[[BTNDropinButton appearance] setTextColor:[UIColor blackColor]];

There are many appearance attributes available to style your Button:

Attribute Default Purpose
cornerRadius 0 The radius to use when drawing rounded corners on the button.
borderWidth 0 The width of the Button's border.
borderColor black The color of the Button's border.
iconSize 24pt The size of the Button's icon (applied as aspect fit inside a square frame this size).
iconLabelSpacing 10pt The spacing between the icon and the text.
font AvenirNext-Regular The font used display text on the Button.
textCase BTNDropinButtonTextCaseDefault Defines the string case of the dropin button text. Values: BTNDropinButtonTextCaseDefault, BTNDropinButtonTextCaseUpper, BTNDropinButtonTextCaseDefaultLower
tintColor nil The color to apply to the text of the Button.
highlightedTintColor nil The color to apply to the text of the Button when highlighted.
textColor black The color to apply to the Button's text (superceeds tintColor).
highlightedTextColor nil The color to apply to the Button's text when highlighted.
normalBackgroundColor nil The background color of the Button in the normal state (i.e. not highlighted)
highlightedBackgroundColor nil The background color of the Button when highlighted.
contentAlignment BTNDropinContentAlignmentDefault The alignment for the text and image in the Button. Values: BTNDropinContentAlignmentDefault, BTNDropinContentAlignmentCenter

Keep in mind that appearance proxy attributes apply to every instance of BTNDropinButton. This greatly simplifies styling, as you only have to do it once, and you can do it from anywhere in your app. You can also customize these properties on a single instance of a button.

Should you need to apply different styles in different view controllers, make your view controller conform to the UIAppearanceContainer protocol:

class MyViewController: UIAppearanceContainer {
  // ...
@interface MyViewController <UIAppearanceContainer>

You'll then be able to specify the appearance based on the container like so:

let buttonAppearance: BTNDropinButton = BTNDropinButton.appearance(whenContainedInInstancesOf: MyViewController)
buttonAppearance.tintColor =
BTNDropinButton *buttonAppearance = [BTNDropinButton appearanceWhenContainedIn:[MyViewController class], nil];
[buttonAppearance setTintColor:[UIColor blueColor]];