Get User Data
This API only available when paywall is in client mode.
Retrieve comprehensive user information including profile, subscription status, token balances, and purchase history.
Overview
The paywall.getUser()
method provides complete user information for authenticated users, including:
- Profile information - name, email, avatar, and creation date
- Subscription status - active subscriptions and payment history
- Token balances - remaining tokens for each action type (tokenized paywalls)
- Geographic data - country matching and tier information
- Trial status - active subscription trials
Authentication Required: This method requires user authentication. For unauthenticated users, it returns a 401 error with basic country information.
API Reference
Method Signature
paywall.getUser(): Promise<GetUserResponse>
Response Types
Authenticated Response
interface GetUserResponse {
/** User profile information */
user: User;
/** Array of user's balance information */
balances: Balance[];
/** Whether user's country matches allowed countries */
countryMatch: boolean;
/** User's country tier level */
tier: number;
/** User's country code */
country: string;
/** Array of user's purchases/subscriptions */
purchases: Purchase[];
/** Whether user has active paid subscription or lifetime payment */
paid: boolean;
/** If user has active subscription trial otherwise undefined */
trial?: {
startedAt: string;
expiresAt: string;
}
}
Subscription Statuses
Status | Description |
---|---|
active | Subscription is in good standing and the most recent payment is successful. Safe to provision your product. |
incomplete | A successful payment needs to be made within 23 hours to activate the subscription, or payment requires action like customer authentication. |
incomplete_expired | Initial payment failed and no successful payment was made within 23 hours of creating the subscription. |
past_due | Payment on the latest invoice failed or wasn’t attempted. Subscription continues to create invoices. |
canceled | Subscription has been canceled. This is a terminal state that can’t be updated. |
unpaid | Latest invoice hasn’t been paid but subscription remains. You should revoke access to your product. |
Paid Status: If user has active subscription or lifetime payment, then paid
is true
.
Basic Usage
Check User Authentication
try {
const userInfo = await paywall.getUser();
if (userInfo.paid) {
console.log('User has active subscription or lifetime payment');
showPremiumFeatures();
} else {
console.log('User needs subscription');
showPaywall();
}
} catch (error) {
if (error.message.includes('401') || error.message.includes('Unauthorized')) {
console.log('User not authenticated');
showLoginPrompt();
} else {
console.error('Failed to fetch user info:', error);
}
}
Check Token Balances
const checkTokenBalances = async () => {
try {
const userInfo = await paywall.getUser();
// Check standard tokens
const standardTokens = userInfo.balances.find(b => b.type === 'standard');
if (standardTokens) {
console.log(`User has ${standardTokens.count} standard tokens`);
}
// Check advanced tokens
const advancedTokens = userInfo.balances.find(b => b.type === 'advanced');
if (advancedTokens) {
console.log(`User has ${advancedTokens.count} advanced tokens`);
}
} catch (error) {
console.error('Failed to check balances:', error);
}
};
Practical Examples
Subscription Status Handler
const handleSubscriptionStatus = async () => {
try {
const userInfo = await paywall.getUser();
// Check overall paid status
if (userInfo.paid) {
enablePremiumFeatures();
} else {
showUpgradePrompt();
}
// Check specific subscription status
const activeSubscription = userInfo.purchases.find(p => p.status === 'active');
if (activeSubscription) {
const daysUntilRenewal = Math.ceil(
(new Date(activeSubscription.current_period_end) - new Date()) / (1000 * 60 * 60 * 24)
);
console.log(`Subscription renews in ${daysUntilRenewal} days`);
if (activeSubscription.cancel_at_period_end) {
showCancellationNotice(activeSubscription.current_period_end);
}
}
} catch (error) {
console.error('Failed to check subscription:', error);
}
};
Trial Status Checker
const checkTrialStatus = async () => {
try {
const userInfo = await paywall.getUser();
if (userInfo.trial) {
const trialEnd = new Date(userInfo.trial.expiresAt);
const now = new Date();
const daysRemaining = Math.ceil((trialEnd - now) / (1000 * 60 * 60 * 24));
if (daysRemaining > 0) {
console.log(`Trial expires in ${daysRemaining} days`);
showTrialBanner(daysRemaining);
} else {
console.log('Trial has expired');
showTrialExpiredMessage();
}
} else {
console.log('No active trial');
}
} catch (error) {
console.error('Failed to check trial:', error);
}
};
Feature Access Control
const checkFeatureAccess = async (requiredTokenType, requiredTokenCount = 1) => {
try {
const userInfo = await paywall.getUser();
// Check if user has paid subscription
if (userInfo.paid) {
return { allowed: true, reason: 'paid_subscription' };
}
// Check token balance for tokenized features
const tokenBalance = userInfo.balances.find(b => b.type === requiredTokenType);
if (tokenBalance && tokenBalance.count >= requiredTokenCount) {
return { allowed: true, reason: 'sufficient_tokens', remaining: tokenBalance.count };
}
return { allowed: false, reason: 'insufficient_access' };
} catch (error) {
if (error.message.includes('Unauthorized')) {
return { allowed: false, reason: 'not_authenticated' };
}
throw error;
}
};
React User Profile Component
import { useState, useEffect } from 'react';
function UserProfile() {
const [userInfo, setUserInfo] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchUserInfo = async () => {
try {
const info = await paywall.getUser();
setUserInfo(info);
setError(null);
} catch (err) {
if (err.message.includes('Unauthorized')) {
setError('Please sign in to view your profile');
} else {
setError('Failed to load user information');
}
} finally {
setLoading(false);
}
};
fetchUserInfo();
}, []);
if (loading) {
return <div>Loading user information...</div>;
}
if (error) {
return (
<div>
<p>{error}</p>
<button onClick={() => paywall.open({ resolveEvent: 'signed-in' })}>
Sign In
</button>
</div>
);
}
return (
<div>
<div style={{ display: 'flex', alignItems: 'center', gap: '16px' }}>
<img
src={userInfo.user.avatar}
alt="Avatar"
style={{ width: '50px', height: '50px', borderRadius: '50%' }}
/>
<div>
<h3>{userInfo.user.name}</h3>
<p>{userInfo.user.email}</p>
</div>
</div>
<div style={{ marginTop: '20px' }}>
<h4>Subscription Status</h4>
{userInfo.paid ? (
<span style={{ color: 'green' }}>✓ Active Subscription</span>
) : (
<span style={{ color: 'orange' }}>⚠ No Active Subscription</span>
)}
</div>
{userInfo.balances.length > 0 && (
<div style={{ marginTop: '20px' }}>
<h4>Token Balances</h4>
{userInfo.balances.map(balance => (
<div key={balance.type}>
{balance.type}: {balance.count} tokens
</div>
))}
</div>
)}
</div>
);
}
Error Handling
const safeGetUser = async () => {
try {
const userInfo = await paywall.getUser();
return { success: true, data: userInfo };
} catch (error) {
if (error.message.includes('Unauthorized') || error.message.includes('401')) {
return {
success: false,
error: 'unauthorized',
message: 'User not authenticated'
};
} else {
return {
success: false,
error: 'unknown',
message: 'An unexpected error occurred'
};
}
}
};
Data Examples
Authenticated User Response
{
user: {
id: "user_123456789",
email: "john.doe@example.com",
name: "John Doe",
avatar: "https://example.com/avatars/user_123456789.jpg",
created_at: "2024-01-15T10:30:00Z"
},
balances: [
{ type: "standard", count: 150 },
{ type: "advanced", count: 25 }
],
countryMatch: true,
tier: 1,
country: "US",
purchases: [
{
status: "active",
current_period_start: "2024-02-01T00:00:00Z",
current_period_end: "2024-03-01T00:00:00Z",
cancel_at_period_end: false,
created: "2024-02-01T00:00:00Z"
}
],
paid: true,
trial: {
startedAt: "2024-01-15T10:30:00Z",
expiresAt: "2024-01-22T10:30:00Z"
}
}
Next Steps
Last updated on