Guide

Feature Flags Powered by License Keys: The Complete Implementation Guide

TOT
Traffic Orchestrator Team
Engineering
March 14, 2026 13 min read 706 words
Share

Feature flags determine what users can do. License keys determine who can do it. When you combine them, you get entitlement-based feature gating — the foundation of modern SaaS monetization. Instead of "is this feature on or off?" you ask "does this customer's license include this feature?"

Why License-Driven Feature Flags?

  • Revenue segmentation — Different plans unlock different features
  • Self-service upgrades — Users see locked features and can upgrade instantly
  • Graceful downgrades — When a subscription ends, features are soft-locked, not deleted
  • Trial management — Unlock all features during trial, then lock to their paid tier
  • Enterprise customization — Per-customer feature sets without code deploys

Architecture: License as the Source of Truth

Your license validation response should include a features array that your application uses to gate UI and functionality:

// License validation response
{
  "valid": true,
  "plan": "professional",
  "features": [
    "analytics",
    "custom-domains",
    "api-access",
    "team-management",
    "priority-support",
    "webhooks"
  ],
  "limits": {
    "domains": 10,
    "apiCalls": 100000,
    "teamMembers": 25
  }
}

Client-Side Feature Gating

// Check features after validation
const license = await validateLicense(key, domain)

// UI gating
if (license.features.includes('analytics')) {
  showAnalyticsDashboard()
} else {
  showUpgradePrompt('analytics', license.plan)
}

// API gating
if (!license.features.includes('webhooks')) {
  return Response.json({
    error: 'feature_not_available',
    message: 'Webhooks are available on Professional plans and above',
    upgrade: '/pricing'
  }, { status: 403 })
}

Feature Tiers: Designing Your Matrix

Map each feature to the minimum plan tier required. This matrix drives your pricing page, your validation logic, and your upgrade prompts.

FeatureBuilderStarterProfessionalBusinessEnterprise
Basic License Validation
Domain Binding131050Unlimited
Analytics Dashboard
API Access
Team Management
Webhooks
Custom Branding
SSO / SAML
SLA Guarantee
Dedicated Support

Upgrade Prompts: Converting Users

When a user encounters a locked feature, the experience should guide them toward upgrading — not frustrate them. The best upgrade prompts are:

  • Contextual — Show the prompt where the feature would appear, not in a separate page
  • Specific — "Unlock analytics with Starter ($29/mo)" beats "Upgrade your plan"
  • Visual — Show a preview or screenshot of the locked feature
  • One-click — Minimum friction from "I want this" to "I have this"
  • Reversible — "Try free for 14 days" removes risk from the upgrade decision
// Contextual upgrade prompt
const showUpgradePrompt = (feature, currentPlan) => {
  const upgradePlan = getMinimumPlan(feature)
  const price = getPlanPrice(upgradePlan)
  
  return `
    <div class="feature-locked">
      <div class="feature-preview">
        <img src="/previews/${feature}.webp" alt="${feature} preview" />
        <div class="feature-overlay">
          <h3>${getFeatureTitle(feature)}</h3>
          <p>Available on ${upgradePlan} and above</p>
          <a href="/pricing" class="upgrade-btn">
            Upgrade to ${upgradePlan} — ${price}/mo
          </a>
        </div>
      </div>
    </div>
  `
}

Server-Side Enforcement

Client-side feature gating is for UX. Server-side enforcement is for security. Always verify feature entitlements on the server before processing requests.

// Middleware: enforce feature entitlement
const requireFeature = (feature) => async (req, res, next) => {
  const license = await validateLicense(req.headers.authorization)
  
  if (!license.valid) {
    return res.status(401).json({ error: 'invalid_license' })
  }
  
  if (!license.features.includes(feature)) {
    return res.status(403).json({
      error: 'feature_not_available',
      feature,
      requiredPlan: getMinimumPlan(feature),
      currentPlan: license.plan,
      upgrade: '/pricing'
    })
  }
  
  req.license = license
  next()
}

// Usage
app.get('/api/analytics', requireFeature('analytics'), analyticsHandler)
app.post('/api/webhooks', requireFeature('webhooks'), webhookHandler)

Graceful Downgrades

When a customer downgrades or lets their subscription lapse, don't delete their data. Instead:

  1. Soft-lock features — Show the data but disable editing
  2. Grace period — Give 14 days before locking (payment retries happen)
  3. Data preservation — Keep analytics, configurations, and history intact
  4. Easy re-upgrade — One click to restore access without re-configuration

A/B Testing Premium Features

Use feature flags to test whether a feature should be included in a lower tier. Give a random subset of Starter users access to a Professional feature for 30 days, then measure:

  • Does usage of the feature increase overall engagement?
  • Does it drive more upgrades to Professional?
  • Does including it in Starter reduce Professional conversions?

Implementation Checklist

  1. Define your feature matrix — which features belong to which plans
  2. Include features in your license validation response
  3. Implement client-side UI gating with contextual upgrade prompts
  4. Add server-side middleware that enforces feature entitlements
  5. Build graceful downgrade flows with data preservation
  6. Instrument feature usage for analytics
  7. Test upgrade flows end-to-end before launch
TOT
Traffic Orchestrator Team
Engineering

The engineering team behind Traffic Orchestrator, building enterprise-grade software licensing infrastructure used by developers worldwide.

Was this article helpful?
Get licensing insights delivered

Engineering deep-dives, security advisories, and product updates. Unsubscribe anytime.

Share this article
Free Plan Available

Ship licensing in your next release

5 licenses, 500 validations/month, full API access. Set up in under 5 minutes — no credit card required.

2-minute setup No credit card Cancel anytime