
How to calculate feature adoption rate (with code examples)
You shipped a new feature last sprint. Product wants to know if anyone's using it. The PM asks for "the adoption rate." Sounds straightforward until you realize there are at least four different formulas, each producing a different number from the same data.
Feature adoption rate measures what percentage of your users have meaningfully engaged with a specific capability. The keyword is "meaningfully." A user clicking a button once during an accidental hover isn't adoption. Getting this metric right determines whether your team invests more in the feature or kills it.
This tutorial walks through the standard formula, three variants that account for real-world complexity, and working React code you can drop into your codebase today.
npm install @tour-kit/adoption @tour-kit/reactWhat is feature adoption rate?
Feature adoption rate is the percentage of users who have meaningfully engaged with a specific product capability, calculated as (Feature Users / Total Active Users) × 100. As of April 2026, the median core feature adoption rate across B2B SaaS products is 16.5%, with an average of 24.5% according to Userpilot's Benchmark Report (n=181 companies). Most teams overestimate their rates because they count anyone who saw the feature, not those who actually used it.
Why feature adoption rate matters for React teams
Product analytics tools hand you page views and click counts, but adoption rate answers the harder question: are users actually getting value from what you built? When we tracked adoption across Tour Kit's own feature set, the gap between "clicked once" and "used three times" cut our numbers by more than half. That distinction drives three concrete decisions.
First, resource allocation. A feature with 6% adoption across 10,000 MAUs means 9,400 people ignore it. Either the feature is poorly discoverable, solves the wrong problem, or targets the wrong audience. Each diagnosis leads to a different fix.
Second, churn prediction. Users who adopt new features are 31% less likely to churn than those who don't (Chameleon, 2025). Identify non-adopters early and you can intervene with targeted onboarding before they leave.
Third, the 30-day cliff. Andrew Chen's research shows 90% of mobile users disappear within 30 days. For web apps the curve is less steep, but the principle holds: feature discovery in the first week matters more than monthly adoption rates. Measuring adoption with time buckets (day 1, day 7, day 30) reveals whether your onboarding pipeline is working.
How to calculate feature adoption rate
Four distinct formulas exist for calculating feature adoption rate, each producing a different number from identical data. The standard formula works for universally available features, but gated features, depth thresholds, and velocity measurements each require their own variant. Here are all four with TypeScript implementations you can copy into your codebase.
The standard formula
// src/lib/adoption-rate.ts
type AdoptionResult = {
rate: number
featureUsers: number
totalUsers: number
}
function calculateAdoptionRate(
featureUsers: number,
totalActiveUsers: number
): AdoptionResult {
if (totalActiveUsers === 0) return { rate: 0, featureUsers: 0, totalUsers: 0 }
return {
rate: (featureUsers / totalActiveUsers) * 100,
featureUsers,
totalUsers: totalActiveUsers,
}
}
// Example: 300 users tried chat / 1,000 total = 30%
const result = calculateAdoptionRate(300, 1000)
// → { rate: 30, featureUsers: 300, totalUsers: 1000 }This works for features available to everyone. But what about gated features?
The eligible-user variant
When a feature is restricted by plan tier, user role, or permissions, using total active users as the denominator deflates your rate. A feature available only to your 400 paid users shouldn't be measured against all 1,000.
// src/lib/adoption-rate.ts
function calculateEligibleAdoptionRate(
featureUsers: number,
eligibleUsers: number
): AdoptionResult {
if (eligibleUsers === 0) return { rate: 0, featureUsers: 0, totalUsers: 0 }
return {
rate: (featureUsers / eligibleUsers) * 100,
featureUsers,
totalUsers: eligibleUsers,
}
}
// 200 paid users tried the feature / 400 paid users total = 50%
// vs 200 / 1,000 all users = 20% — very different signal
const gatedResult = calculateEligibleAdoptionRate(200, 400)
// → { rate: 50, featureUsers: 200, totalUsers: 400 }The distinction between total users, eligible users, and target users is one that most product blogs skip. Smashing Magazine's TARS framework goes further, defining "target users" as those who actually have the problem the feature solves (a subset of even eligible users).
The depth-adjusted formula
A user who clicked a feature once during a random exploration isn't an adopter. The depth-adjusted formula requires a minimum engagement threshold before counting a user as "adopted."
// src/lib/adoption-rate.ts
type DepthConfig = {
minUses: number
windowDays: number
}
function calculateDepthAdjustedRate(
users: Array<{ userId: string; useCount: number; lastUsed: Date }>,
totalActiveUsers: number,
config: DepthConfig = { minUses: 3, windowDays: 30 }
): AdoptionResult {
const cutoff = new Date()
cutoff.setDate(cutoff.getDate() - config.windowDays)
const adopters = users.filter(
(u) => u.useCount >= config.minUses && u.lastUsed >= cutoff
)
return {
rate: totalActiveUsers === 0 ? 0 : (adopters.length / totalActiveUsers) * 100,
featureUsers: adopters.length,
totalUsers: totalActiveUsers,
}
}The industry convention is 3 uses within 30 days, but the right threshold depends on the feature. A daily workflow tool (task manager, editor) should require weekly usage. A monthly reporting feature might only need 1 use per month.
Adoption velocity
Adoption rate is a snapshot. Velocity tracks whether adoption is accelerating or stalling.
// src/lib/adoption-rate.ts
function calculateAdoptionVelocity(
rateAtT1: number,
rateAtT2: number,
daysBetween: number
): number {
// Returns percentage points per day
return (rateAtT2 - rateAtT1) / daysBetween
}
// Week 1: 5% adoption. Week 2: 12% adoption.
const velocity = calculateAdoptionVelocity(5, 12, 7)
// → 1.0 percentage points/day — healthy launch curveTop-quartile enterprise SaaS products hit 7-10% daily adoption velocity during a core feature launch window. If your velocity drops below 1% per day in the first two weeks, the feature has a discovery problem.
Benchmarks: what good looks like
A 24.5% adoption rate sounds low until you learn the median is 16.5% and most niche features sit at 6.4% across all B2B SaaS products (Userpilot 2024, Pendo). Context changes everything, and the right benchmark depends on whether your feature is core, secondary, or niche. Here's the breakdown by feature importance, sourced from studies covering 181+ companies.
| Feature tier | Target adoption | Median reality | Source |
|---|---|---|---|
| Core / defining features | 60-80% | 24.5% | Userpilot 2024 |
| Secondary features | 30-50% | ~16% | Pendo benchmark |
| Niche / advanced features | 5-30% | 6.4% | Pendo all-feature median |
Pendo considers 28% a "good" adoption rate for core features. The top 10% of products hit 15.6% across all features — 2.5x the industry average of 6.4%.
Industry matters too. HR products lead at 31% average core feature adoption. FinTech and Healthcare sit around 22.6-22.8%. And counterintuitively, sales-led companies (26.7%) slightly outperform product-led ones (24.3%), possibly because sales teams provide direct feature training during onboarding.
One data point that should bother you: the gap between target (60-80%) and reality (24.5%) for core features. That gap represents the discoverability problem. Users don't reject features. They never find them.
How to track feature adoption rate in React
We tested two approaches when building Tour Kit's adoption tracking: a minimal custom hook for simple cases (under 5 features) and a declarative provider for anything larger. The custom hook took about 30 lines but fell apart once we needed per-feature thresholds, churn detection, and nudge logic. Here's both approaches so you can pick the right one for your scale.
Custom hook approach
// src/hooks/use-feature-adoption.ts
import { useCallback, useEffect, useRef } from 'react'
type FeatureEvent = {
featureId: string
userId: string
timestamp: number
}
export function useFeatureAdoption(
featureId: string,
userId: string,
onTrack?: (event: FeatureEvent) => void
) {
const tracked = useRef(false)
const trackUsage = useCallback(() => {
const event: FeatureEvent = {
featureId,
userId,
timestamp: Date.now(),
}
// Send to your analytics backend
onTrack?.(event)
// Persist locally for offline resilience
const key = `adoption:${featureId}:${userId}`
const existing = JSON.parse(localStorage.getItem(key) ?? '{"count":0}')
existing.count += 1
existing.lastUsed = event.timestamp
localStorage.setItem(key, JSON.stringify(existing))
}, [featureId, userId, onTrack])
return { trackUsage, tracked: tracked.current }
}This works for a handful of features. But once you're tracking 10+ features with different adoption criteria, nudge logic, and analytics integration, the boilerplate adds up fast.
Using @tour-kit/adoption
Tour Kit's adoption package handles the tracking engine, status calculation, and nudge scheduling out of the box. You define features declaratively and the library manages the rest.
// src/providers/adoption-setup.tsx
import { AdoptionProvider } from '@tour-kit/adoption'
import type { Feature } from '@tour-kit/adoption'
const features: Feature[] = [
{
id: 'dark-mode',
name: 'Dark mode',
trigger: '[data-feature="dark-mode"]', // CSS selector
adoptionCriteria: { minUses: 3, recencyDays: 30 },
category: 'settings',
},
{
id: 'export-csv',
name: 'CSV export',
trigger: { event: 'export:csv' }, // Custom event
adoptionCriteria: { minUses: 1, recencyDays: 60 },
category: 'data',
priority: 2,
},
]
export function AppProviders({ children }: { children: React.ReactNode }) {
return (
<AdoptionProvider features={features}>
{children}
</AdoptionProvider>
)
}Then query adoption state from any component:
// src/components/feature-callout.tsx
import { useFeature, IfNotAdopted, NewFeatureBadge } from '@tour-kit/adoption'
function ExportButton() {
const { isAdopted, useCount, trackUsage, status } = useFeature('export-csv')
return (
<div>
<button onClick={trackUsage}>
Export CSV
<IfNotAdopted featureId="export-csv">
<NewFeatureBadge>New</NewFeatureBadge>
</IfNotAdopted>
</button>
{/* Status: 'not_started' | 'exploring' | 'adopted' | 'churned' */}
{status === 'exploring' && <span>Used {useCount} times</span>}
</div>
)
}The AdoptionStatus type gives you four states: not_started (never used), exploring (used but below the adoption threshold), adopted (meets criteria), and churned (was adopted but hasn't been used within the recency window). That last one is particularly useful. It's the signal that a previously engaged user is drifting.
Tour Kit doesn't include its own analytics dashboard. It's a headless library that tracks state and fires callbacks. You wire it into PostHog, Mixpanel, Amplitude, or your own backend. That's a deliberate tradeoff: you keep full control of your data pipeline, but you won't get a pre-built dashboard out of the box. Tour Kit requires React 18+ and TypeScript, so it won't fit every stack.
Five ways to improve feature adoption rate
Improving feature adoption rate requires addressing discoverability, measurement accuracy, and user segmentation before touching the feature itself. In our experience building Tour Kit's adoption tracking, the biggest gains came not from UI changes but from fixing how we counted adopters. Here's what actually moves the number.
1. Fix discoverability first. As Smashing Magazine's TARS research notes, "Sometimes low feature adoption has nothing to do with the feature itself, but rather where it sits in the UI." Before assuming users don't want the feature, verify they can find it. Contextual tooltips placed where users already look outperform modal announcements.
2. Segment your denominator. If you're measuring adoption against all users when only 30% have the relevant use case, you'll always underperform benchmarks. Use the eligible-user or target-user formula instead.
3. Set different thresholds per feature type. A search bar needs daily usage to count as adopted. A quarterly reporting tool needs 1 use per quarter. One-size-fits-all thresholds distort your data.
4. Measure time-to-adopt, not just adoption rate. Litmus saw a 22x increase in adoption for one feature by targeting users within their first 72 hours using in-app messaging (Appcues case study). The speed of discovery matters as much as the final percentage.
5. Check accessibility. This is the blind spot no product analytics blog covers: features with accessibility gaps have artificially low adoption rates because some users physically cannot use them. Run an axe-core audit on the feature's UI before concluding users aren't interested.
Tools for feature adoption tracking
The adoption tracking market splits into two categories: all-in-one platforms that bundle guidance with analytics (Pendo, Appcues) and composable tools where you pick separate layers for tracking, visualization, and in-app messaging. React teams building their own stack tend toward the composable approach because it avoids vendor lock-in on your event pipeline.
| Tool | Approach | Best for | Adoption tracking |
|---|---|---|---|
| PostHog | Open source, developer-first | Engineering teams | Native feature flags + custom events |
| Mixpanel | Event-based, no-code queries | Growth teams | Event segmentation and funnels |
| Amplitude | Behavioral cohorting | Cross-functional teams | Behavioral cohorting and paths |
| Pendo | Usage intelligence + guidance | Enterprise PM teams | Strong benchmarks, feature tagging |
| Tour Kit | Headless React library | React teams owning their stack | Declarative tracking + nudge engine |
Appcues and Userpilot focus on in-app guidance but have limited analytics capabilities. Appcues doesn't offer product analytics features like funnels and paths. If you need both guidance and tracking, pairing a headless library like Tour Kit with PostHog or Mixpanel gives you full control over both layers.
FAQ
What is a good feature adoption rate for SaaS?
Feature adoption rate benchmarks vary by feature tier. Core features should target 60-80% adoption, though the median across B2B SaaS is 24.5% as of 2024 (Userpilot, n=181). Secondary features target 30-50%, and niche features sit at 5-30%. Pendo considers 28% a "good" rate for core features. The right benchmark depends on whether you're measuring against all users or only eligible users with access to the feature.
How do you calculate feature adoption rate in React?
Create a custom hook that tracks usage events per feature per user, persists counts to localStorage or your analytics backend, and compares against a configurable threshold. Tour Kit's useFeature hook handles this with a declarative config: pass adoptionCriteria: { minUses: 3, recencyDays: 30 } and get back isAdopted, status, and useCount. The formula is (users meeting threshold / total eligible users) × 100.
What is the difference between feature adoption and product adoption?
Product adoption measures whether users regularly engage with your application overall. Feature adoption zooms in on a single capability within the product. A user can be a daily active user (high product adoption) while ignoring 80% of your features (low feature adoption). Tracking both reveals whether users are getting surface-level value or deep value from your product.
Does feature adoption rate affect churn?
Users who regularly adopt new features are 31% less likely to churn than those who don't (Chameleon, 2025). Feature adoption serves as a leading indicator: declining feature engagement often precedes cancellation by 30-60 days. Tracking adoption velocity (the rate of change, not just the snapshot) gives your retention team earlier warning signals than monthly adoption checks.
How often should you measure feature adoption rate?
Measure daily during the first two weeks after a feature launch to track adoption velocity. After the launch window, switch to weekly snapshots for actively promoted features and monthly for mature features. The key metric during launch is velocity (percentage points gained per day), not the absolute rate. Top-quartile enterprise products hit 7-10% daily velocity during core feature launches.
Get started with Tour Kit — headless adoption tracking and product tours for React. Check the docs or install with npm install @tour-kit/adoption.
Related articles

Behavioral triggers for product tours: event-based onboarding
Build event-based product tours that trigger on user actions, not timers. Code examples for click, route, inactivity, and compound triggers in React.
Read article
Cohort analysis for product tours: finding what works
Build cohort analysis around product tour events to measure retention impact. Step-level tracking, trigger-type segmentation, and Tour Kit code examples.
Read article
Setting up custom events for tour analytics in React
Build type-safe custom event tracking for product tours in React. Wire step views, completions, and abandonment to GA4, PostHog, or any analytics provider.
Read article
DAU/MAU ratio and onboarding: how tours improve stickiness
Learn how DAU/MAU ratio connects to product onboarding quality. See benchmarks, formulas, and code examples for tracking tour-driven stickiness in React.
Read article