Targeting Rules
Targeting rules allow you to control which users see specific features or variations based on their attributes, behavior, and context. This enables precise feature delivery and personalized experiences.
What Are Targeting Rules?
Targeting rules are conditions that determine whether a user should receive a feature or variation. They evaluate user attributes against defined criteria to make targeting decisions.
import { DarkFeatureClient } from '@darkfeature/sdk-javascript'
const client = new DarkFeatureClient({
apiKey: '1234567890abcdef1234567890abcdef',
context: {
userId: '123',
email: '[email protected]',
plan: 'premium',
country: 'US',
device: 'mobile',
},
})
// The platform automatically evaluates targeting rules
const isEnabled = await client.getFeature('premium-feature', {
fallback: false,
})
// Returns true if user.plan === 'premium'
Types of Targeting
1. User Attribute Targeting
Target based on user properties.
// Configure in dashboard to target premium users
const targeting = {
rules: [
{
attribute: 'user.plan',
operator: 'equals',
value: 'premium',
},
],
}
// Configure in dashboard to target specific email domains
const targeting = {
rules: [
{
attribute: 'user.email',
operator: 'ends_with',
value: '@company.com',
},
],
}
2. Geographic Targeting
Target users by location.
// Configure in dashboard to target specific countries
const targeting = {
rules: [
{
attribute: 'user.country',
operator: 'in',
value: ['US', 'CA', 'UK'],
},
],
}
// Configure in dashboard to target by region
const targeting = {
rules: [
{
attribute: 'user.region',
operator: 'equals',
value: 'North America',
},
],
}
3. Device Targeting
Target based on device characteristics.
// Configure in dashboard to target mobile users
const targeting = {
rules: [
{
attribute: 'user.device',
operator: 'equals',
value: 'mobile',
},
],
}
// Configure in dashboard to target specific browsers
const targeting = {
rules: [
{
attribute: 'user.browser',
operator: 'in',
value: ['chrome', 'firefox'],
},
],
}
4. Behavioral Targeting
Target based on user behavior.
// Configure in dashboard to target new users
const targeting = {
rules: [
{
attribute: 'user.signup_date',
operator: 'greater_than',
value: '2024-01-01',
},
],
}
// Configure in dashboard to target active users
const targeting = {
rules: [
{
attribute: 'user.last_login',
operator: 'greater_than',
value: '2024-01-01',
},
],
}
Targeting Operators
Comparison Operators
// Equals
{
attribute: 'user.plan',
operator: 'equals',
value: 'premium'
}
// Not equals
{
attribute: 'user.plan',
operator: 'not_equals',
value: 'free'
}
// Greater than
{
attribute: 'user.age',
operator: 'greater_than',
value: 18
}
// Less than
{
attribute: 'user.age',
operator: 'less_than',
value: 65
}
// Greater than or equal
{
attribute: 'user.purchase_count',
operator: 'greater_than_or_equal',
value: 5
}
// Less than or equal
{
attribute: 'user.purchase_count',
operator: 'less_than_or_equal',
value: 10
}
String Operators
// Contains
{
attribute: 'user.email',
operator: 'contains',
value: 'admin'
}
// Starts with
{
attribute: 'user.email',
operator: 'starts_with',
value: 'test'
}
// Ends with
{
attribute: 'user.email',
operator: 'ends_with',
value: '@company.com'
}
// Regex match
{
attribute: 'user.email',
operator: 'regex',
value: '^admin@.*\\.com$'
}
Array Operators
// In array
{
attribute: 'user.country',
operator: 'in',
value: ['US', 'CA', 'UK']
}
// Not in array
{
attribute: 'user.country',
operator: 'not_in',
value: ['CN', 'RU']
}
// Array contains
{
attribute: 'user.tags',
operator: 'array_contains',
value: 'premium'
}
Using Targeting in Code
Basic Targeting
import { DarkFeatureClient } from '@darkfeature/sdk-javascript'
const client = new DarkFeatureClient({
apiKey: '1234567890abcdef1234567890abcdef',
context: {
userId: '123',
email: '[email protected]',
plan: 'premium',
country: 'US',
},
})
// The platform automatically evaluates targeting rules
const isEnabled = await client.getFeature('premium-features', {
fallback: false,
})
if (isEnabled) {
showPremiumFeatures()
} else {
showBasicFeatures()
}
Context Override
// Override context for specific requests
const isEnabled = await client.getFeature('premium-features', {
fallback: false,
context: { plan: 'premium' },
})
Dynamic Context
// Update context based on user actions
client.setContext({
userId: user.id,
email: user.email,
plan: user.plan,
lastLogin: new Date().toISOString(),
device: navigator.userAgent.includes('Mobile') ? 'mobile' : 'desktop',
})
// All subsequent feature evaluations will use this context
const isEnabled = await client.getFeature('mobile-optimized', {
fallback: false,
})
Multiple Features with Targeting
// Get multiple features with targeting
const features = await client.getFeatures({
features: {
'premium-features': false,
'beta-features': false,
'mobile-optimized': false,
},
context: {
userId: '123',
plan: 'premium',
device: 'mobile',
},
})
if (features['premium-features']) {
showPremiumFeatures()
}
if (features['beta-features']) {
showBetaFeatures()
}
if (features['mobile-optimized']) {
applyMobileOptimizations()
}
Advanced Targeting Patterns
Percentage Rollouts
// Configure percentage rollout in dashboard
// The platform automatically handles percentage-based targeting
const isEnabled = await client.getFeature('new-feature', { fallback: false })
if (isEnabled) {
showNewFeature()
} else {
showOldFeature()
}
Time-based Targeting
// Configure time-based rules in dashboard
const isEnabled = await client.getFeature('holiday-promo', { fallback: false })
if (isEnabled) {
showHolidayPromotion()
}
Complex Conditional Logic
// Configure complex rules in dashboard
const isEnabled = await client.getFeature('advanced-feature', {
fallback: false,
})
if (isEnabled) {
showAdvancedFeature()
}
React Integration
Basic Usage
import { DarkFeatureProvider, useFeature } from '@darkfeature/sdk-react'
function App() {
return (
<DarkFeatureProvider
config={{
apiKey: '1234567890abcdef1234567890abcdef',
context: {
userId: '123',
plan: 'premium',
country: 'US',
},
}}>
<MyComponent />
</DarkFeatureProvider>
)
}
function MyComponent() {
const { feature: isEnabled } = useFeature('premium-features', {
fallback: false,
})
return isEnabled ? <PremiumFeatures /> : <BasicFeatures />
}
Dynamic Context
import { useDarkFeatureContext } from '@darkfeature/sdk-react'
function UserProfile() {
const { updateContext, context } = useDarkFeatureContext()
const handleUpgrade = () => {
updateContext({
...context,
plan: 'premium',
upgradeDate: new Date().toISOString(),
})
}
return (
<div>
<h2>Current Plan: {context.plan || 'free'}</h2>
<button onClick={handleUpgrade}>Upgrade to Premium</button>
</div>
)
}
Server-Side Targeting
Express.js Middleware
import express from 'express'
import { DarkFeatureClient } from '@darkfeature/sdk-javascript'
const app = express()
const client = new DarkFeatureClient({
apiKey: process.env.DARKFEATURE_API_KEY,
})
// Middleware to add feature flags with targeting
app.use(async (req, res, next) => {
const context = {
userId: req.user?.id,
email: req.user?.email,
plan: req.user?.plan,
country: req.get('CF-IPCountry'), // Cloudflare country header
userAgent: req.get('User-Agent'),
}
req.features = await client.getFeatures({
features: {
'premium-features': false,
'beta-features': false,
'mobile-optimized': false,
},
context,
})
next()
})
app.get('/api/data', async (req, res) => {
if (req.features['premium-features']) {
res.json({ data: 'premium-data', features: ['advanced', 'priority'] })
} else {
res.json({ data: 'basic-data', features: ['standard'] })
}
})
Fastify Plugin
import Fastify from 'fastify'
import { DarkFeatureClient } from '@darkfeature/sdk-javascript'
const fastify = Fastify()
const client = new DarkFeatureClient({
apiKey: process.env.DARKFEATURE_API_KEY,
})
// Plugin to add feature flags with targeting
fastify.addHook('preHandler', async (request, reply) => {
const context = {
userId: request.user?.id,
email: request.user?.email,
plan: request.user?.plan,
country: request.headers['cf-ipcountry'],
userAgent: request.headers['user-agent'],
}
request.features = await client.getFeatures({
features: {
'premium-features': false,
'beta-features': false,
},
context,
})
})
fastify.get('/api/dashboard', async (request, reply) => {
const data = { dashboard: 'basic' }
if (request.features['premium-features']) {
data.enhanced = true
data.features = ['advanced-analytics', 'priority-support']
}
return data
})
Best Practices
Context Management
// Provide comprehensive user context
const context = {
userId: user.id,
email: user.email,
plan: user.plan,
country: user.country,
device: user.device,
browser: user.browser,
signupDate: user.signupDate,
lastLogin: user.lastLogin,
purchaseCount: user.purchaseCount,
tags: user.tags,
}
client.setContext(context)
Testing Targeting Rules
// Test targeting rules with different contexts
const testContexts = [
{ plan: 'free', country: 'US' },
{ plan: 'premium', country: 'US' },
{ plan: 'premium', country: 'CA' },
{ email: '[email protected]', plan: 'free' },
]
for (const context of testContexts) {
const isEnabled = await client.getFeature('premium-features', {
fallback: false,
context,
})
console.log(`Context: ${JSON.stringify(context)}, Enabled: ${isEnabled}`)
}
Performance Optimization
// Cache targeting results when appropriate
const cache = new Map()
async function getFeatureWithCache(featureName, context, fallback = false) {
const cacheKey = `${featureName}-${JSON.stringify(context)}`
if (cache.has(cacheKey)) {
return cache.get(cacheKey)
}
const result = await client.getFeature(featureName, { fallback, context })
cache.set(cacheKey, result)
return result
}
Error Handling
try {
const isEnabled = await client.getFeature('premium-features', {
fallback: false,
})
// Use feature
} catch (error) {
console.error('Targeting evaluation error:', error)
// Fallback to default behavior
showDefaultFeatures()
}
Next Steps
- Feature Flags - Learn about flag types and configuration
- Analytics - Track and analyze targeting effectiveness
- Environments - Manage targeting across environments
- Best Practices - Follow proven targeting patterns
Last updated on