Coming soon! A Pro version of the Flipper gem for entirely local installations.

Get Updates

Documentation

Let People Opt-in to New Features

Learn how to user feature flags to let end users opt-in to new functionality on their terms instead of forcing them to adapt on your timeline.

You've been quietly working on a significant new feature in your app, and you're finally ready to release it. You're excited to release it because you know how much of an improvement it represents.

So you push it out the door, and thousands of customers are forced to adjust to the update right in the middle of their workflow. You get dozens of support requests from angry customers who are just trying to get their work done, and you realize just how much people don't like to be forced into a new way of doing things.

There's another way, and with Flipper, it's not even difficult.

Feature flags as preferences?

Instead of pushing significant changes on people, you can use feature flags to ensure those large changes are a better experience for both your customers and your team.

The essence of feature flags is all about incrementally releasing changes in a way that minimizes negative impacts on customers, doesn't break your existing code, doesn't take down your app due to unforeseen performance issues, and provides you a way to revert quickly if something goes wrong.

If launching new features with feature flags lets you slowly roll out a new feature to a wider audience, letting people control their own adaption on their schedule takes it to the next level. Before we get into the implementation details, let's run through the benefits of releasing new features via feature flags as preferences.

Happier Customers

By letting people decide when they're ready to try out a new feature—and turn it off if they don't like it or aren't ready—you're empowering them to make their own decisions instead of forcing them into something on your timeline.

You end up with happier customers because there's never a surprise, and they choose whether they want to help provide feedback or whether they just need it to work and are happy waiting for the final release.

Also, keep in mind that the people most likely to be negatively affected by significant, unexpected changes are the people that use your application the most. They may not be your most vocal supporters, but they're certainly more likely to be some of your best customers. They're definitely not the customers you want to upset and send shopping for alternatives.

Better Feedback

When people opt-in to a feature, they're self-selecting for you. You end up with a more engaged (as opposed to enraged) set of beta testers that want the feature and are happy to provide feedback.

When new features are pushed on people without the ability to opt-in, there's a good chance it won't be changing at a convenient time for them. If they're providing feedback from the perspective of being inconvenienced, they likely aren't going to want to bother providing considered feedback, and they'll be upset on top of it.

Getting feedback from someone who's been inconvenienced is much less likely to be useful and actionable feedback.

Less Support

We've all been there after that large new feature release or design change. No matter how much you notified customers ahead of time or tried to prepare them, not everyone has seen your preparatory announcements or had the time or inclination to prepare for the change.

So you unleash the great new feature, but for a large percentage of your customers, they can't appreciate any new benefits because it just threw them for a loop. All they want is for you to change it back so they can do their job.

Now instead of celebrating the release, you're stuck replying to angry customers. Or worse, the rug pull has them thinking about leaving for a competitor that's more predictable.

Let customers choose between basic and advanced

With any system, there's a delicate balance between simplicity and power. Keeping an interface simple and clean makes it easier to learn, but power users may be alright with a busier interface if it means they can perform tasks in less time or with less interaction.

With feature flags, you can provide a way for some to opt-in to the more advanced features so they can have the added flexibility while leaving others with a less-overwhelming initial experience so they can ease into learning how to use your system.

Using feature flags for opt-in

If you like the idea of all of these benefits, all that's left is making a plan for how to make it happen. If you haven't read our guide on using feature flags to launch new features, you might want to go read through that first to lay the groundwork.

We have a few options when it comes to implementing opt-in feature flags.

Opting in to individual features

Assuming that you're already using feature flags to incrementally share functionality with a wider group of customers or testers, you're not far from letting people opt in or out of a given feature.

With Rails, you could build a preferences controller that acts as a proxy for Flipper. For example, let's say the current_user instance represents your currently-logged-in user.

You would need to make the following call to Flipper:

Flipper.enable(:new_design, current_user)

In that context, you could create a controller dedicated to customer preferences for new features.

app/controllers/new_feature_controller.rb
class LabsController < ApplicationController
  def index
    # Use these to generate the relevant form fields for customers
    @available_features = available_features
  end

  def update
    if available_features.include?(feature)
      toggle(feature, current_user)

      redirect_to action: :index, notice: "Welcome to the beta!"
    else
      redirect_to action: :index, alert: "Uh oh. That's not a valid opt-in feature."
    end
  end

  private

  # Make sure they can turn the feature on or off
  def toggle(feature, user)
    if Flipper.enabled?(feature, user)
      Flipper.disable(feature, user)
    else
      Flipper.enable(feature, user)
    end
  end

  def feature
    params[:feature]&.to_sym
  end

  def available_features
    [:new_design, :advanced_search]
  end
end

Joining an early access group

In addition to opting in to individual features you could let people join an early access group that always gets access to new features. Or you could gate their ability to opt-in to new features by requiring that they belong to the early access group, and then you can control who is in that group the same you would with any other features.

For example, you could use the console to add someone to the early access group, or you could create an administrative tool that lets you add someone to a :beta_testers group so non-technical team members can do it.

# Register a special group with Flipper by checking to see if they've been
# flagged as a beta tester.
Flipper.register(:beta_testers) do |actor, _context|
  actor.respond_to?(:beta_tester?) && actor.beta_tester?
end

# Ensure all beta testers in the group get early access without having to enable
# it manually for each user
Flipper.enable_group(:early_access, :beta_testers)

To use groups, you'd need to have an attribute on the User model that can serve as a flag for knowing when someone is beta tester. The easiest solution is to add a boolean, but you may already have flags for VIPs or a similar group that can be used in a similar fashion.

Or, if there's no existing identifying characteristic/attribute for early access users, and adding one isn't feasible, you can enable them manually on a case-by-case basis. This approach isn't quite as tidy as using Flipper's groups, but it may be all you need.

class EarlyAccess
  attr_reader :email, :user

  FEATURE_KEY = :early_access

  def initialize(email)
    @email = email

    # Ensure there's a valid user with that email address, or it won't work
    # This could also check other status or role-based details to verify
    @user ||= User.find_sole_by(email: email)
  end

  def self.add!(email)
    new(email).enable!
  end

  def self.remove!(email)
    new(email).disable!
  end

  def toggle!
    Flipper.enabled?(FEATURE_KEY, user) ? disable! : enable!
  end

  def enable!
    Flipper.enable(FEATURE_KEY, user)
  end

  def disable!
    Flipper.disable(FEATURE_KEY, user)
  end
end

Then you could use the :early_access flag to allow or prevent access to the opt-in feature flags. Or, maybe you have some feature flags that are available to everyone, but you limit some of the feature flags to your early access customers.

The possibilities are endless, and you have maximum flexibility to design your opt-in features in the way that works best with your data model.

Alternatively, each opt-in feature could get its own group. So instead of a wider "beta testers" group, people would be adding themselves to "feature one testers" or "feature two testers" and opt in or our of features individually.

Toggling simple and advanced mode

Finally, you may want to start customers off with a subset of key features or a simpler interface when they join, and then let them turn on the more advanced functionality once they've found their way around.

This approach is similar to providing preferences or a labs area where people can opt in to features, but instead of opting in to features that have been widely released, they're simply turning on more advanced features that may create a little more clutter or confusion in the interface but allow them to perform an action with less clicking around.

So with this approach, the difference is in the workflow. Those with limit access still have the features, they just don't have as many options for how they use the feature or where they access them from.

This kind of approach works best for exposing shortcuts or interface conveniences that don't provide new functionality, they just provide faster ways to perform actions by adding widgets that might otherwise clutter the interface and overwhelm someone who's in the process of learning their way around your app.

For a quick example, if you have an onboarding process, you can add people to a group as they complete steps. For example, say you create groups for "new", "onboarded", "beginner", "intermediate", and "advanced" users. Then as someone progresses through onboarding or after a set period of time, you can add them to the next group which will expose the additional functionality as they're ready for it.

Wrapping Up

Feature flags are great for slowly expanding a release to more customers, but it doesn't solve the problem that eventually some customers have significant changes forced onto them at inopportune times. It's certainly a great start, but feature flags can do so much more for you and your customers.

Adopting feature flags for more gradual releases is a necessary first step, but you don't want to stop there. Let people have a say in their destiny so they can try out a new feature when they have the time and capacity instead of forcing them to adapt on the fly at a time when they could be navigating a critical deadline.

It's a little more work up front, but once it's in place, the benefit to both you and your customers pays for itself in no time.

Ready to try it out?

Get audit history, rollbacks, advanced permissions, analytics, and all of your projects in one place.


Prefer our Cloudless option?

You can choose from several tiers to sponsor Flipper on GitHub and get some great benefits!

The Friday Deploy

Get updates for all things Flipper—open source and cloud.

Have questions? Need help?

Email us any time or head on over to our documentation or status page for the latest on the app or API.

Ready to take Flipper for a swim?

No credit card required. 14-day free trial. And customer support directly from the developers.