Supporting In App Purchases in Your Roku BrightScript Channels

Monetizing applications is a common requirement for software developers. Roku developers are no different. Fortunately, the Roku platform has great support for in-app purchases. This article will cover everything you need to know to start monetizing your Roku channels with subscriptions and other purchases.

To make it easier to understand Roku’s in-app purchase capabilities, I’ve included a simple test channel that supports in-app purchase. This test channel presents a set of products for purchase, and places a check mark next to the ones that the user has already purchased. Selecting one of the products triggers the purchase flow in the channel.  Keep in mind that this sample is very rudimentary and is primarily meant to show how to use the BrightScript in-app purchase APIs.  A production channel would include a lot more purchase flow UI.

The sample channel can be downloaded from this link:
A detailed overview of the Roku billing platform can be found here: Roku Billing Platform

Creating In-App Products

Before you can make purchases from your channel, you need to create products and associate them with your channel. Products are created and managed through your Roku developer account. Log into your Roku account, click Developer Site, and then Manage My In-Channel Products:

After clicking the Manage My In-Channel Products link, you will see a page that lets you create and edit all of your in-app products:

If you press the Add a Product button, you are taken to another screen that allows you to specify the product type, product code, price and other product information.  Product type can be one-time purchase or subscription, with one-time purchases further characterized as either consumable or non-consumable.  A consumable one-time purchase is something like a TVOD video title that you rent and can watch only once.  A non-consumable one-time purchase might represent a video title that you buy through a channel and then have access to forever.  When creating or editing a product, you also specify which of your published channels the product is associated with.  This defines which channels the product can be purchased from.

The roChannelStore and roChannelStoreEvent Components

In-app purchase is implemented via BrightScript using the APIs implemented by the ifChannelStore interface.  This interface is implemented on the roChannelStore component.  This interface includes methods for operations like making purchases, retrieving the list of products available for purchase in a channel, and the subset of those products that the Roku user has already purchased.  In response to any of these calls, the BrightScript event loop will receive an roChannelStoreEvent.  Full documentation of these components can be found here:
roChannelStore and roChannelStoreEvent Docs

Let’s take a look at how these components are used to implement making a purchase. First, the channel creates an roChannelStore instance. Then the BrightScript code needs to create an order and assign it to the roChannelStore instance by calling SetOrder. The channel then calls DoOrder to place the order.

    store = CreateObject("roChannelStore")
    port = CreateObject("roMessagePort")
    order = [{
        code: “TS1”
        qty: 1        
    result = store.DoOrder()
    if (result = true)
        print “Order Succeeded”
        print “Order Failed”

The order object contains two items, the product code of the product to be purchased, and the number of these items to purchase. The product code is defined when the product is created via the Manage In-Channel Products screen. DoOrder returns true if the purchase is successful and false otherwise. Upon a successful purchase, the channel will receive an roChannelStoreEvent. Calling GetResponse on this event returns a variety of information about the transaction, including the purchase ID and product code. The information returned includes tax details.

    while (true)
        msg = wait(0, port)
        if (type(msg) = "roChannelStoreEvent")
	    purchaseDetails = msg.GetResponse()
        end if
    end while

purchaseId = 12345
total = $1.99
qty = 1
amount = $1.99
code = TS1
total = $0.00
qty = 1
amount = $0.00
code = SKUTAX

Your channel can query for all of the products available for purchase in the channel by calling the ifChannelStore function GetCatalog. After calling this function, your channel will receive an roChannelStoreEvent whose GetResponse function will return XML containing information about all of the products associated with the channel.

You can also query for the channel products that the user has purchased by calling the ifChannelStore GetPurchases function. This function results in an roChannelStoreEvent whose GetResponse function returns XML with the subset of the channel products that have been purchased by the user.

Sharing User Account Information

An important in-app purchase use case is purchasing subscriptions. For example, a channel may have a variety of free content such as clips, but require a paid subscription for full-length premium content. Content providers generally require an account with the provider’s service as part of the subscription signup process. To make such registration easier, or to aid in verifying a third party account, the Roku platform can provide the user’s Roku account information to the channel without requiring the user to enter this information via an on-screen keyboard. This is done by calling the ifChannelStore function called GetUserData. Calling this function presents the user with a screen similar to the one shown below:

This screen presents the user with their Roku account information and two buttons labeled Share and Don’t Share.  If the user presses the Don’t Share button, GetUserData returns invalid.  If the user presses Share, GetUserData returns an associative array with the user’s account information.  This information can then be used in content provider service API calls for purposes such as creating or verifying  accounts on the partner service.  Here is a dump of the information returned for the user in the previous screen:

country: US
firstname: Roku
lastname: User
street1: 123 Any Street
state: AL
zip: 12345
city: Anytown

A channel can also request a more limited set of user account information by calling the function GetPartialUserData:

    GetPartialUserData(properties as String) as Object

You pass this function a comma separated list of the user account properties you want, and the function returns an object, like that returned by GetUserData, with just those account values. The data sharing screen that is displayed when calling GetPartialUserData contains only the requested account elements as well. For example, to retreive only the email address and first name of the Roku account holder, you would call:

    GetPartialUserData("email, firstname")

The full set of properties that can be specified in the function argument is:


Testing Channels With In-App Purchase

Channels that support in-app purchase present a few additional challenges when it comes to testing when compared to other channels. In addition to all of the UI flow and other features in a channel, in-app purchase channels need to have products created, and successful and unsuccessful transactions need to be tested. Furthermore, to test purchases with the actual products associated with your channel, your channel needs to be published to the Roku Channel Store as either a public or a non-certified channel. This limits your debugging options. For example, published channels can’t be debugged with the telnet debug console.

Fortunately, there are a number of tools available that make this easier. First, the Roku billing web service includes three test products that can be accessed whenever a channel is side loaded. If a side loaded channel calls the ifChannelStore GetCatalog function, the three products shown below are returned via an roChannelStoreEvent:

Product  1 represents a non-consumable product, while Product 2 is consumable.  There is also a choice which will fail, allowing you to test purchase failures in your side loaded channel.

Another powerful debugging tool is the fake server mechanism.  This is also very useful for testing side loaded channels, but provides much more flexibility that the three fake products just described.  With this technique, your channel uses a set of XML files that simulate the web service request and response data.  A channel indicates that it wants to use the fake server approach by passing true to the ifChannelStore FakeServer function:

store = CreateObject(“roChannelStore”)

In-app purchase API calls will now be driven by the XML files in the channel’s csfake directory:


GetCatalog.xml and GetPurchases.xml simulate the list of products available for purchase in the channel and those products already purchased by the user, respectively. PlaceOrder.xml contains the information about the product to be ordered, and CheckOrder.xml is used to verify the validity of the order. For example, if the <order><id>values in these two files don’t match, the fake server will report an error in the order processing. Using the fake server mechanism, you make the same ifChannelStore function calls to create orders and make purchases, and your channel still receives roChannelStoreEvents.  The difference is that the data used in these call flows is derived from the csfake XML files.

Even with these debugging tools, before publishing your channel you should still test it with real products.  To do this, publish your channel as a non-certified channel, associate your products with the channel, and test a few purchases. To prevent Roku from billing you for these live test purchases, you can define test users and associate them with your channels.  From the developer site, click the Manage Test Users link.  You will be taken to a page like this:

This screen lets you add the Roku account email address of any user (including yourself) who will then be treated as a test user for the set of specified channels.  No purchases in those channels will be charged to those users.  To make live purchase testing even easier, you can void transactions so that the same purchase can be tested more than once if needed.  Press the View link under the Transactions heading for a particular test user and you will get a list of all transactions for that user, plus the option to void transactions. Products must be cleared for sale and approved before your channel can discover them with the ifChannelStore GetCatalog API.

As with any new development topic, the best way to learn the details is to dig into some working code.  So feel free to download the sample channel from here and happy coding!

About Robert Burdick

Roku Developer Support Manager
This entry was posted in Uncategorized. Bookmark the permalink.