Skip to end of metadata
Go to start of metadata

Deep linking is the ability to launch the channel and go directly to a piece of content.  Deep linking is used by multiple places in the Roku OS to communicate with your channel.  All public Roku channels are now required to implement deep linking in order to pass certification.  Channels are required to implement it as per this documentation.  

Implementing Deep Linking in a Channel

Deep linking is implemented by sending parameters to the function main().   These launch arguments are passed in an associate array similar to argc in C.   The channel is responsible for parsing those parameters and doing the appropriate action or in the case of an error detecting it and going to the channel's home screen.  Crashing from an invalid deep link will cause you to fail certification. 

Accepting deep linking parameters in Main()

The first step is to modify the Main method to accept the deep linking parameters in BrightScript.  You can name it what you like but in the documentation, we always call it "args"

Function Main (args as Dynamic) as Void

Ad parameter

The first thing you want to do in your channel is parse args.  This first stanza is not required it is just a good idea.   It has nothing to do with deep linking.   You want to know if your channel was launched from an Ad and if so you want to record that fact.   This is fast and independent of all other code so do it first.

if (args.reason = “ad”) then
    if (args.refmarker <> invalid) then
    end if
end if
  • Args.reason - is always there.  It states why the channel was launched.
  • Args.refmarker - almost always will be there.  It is passed when the channel is launched from an ad. This parameter can be used to determine which ad launched the channel.
  • fireAdBeacon() - is a function for any tracking beacons that need to be fired.
    • Note: This is a function that the developer has to write. It is not a Roku SDK function

Am I deep linking or is it just a normal channel launch?

The next thing to do is determine if the channel is being deep linked to.   If it is then args.ContentID and args.MediaType will both be not invalid if you are deep linking.   If either of them are invalid then it is a normal channel launch and both can be safely ignored.

if (args.ContentId <> invalid) and (args.MediaType <> invalid)
end if

Next what kind of deep link are you doing?

You deep link to pieces of content. We break content into types in our system. The type of content that is being deep linked to is passed in via args.MediaType. The required behavior is dependent on args.MediaType.

MediaType must be one of the following values:

MediaTypeContentIDRequired Behavior
"movie"Movie to be playedGo to play the content directly. If the content is paywalled or the user is not authenticated you can redirect to the appropriate screen. The user should be able to play content directly after the required action is performed.
"episode"Episode to be played
"short-form"Item to be played
"series"ContentId of an episode in that seriesGo to the episodic picker screen for this series. Do not autoplay content.
"season"ContentId of an episode in that series and in the desired season.Go to the episodic picker screen for this series. Select the episode who's ContentId was passed in. Do not autoplay the content.

I don't have all of these content!

If you don't have a particular form of content you don't have to implement deep linking for that. For example, a channel which is all speeches would not have movies or series. In that case, I would use "short-form". In general, try to implement "movies" "series" " season" first. Those are what is currently used in Roku Global Search.

More pseudo code :

if (args.ContentId <> invalid) and (args.MediaType <> invalid)
   if (args.mediaType = “movie” ) 
      if (movie_is_free(args.ContentId)
          doSpringBoard(ContentID, Screen)
          doPlayMedia(ContentID, Screen)
   else if (args.mediaType = “short form” or args.mediaType = “Live” or mediaType = “episode”) then
      doplayMedia(ContentID, Screen)
   else if (args.mediaType = “series” or args.MediaType = "season")
      doEpisodicPicker(ContentID, Screen)
    ' Always print an error message.  Don't fail silently
    print “Unknown media type “, args.mediaType
end if

So what is in this ContentId?

The contents of ContentId is a defined by the channel.   As far as Roku is concerned it is just a string less than 255 characters long.   The only restriction we put on it is that it has to be passable as a command line argument in a curl command.   So no "&" characters.   Channels frequently will send multiple values in the ContentId and delimit them with "|".    There is more information about using curl below.

Is the user authenticated?

Something to consider when designing this flow is what to do about unauthenticated users.   Users can deep link to the channel even when the channel is not installed.   This happens via Roku global search and when it happens the system will prompt the user to install the channel before continuing with the deep link.  This means that the first time your channel is launched it is a deep link to a particular piece of content.

The standard for deep linking parameters enforced by Roku to support ads or universal search is that channels use the following parameters:

Some More rules about deep linking

  • When you submit your channels you must send along some standard deep links that will work
  • You are free to add your own other kinds of deep linking.   You just need to make sure you support the standard ones that are relevant to your channel
  • We know our mediaTypes are not exhaustive.  If you think your channel's content does not fit into one of the standard mediaTypes then make up something like mediaType=track or mediaType=playlist that makes sense for your channel.  You are still required to implement deep linking.  We use deep linking with advertisement too.   That is why we require it for all channels.   

How to test your deep link code

We use the ECP commands to test deep linking.   ECP is basically a pseudo web server built into the device.   Here is more information about ECP.   The curl command below does an http post to the Roku at IP address   It launches the side loaded app ("dev") and it passes the ContentID of 1234 and the MediaType of series.   Please note Roku Associative Arrays are not case sensitive so "args[MediaType]" is the same as "args.mediatype" :

curl -d '' ''

Another way to test deep linking is with the deep linking tester app. 

Here is the install link for our old test tools for Luddites like the author: 


  • No labels