Shiny Feature Toggles


Kelly O’Briant


July 17, 2019

At Posit, we recommend staying (or at least starting) within the boundaries of a set of best practices when it comes to the use of our professional products. I write how-to articles that cover basic solutions for Connect based workflows. I would highly encourage you to explore those “basic builds” while you’re learning the ins and outs of Connect.

With that being said, I also believe that a certain amount of exploratory hacking is healthy for product development. Connect is actually an incredibly flexible platform that can enable all sorts of creative solutions.

This post describes a few experimental projects (mad-science hacks) that push the boundaries of what the current Connect feature-set includes; with the hope that it may inspire the development of future functionality.

Shiny Feature Toggles

First, a longish backstory…

I started thinking about feature toggles for shiny application release management while preparing for the Shiny in Production workshop at RStudio Conf last January. We wanted to address the growing popularity of DevOps as a topic of interest to R Admins in the data science community, but at the time our DevOps story was mostly limited to programmatic deployment. In the end, I dropped some placeholders (“thought exercises”) into the course materials and promised myself I’d get back to it.

Particularly, I wanted to explore the idea of maintaining Shiny applications in production in a way that decouples deployments from releases.

  • Deployment is any push of code to an environment (staging, production)
  • Release is when that code (feature) is made available to users or customers

Deployment on demand and thoughtful release strategies allow more control (and more success) over the delivery of features to end users. — DevOps Handbook

My thoughts around DevOps and release patterns are taken directly from The DevOps Handbook and Gene Kim (seeing him speak in person — which I highly recommend!)

There are a whole slew of techniques for accomplishing the decoupling of deployment from release. I became interested in feature toggles (an application-based release pattern) because it sounded like a concept we already have a framework for in Shiny. In fact, there’s an application in the Shiny Gallery that implements something like feature toggles:

Screenshot of two Shiny applications. One shows data that is specific to a particular airline, available only after the user logs in; the second shows a Sales Report personalized for the logged in user.

A feature toggle is simply “A mechanism to selectively enable and disable features, or control which features are visible to specific user segments”.

Feature toggles can be used to deploy changes to production (new features) that are hidden to most/all users and then be tested under production load and incrementally exposed to user groups as your confidence increases.

The Personalized Sales Report shows an implementation of Personalized Data Access — demonstrating the use of authentication to customize the UI according to the privileges of the logged in user.

Screenshots from two views of the same app. On the left, the managers's report shows data for all of the manager's employees. On the right, the sales person's report shows only their data.

On the left you can see the application UI as displayed when a manager logs in. The manager sees all available sales data. On the right you see the same application from the view of a salesperson. Sales people can only view their own sales data.

Shiny applications can access the username and groups of the current user through the session parameter of the shiny server function. The example application leverages this information session$user to output UI elements based on the user conditional.

user <- reactive({

if (is.null(user()){
   ...return elements...

The example app makes use of user conditional tests to:

  • Determine whether or not the user is a manager (reactive)
  • Pull only the data this user is allowed to see (reactive)
  • Render the subtitle of the page according to what user is logged in (output renderText())
  • Generate plot view of the data (output renderPlot())
  • Generate table view of the data (output renderDataTable())

I spent some time playing with this framework from a DevOps perspective — here are my thoughts/learnings:

  • Feature toggles are not easy to manage, automate, test and ultimately “toggle”
  • They are still a cool concept, and potentially useful pattern for solving other types of problems

Will I personally be using or recommending feature toggles for shiny application deployment and releases? No, not likely.

What I gravitated toward instead, is using feature toggles for something else: Connect Feature Hacks!

Mixing Access Controls & Feature Toggles on Connect

As a content publisher, one powerful feature Connect exposes for you is the ability to control who can see the things you create. There are four basic levels of access to choose from:

Screenshot of the Access pane in Connect where publishers can control the access settings for content.

Because the access settings are exposed in the Connect settings panel, it’s easy to update them at any time. My strategy for selecting and changing access level settings depends on the purpose I’ve set for the particular data product and workflow I want to achieve.

Some of my published content is completely private and will remain as such until I choose to remove it from the server — these are my “development/test projects”. It’s also easy to share content with only certain people or groups. Occasionally I may open a piece of content to specific people for testing and feedback before eventually making the content public to everyone.

As a whole, I think about these four levels of access control as environment-based because I’m letting the Connect server manage the execution of those rules. I would classify the Shiny Gallery “Personalized UI” example as application-based access control, because the conditional logic is actually contained within the application logic itself.

What I’m interested in exploring here is the intersection of environment- and application-based access controls, used together, to achieve a new solution. Here are two potential solutions I’ve dreamed up that are the result of layering these two types of access:

A table showing two solutions. First, Connect Access Control set to Anyone, no log in required; Feature Toggle Conditional is `is.null(user(()` TRUE; and the Solution is Custom UI for anonymous visitors.  Second, Connect Access Control set to All users, login required; Feature Toggle Conditional is Group `isCollab()` FALSE; and the Solution is Custom UI for users requesting collaborator access

A custom landing page (UI) for anonymous visitors

“Hey, is it possible to customize this access page on Connect?”

When you get logged out of Connect, or if you’re an anonymous visitor trying to access a piece of content hosted on Connect, you’ll see a screen in place of the content along with an invitation to “Log In”.

I occasionally hear feedback from users that this landing screen would be nice to customize. We love getting this type of feature request feedback because it gives us a sense of how people are interacting with Connect and what product usability issues they care about.

The fact that I’m writing about hacks to do this in Connect today, doesn’t mean that this feature will never make it into the product; I hope instead that it inspires more feedback, reactions or expressions of delight (or disgust !?) to help shape the future direction of our work.

An example of a custom landing page presented to anonymous users

In this scenario, instead of the default “logged out” Connect landing page, I’d like to show anonymous users a little bit more information. Perhaps they’ve discovered this application by clicking on a link to it from an email or an internal dashboard or wiki.

In some cases, it might be appropriate to open the access settings to Anyone, no login required so that these users (still behind your org firewall) can have viewing privileges to the app without needing any knowledge of Connect or needing an account — this is a perfectly acceptable pattern.

Screenshot of the Old Faithful app accessible to anyone, no login required.

The downside to enabling anonymous access is that you won’t be able to track who these new visitors are; which is information that could be used to grow adoption or effectively advocate for the importance of your work.

With a little imagination and the creative use of session$user information, it’s possible to extend the Anyone, no login required access option to display a user-aware application view.

With the addition of session$user and is.null(user()), when the app is set to anyone, no login required, the app can still be aware of the user state to display the custom anonymous user landing page if they are not a user, and otherwise show the app if it is a known user.

This is exactly the same concept that the Shiny Gallery “Personalized UI” application example shows, applied for a slightly different purpose. In this case, anyone with access to the Connect server can discover and view some version of my shiny application. Only visitors with user accounts will be able to see the actual application. Any anonymous visitor who happens to discover my app will see a screen that gives a few details about what they’ve found and instructions for how to go about requesting a user account.

Watch a 20-second video of this application logic in action.

Take it one step further

Once you’ve played around with building application logic around session$user, the next layer I would recommend exploring is session$groups.

If you don’t currently use groups with Connect, have your administrator look into this feature. Groups are managed in different ways depending on the authentication system you have in place. As of Connect 1.7.2, group support has been enabled for all authentication providers.

People tab in the Connect Admin Tools section where Groups can be identified.

Example: As a Connect administrator, I can create a group for the “Solutions Engineering” team and associate all the user accounts for my teammates to that group.

Mixing Connect access control settings with session$groups logic opens up another whole set of creative feature solutions. I’ll cover some of my ideas for these in part two.

Back to top