Perks
Understanding perks and how they control access to features
Perks are the features, content, or capabilities that users gain access to when they purchase a product. They're the building blocks of your app's access control system.
What is a Perk?
A perk represents a specific feature or piece of content that can be unlocked through purchases. Think of perks as permissions or entitlements that control what users can access in your app.
Examples of perks:
- Access to premium features
- Ad-free experience
- Unlimited usage
- Priority support
- Exclusive content
- Advanced tools
Creating Perks
Perks are defined in your schema configuration using the unlockablePerk helper:
import { schemaConfiguration, unlockablePerk } from "@voidhash/react-native";
export const sc = schemaConfiguration({
providers: {
googlePlay: true,
appleAppStore: true,
},
perks: {
allAccess: unlockablePerk("all-access", {
name: "All Access",
}),
premiumFeatures: unlockablePerk("premium-features", {
name: "Premium Features",
}),
adFree: unlockablePerk("ad-free", {
name: "Ad-Free Experience",
}),
},
});Perk Configuration
Key (Identifier)
The key is how you reference the perk in your code. It should be camelCase and descriptive. In most cases, it is similar to the slug, just in a .js/.ts friendly way.
schemaConfiguration({
providers: { /* ... */ },
perks: {
allAccess: unlockablePerk(...), // Good
premiumFeatures: unlockablePerk(...), // Good
},
});Slug
The slug is a unique identifier for your perk across Voidhash. It should be lowercase with hyphens or underscores. Do not use spaces or special characters.
unlockablePerk("all-access", { ... }); // Good
unlockablePerk("premium-features", { ... }); // Good
unlockablePerk("AllAccess", { ... }); // Bad: Use lowercaseName
The name is a human-readable display name. It could be shown to users in your app but is primarily used for admin purposes.
unlockablePerk("all-access", {
name: "All Access",
});Assigning Perks to Products
Perks are unlocked by products. When a user purchases a product, all the perks assigned to that product are automatically activated:
export const monthlySub = sc.subscription("monthly_sub", {
name: "Monthly Premium",
perks: {
allAccess: true, // This perk will be unlocked
premiumFeatures: true, // This perk will be unlocked
// adFree not listed, so it stays locked
},
providers: {
// ... providers configuration
},
});Checking Perk Access
TODO: Add documentation about checking perk access.
Perk Lifecycle
Activation
Perks are automatically activated when:
- A user purchases a product that includes the perk
- An active subscription that grants the perk is in good standing
Deactivation
Perks are automatically deactivated when:
- A subscription expires
- A subscription payment fails and grace period ends
Expiration
For subscription-based perks:
- Perks remain active as long as the subscription is active
- When a subscription expires, associated perks are automatically deactivated
- Voidhash handles this synchronization automatically
Perk Strategies
Feature-Based Perks
Group features into logical perks:
export const sc = schemaConfiguration({
providers: {
/* ... */
},
perks: {
basicEditor: unlockablePerk("basic-editor", {
name: "Basic Editor",
}),
advancedEditor: unlockablePerk("advanced-editor", {
name: "Advanced Editor",
}),
exportFeatures: unlockablePerk("export-features", {
name: "Export Features",
}),
},
});Tier-Based Perks
Create perks for different subscription tiers:
export const sc = schemaConfiguration({
providers: {
/* ... */
},
perks: {
basicTier: unlockablePerk("basic-tier", {
name: "Basic Tier",
}),
proTier: unlockablePerk("pro-tier", {
name: "Pro Tier",
}),
enterpriseTier: unlockablePerk("enterprise-tier", {
name: "Enterprise Tier",
}),
},
});
// Products
export const basic = sc.subscription("basic", {
name: "Basic",
perks: {
basicTier: true,
},
providers: {
/* ... */
},
});
export const pro = sc.subscription("pro", {
name: "Pro",
perks: {
basicTier: true,
proTier: true, // Pro gets both basic and pro perks
},
providers: {
/* ... */
},
});Content-Based Perks
Control access to specific content categories:
export const sc = schemaConfiguration({
providers: {
/* ... */
},
perks: {
freeContent: unlockablePerk("free-content", {
name: "Free Content",
}),
premiumContent: unlockablePerk("premium-content", {
name: "Premium Content",
}),
exclusiveContent: unlockablePerk("exclusive-content", {
name: "Exclusive Content",
}),
},
});Best Practices
Hierarchical Access
Design your perks so higher tiers include lower tier perks:
// Free tier gets nothing
export const freeTier = sc.subscription("free", {
name: "Free",
perks: {}, // No perks
providers: {
/* ... */
},
});
// Basic tier gets basic features
export const basicTier = sc.subscription("basic", {
name: "Basic",
perks: {
adFree: true,
},
providers: {
/* ... */
},
});
// Pro tier gets basic + pro features
export const proTier = sc.subscription("pro", {
name: "Pro",
perks: {
adFree: true,
premiumFeatures: true,
},
providers: {
/* ... */
},
});
// Premium tier gets everything
export const premiumTier = sc.subscription("premium", {
name: "Premium",
perks: {
adFree: true,
premiumFeatures: true,
exclusiveContent: true,
prioritySupport: true,
},
providers: {
/* ... */
},
});