The first-time user experience (FTUE) is the 2-5 minutes between "app opened for the first time" and "user understands the product." It's the most important experience in the entire app lifecycle because it determines whether the user comes back tomorrow. Deep links change the FTUE fundamentally: a user who arrived via a product link has different needs than one who found the app organically.
For improving completion rates, see Improving Onboarding Completion Rates. For personalization with deep link data, see Personalized Onboarding Flows with Deep Link Data.

The First 30 Seconds
What Users Decide Instantly
Users form three judgments in the first 30 seconds:
- Is this what I expected? (Does the app match what the ad/link promised?)
- Can I figure this out? (Is the interface clear enough to navigate?)
- Is this worth my time? (Do I see value or potential value?)
If any answer is "no," the user leaves. Deep link context helps you answer "yes" to all three by showing relevant content immediately.
First Screen Strategy
function FirstScreen({ deepLinkContext }) {
// If we know what they want, skip the welcome
if (deepLinkContext.productId) {
return <ProductView productId={deepLinkContext.productId} isFirstTime={true} />;
}
if (deepLinkContext.referrer) {
return <ReferralWelcome referrer={deepLinkContext.referrer} />;
}
if (deepLinkContext.category) {
return <CategoryBrowse category={deepLinkContext.category} isFirstTime={true} />;
}
// Organic: show value proposition
return <ValueProposition />;
}
For organic users (no deep link context), the first screen should communicate value in one sentence and one action. For strategies on reducing friction at this stage, see reducing onboarding drop-off.
function ValueProposition() {
return (
<Screen>
<Headline>
Track your fitness goals in one place.
</Headline>
<Subtext>
Join 2 million people who use [App] to stay on track.
</Subtext>
<Button primary onPress={startSetup}>
Get Started
</Button>
<Button secondary onPress={explorFirst}>
Explore First
</Button>
</Screen>
);
}
Empty States
The Cold Start Problem
New users see empty screens everywhere: no projects, no connections, no history, no data. Empty states are where most FTUE failures happen.
Anti-Patterns
| Bad Empty State | Why It Fails |
|---|---|
| "No items yet" | Tells the user nothing about what to do |
| Blank white screen | Feels broken |
| "Add your first item" with no context | User doesn't know what an "item" is yet |
| Complex tutorial overlay on an empty screen | No content to learn from |
Effective Empty States
Each empty state should include three elements:
- What belongs here (explain the screen's purpose)
- Why it matters (value of filling this screen)
- How to start (a single, clear CTA)
function EmptyProjectList() {
return (
<EmptyState>
<Illustration source={projectsIllustration} />
<Heading>Your projects live here</Heading>
<Text>
Create a project to start tracking your work.
Most people start with their current task.
</Text>
<Button onPress={() => navigation.navigate('CreateProject')}>
Create Your First Project
</Button>
</EmptyState>
);
}
Pre-Populated Content
For some apps, the best empty state is not empty:
function FirstTimeFeed({ user }) {
// Show curated content based on interests or deep link context
const starterContent = getStarterContent(user.interests || ['popular']);
return (
<FlatList
data={starterContent}
ListHeaderComponent={
<Banner>
<Text>Here's some content to get you started. Follow topics to customize your feed.</Text>
</Banner>
}
renderItem={({ item }) => <ContentCard item={item} />}
/>
);
}
The First Action
Identifying the First Action
The first action is the single thing the user should do to experience core value:
| App Type | First Action | Why |
|---|---|---|
| Productivity | Create a project/document | Experiences the editor |
| Social | Follow 3 people | Gets a populated feed |
| E-commerce | Browse and save a product | Sees the catalog |
| Fitness | Log a workout | Uses the core feature |
| Finance | Connect a bank account | Sees their data |
| Music | Play a song or create a playlist | Experiences the product |
Guiding to the First Action
function FirstActionGuide({ appType, deepLinkContext }) {
// If deep link points to specific content, that IS the first action
if (deepLinkContext.productId) {
return <ProductDetail productId={deepLinkContext.productId} />;
}
// Otherwise, guide to the first action
const action = getFirstAction(appType);
return (
<Card highlighted>
<Icon name={action.icon} />
<Heading>{action.title}</Heading>
<Text>{action.description}</Text>
<Button onPress={() => navigation.navigate(action.screen)}>
{action.ctaText}
</Button>
</Card>
);
}
Templates and Samples
Reduce friction by providing starting points:
function FirstProjectFlow() {
return (
<Screen>
<Heading>Start your first project</Heading>
<TemplateGrid>
<TemplateCard
name="Personal To-Do"
description="A simple task list to get started"
onSelect={() => createFromTemplate('personal_todo')}
/>
<TemplateCard
name="Team Project"
description="Track work with your team"
onSelect={() => createFromTemplate('team_project')}
/>
<TemplateCard
name="Blank Project"
description="Start from scratch"
onSelect={() => createFromTemplate('blank')}
/>
</TemplateGrid>
</Screen>
);
}
Templates convert better than "create from scratch" because they show the user what a completed project looks like, reducing uncertainty.
Deep Link Context in FTUE
Contextual Value Proposition
Adapt the value proposition to the user's context:
function getValueProp(context) {
if (context.source === 'fitness_ad') {
return {
headline: 'Your personal fitness tracker',
subtext: 'Log workouts, track progress, and hit your goals.',
cta: 'Start Your First Workout',
};
}
if (context.source === 'social_share') {
return {
headline: `See what ${context.sharerName} shared with you`,
subtext: 'View the content and join the conversation.',
cta: 'View Shared Content',
};
}
if (context.referrer) {
return {
headline: `${context.referrerName} uses [App] every day`,
subtext: 'Sign up and you both earn a reward.',
cta: 'Claim Your Reward',
};
}
return {
headline: 'Welcome to [App]',
subtext: 'The simplest way to [core value].',
cta: 'Get Started',
};
}
Skip-to-Content for Deep Link Users
Users who arrive via content links should see the content before anything else:
function handleFirstLaunchDeepLink(context) {
if (context.contentId) {
// Show content immediately, onboard later
return {
firstScreen: 'ContentView',
params: { contentId: context.contentId },
onboardAfterContent: true,
};
}
if (context.productId) {
// Show product, onboard at purchase
return {
firstScreen: 'ProductDetail',
params: { productId: context.productId },
onboardAfterContent: true,
};
}
// No specific content, start normal onboarding
return {
firstScreen: 'Onboarding',
params: {},
onboardAfterContent: false,
};
}
Feature Discovery
Progressive Reveal
Don't show every feature in the FTUE. Show the minimum needed to accomplish the first action. Our guide on progressive onboarding covers this approach in depth.
const featureVisibility = {
firstSession: ['create', 'view', 'search'],
afterFirstAction: ['share', 'save', 'edit'],
afterThirdSession: ['export', 'analytics', 'integrations'],
afterFirstWeek: ['automation', 'advanced_settings', 'api'],
};
function getVisibleFeatures(user) {
if (user.sessionCount === 0) return featureVisibility.firstSession;
if (user.hasCompletedFirstAction === false) return featureVisibility.firstSession;
if (user.sessionCount < 3) return [...featureVisibility.firstSession, ...featureVisibility.afterFirstAction];
if (user.daysSinceSignup < 7) return [...featureVisibility.firstSession, ...featureVisibility.afterFirstAction, ...featureVisibility.afterThirdSession];
return Object.values(featureVisibility).flat();
}
Inline Hints
Instead of separate tutorials, embed hints directly in the interface:
function CreateButton({ isFirstTime }) {
return (
<View>
<Button onPress={handleCreate}>Create</Button>
{isFirstTime && (
<Hint
text="Tap here to create your first item"
arrow="up"
autoDismiss={5000}
/>
)}
</View>
);
}
Measuring FTUE Success
Key Metrics
| Metric | Definition | Target |
|---|---|---|
| First action rate | % who complete the first action | > 50% |
| Time to first action | Seconds/minutes from app open to first action | < 3 minutes |
| Session depth | Screens viewed in first session | 5-10 screens |
| Return rate (Day 1) | % who open the app the next day | > 25% |
| Activation rate | % who reach the "aha moment" | > 30% |
FTUE by Source
async function ftueBySource(dateRange) {
const sources = ['organic', 'referral', 'ad', 'content_share'];
for (const source of sources) {
const users = await getFirstTimeUsers(dateRange, { source });
const activated = users.filter(u => u.firstActionCompleted);
const returned = users.filter(u => u.returnedDay1);
console.log(source, {
users: users.length,
firstActionRate: (activated.length / users.length * 100).toFixed(1) + '%',
day1ReturnRate: (returned.length / users.length * 100).toFixed(1) + '%',
});
}
}
Users from content shares and referrals should have the highest first action rates because they arrive with context and motivation. For more tips on optimizing the full onboarding experience, see onboarding best practices in 2026.
For deep linking features, see Tolinku deep linking. For onboarding use cases, see the onboarding documentation.
Get deep linking tips in your inbox
One email per week. No spam.