The useUser hook provides functions to manage user identity, attributes, and subscription status in the Superwall SDK.
Basic Usage
import { useUser } from "expo-superwall" ;
function ProfileScreen () {
const { identify , user , subscriptionStatus } = useUser ();
return (
< View >
< Text > User ID: { user ?. appUserId } </ Text >
< Text > Status: { subscriptionStatus ?. status } </ Text >
</ View >
);
}
User Identification
Identify users when they log in to track their behavior and purchases:
Call identify() on login
const { identify } = useUser ();
const handleLogin = async ( userId : string ) => {
try {
await identify ( userId );
console . log ( "User identified:" , userId );
} catch ( error ) {
console . error ( "Failed to identify user:" , error );
}
};
Use consistent user IDs
Use the same ID as your authentication system: // ✅ Good - consistent with your auth system
await identify ( firebaseUser . uid );
await identify ( supabaseUser . id );
await identify ( clerkUser . id );
// ❌ Bad - random or changing IDs
await identify ( `user_ ${ Date . now () } ` );
Sign out when user logs out
const { signOut } = useUser ();
const handleLogout = async () => {
await signOut ();
// User identity is now reset
};
Identification Options
Restore paywall assignments from previous sessions:
await identify ( userId , {
restorePaywallAssignments: true ,
});
When restorePaywallAssignments is true, the SDK attempts to restore the user’s previous paywall variant assignments. This ensures consistent A/B test experiences across sessions.
User Attributes
User attributes help you:
Target specific user segments with paywalls
Personalize paywall content
Track user behavior
Make data-driven decisions
Built-in Attributes
The SDK automatically tracks these attributes:
const { user } = useUser ();
console . log ( user ?. appUserId ); // Your app's user ID
console . log ( user ?. aliasId ); // Superwall's internal alias
console . log ( user ?. applicationInstalledAt ); // ISO date of app install
console . log ( user ?. seed ); // Seed for variant assignment
Custom Attributes
Set custom attributes to enrich user data:
const { update } = useUser ();
// Set attributes directly
await update ({
name: "John Doe" ,
email: "[email protected] " ,
plan: "free" ,
onboardingCompleted: true ,
signupDate: new Date (). toISOString (),
});
Updating Attributes with Functions
Use a function to update based on previous values:
const { update } = useUser ();
// Increment a counter
await update (( oldAttributes ) => ({
... oldAttributes ,
exportCount: ( oldAttributes . exportCount || 0 ) + 1 ,
}));
// Update nested properties
await update (( oldAttributes ) => ({
... oldAttributes ,
preferences: {
... oldAttributes . preferences ,
theme: "dark" ,
},
}));
Practical Examples
User Onboarding
Feature Usage
User Preferences
const { update } = useUser ();
// Track onboarding progress
await update ({
onboardingStep: 3 ,
onboardingCompleted: false ,
});
// After onboarding
await update ({
onboardingCompleted: true ,
onboardingCompletedAt: new Date (). toISOString (),
});
Subscription Status
Track and manage the user’s subscription state:
const { subscriptionStatus } = useUser ();
console . log ( subscriptionStatus ?. status );
// "UNKNOWN" | "INACTIVE" | "ACTIVE"
if ( subscriptionStatus ?. status === "ACTIVE" ) {
console . log ( "Entitlements:" , subscriptionStatus . entitlements );
// [{ id: "premium", type: "SERVICE_LEVEL" }]
}
Subscription Status Types
// Unknown status (initial state)
{ status : "UNKNOWN" }
// User not subscribed
{ status : "INACTIVE" }
// User has active subscription
{
status : "ACTIVE" ,
entitlements : [
{ id: "premium" , type: "SERVICE_LEVEL" },
{ id: "pro_features" , type: "SERVICE_LEVEL" },
]
}
Setting Subscription Status
Manually set status after purchase or restore:
const { setSubscriptionStatus } = useUser ();
// After successful purchase
await setSubscriptionStatus ({
status: "ACTIVE" ,
entitlements: [
{ id: "premium" , type: "SERVICE_LEVEL" },
],
});
// After subscription expires
await setSubscriptionStatus ({
status: "INACTIVE" ,
});
Only use setSubscriptionStatus if you’re managing subscriptions manually. The SDK automatically tracks subscription status when using native purchase flows.
Entitlements
Retrieve detailed entitlement information:
const { getEntitlements } = useUser ();
const entitlements = await getEntitlements ();
console . log ( entitlements );
// {
// active: [{ id: "premium", type: "SERVICE_LEVEL" }],
// inactive: [{ id: "trial", type: "SERVICE_LEVEL" }]
// }
Syncing Subscription Status
Sync subscription status from entitlements:
const { getEntitlements , setSubscriptionStatus } = useUser ();
const syncSubscription = async () => {
const entitlements = await getEntitlements ();
if ( entitlements . active . length > 0 ) {
await setSubscriptionStatus ({
status: "ACTIVE" ,
entitlements: entitlements . active ,
});
} else {
await setSubscriptionStatus ({
status: "INACTIVE" ,
});
}
};
Refreshing User Data
Manually refresh user attributes and subscription status:
const { refresh } = useUser ();
const handleRefresh = async () => {
try {
const updatedAttributes = await refresh ();
console . log ( "User data refreshed:" , updatedAttributes );
} catch ( error ) {
console . error ( "Failed to refresh:" , error );
}
};
Complete Example
Here’s a comprehensive user management implementation:
import { useUser } from "expo-superwall" ;
import { View , Text , Button , TextInput } from "react-native" ;
import { useState , useEffect } from "react" ;
function UserProfileScreen () {
const {
identify ,
update ,
signOut ,
refresh ,
user ,
subscriptionStatus ,
setSubscriptionStatus ,
getEntitlements ,
} = useUser ();
const [ name , setName ] = useState ( "" );
// Load user data on mount
useEffect (() => {
if ( user ?. name ) {
setName ( user . name );
}
}, [ user ]);
const handleLogin = async ( userId : string ) => {
try {
await identify ( userId , {
restorePaywallAssignments: true ,
});
// Set initial user attributes
await update ({
loginAt: new Date (). toISOString (),
platform: Platform . OS ,
});
} catch ( error ) {
console . error ( "Login failed:" , error );
}
};
const handleUpdateProfile = async () => {
await update ({
name ,
profileUpdatedAt: new Date (). toISOString (),
});
};
const handleLogout = async () => {
await signOut ();
setName ( "" );
};
const handleRefresh = async () => {
const updatedData = await refresh ();
console . log ( "Refreshed:" , updatedData );
};
const syncSubscriptionStatus = async () => {
const entitlements = await getEntitlements ();
if ( entitlements . active . length > 0 ) {
await setSubscriptionStatus ({
status: "ACTIVE" ,
entitlements: entitlements . active ,
});
}
};
return (
< View style = { { padding: 20 } } >
< Text style = { { fontSize: 24 , marginBottom: 20 } } > User Profile </ Text >
{ user ? (
< View >
< Text > User ID: { user . appUserId } </ Text >
< Text > Alias: { user . aliasId } </ Text >
< Text > Installed: {new Date ( user . applicationInstalledAt ). toLocaleDateString () } </ Text >
< View style = { { marginTop: 20 } } >
< Text > Subscription: { subscriptionStatus ?. status } </ Text >
{ subscriptionStatus ?. status === "ACTIVE" && (
< Text >
Entitlements: { subscriptionStatus . entitlements . map ( e => e . id ). join ( ", " ) }
</ Text >
) }
</ View >
< TextInput
value = { name }
onChangeText = { setName }
placeholder = "Name"
style = { { borderWidth: 1 , padding: 10 , marginTop: 20 } }
/>
< Button title = "Update Profile" onPress = { handleUpdateProfile } />
< View style = { { marginTop: 20 } } >
< Button title = "Refresh Data" onPress = { handleRefresh } />
< Button title = "Sync Subscription" onPress = { syncSubscriptionStatus } />
< Button title = "Logout" onPress = { handleLogout } color = "red" />
</ View >
</ View >
) : (
< View >
< Text > Not logged in </ Text >
< Button
title = "Login"
onPress = { () => handleLogin ( "user_123" ) }
/>
</ View >
) }
</ View >
);
}
export default UserProfileScreen ;
User Attribute Patterns
Onboarding
Feature Usage
User Segmentation
A/B Testing
Track onboarding progress: await update ({
onboardingStep: currentStep ,
onboardingCompleted: false ,
onboardingStartedAt: new Date (). toISOString (),
});
Track feature adoption: await update (( prev ) => ({
... prev ,
featuresUsed: [ ... ( prev . featuresUsed || []), "pdf_export" ],
lastActiveAt: new Date (). toISOString (),
}));
Segment users for targeting: await update ({
userType: "power_user" ,
segment: "high_value" ,
documentsCreated: 50 ,
daysActive: 30 ,
});
Store experiment assignments: await update ({
experimentVariant: "variant_b" ,
experimentAssignedAt: new Date (). toISOString (),
});
Best Practices
Call identify() as soon as you have a user ID: useEffect (() => {
if ( authUser ?. uid ) {
identify ( authUser . uid );
}
}, [ authUser ]);
Use meaningful attribute names
Choose clear, consistent names:
✅ onboardingCompleted, lastActiveAt, documentsCreated
❌ flag1, temp, x
Keep attributes up to date
Update attributes when relevant events occur: // On document creation
await update (( prev ) => ({
... prev ,
documentsCreated: ( prev . documentsCreated || 0 ) + 1 ,
}));
Don't store sensitive data
Avoid storing:
Passwords
Credit card numbers
Social security numbers
Private personal information
Next Steps
Handling Subscriptions Learn about subscription status and entitlements
Integration Attributes Link third-party analytics and attribution platforms