Mobile devices have become the primary computing platform for billions of people worldwide. For many, particularly in developing nations and underserved communities, smartphones are the only internet-connected device they own. A mobile-first approach to digital therapeutics is not just convenient - it's essential for equitable access.
| Metric | Global Data | Implication | Design Response |
|---|---|---|---|
| Mobile-Only Internet Users | 2.5 billion (31% of global population) | No desktop/laptop access | Full feature parity on mobile |
| Avg Daily Phone Usage | 3-4 hours | High engagement opportunity | Microlearning, brief interventions |
| Push Notification Open Rate | 7-10% (mental health apps: 15-20%) | Effective for reminders | Thoughtful notification strategy |
| Mobile App Retention (Day 30) | 5-10% average, 25-35% for health apps | Engagement critical | Gamification, progress visualization |
| Offline Usage Scenarios | 40% of time in areas with poor connectivity | Offline capability essential | Local storage, background sync |
The WIA-MENTAL-001 standard recommends React Native for cross-platform mobile development, enabling a single codebase to serve both iOS and Android while maintaining native performance and UX quality.
// Mobile App Architecture
// Core Dependencies
{
"dependencies": {
"react": "18.2.0",
"react-native": "0.72.0",
"@react-navigation/native": "^6.1.0",
"@react-navigation/stack": "^6.3.0",
// State Management
"@reduxjs/toolkit": "^1.9.5",
"react-redux": "^8.1.0",
"redux-persist": "^6.0.0",
// Offline & Sync
"@react-native-async-storage/async-storage": "^1.19.0",
"@react-native-community/netinfo": "^9.4.0",
// Security
"react-native-keychain": "^8.1.0",
"react-native-encrypted-storage": "^4.0.3",
// Health Integration
"react-native-health": "^1.19.0",
"@react-native-community/google-fit": "^0.2.0",
// Notifications
"@react-native-firebase/messaging": "^18.0.0",
"@react-native-firebase/analytics": "^18.0.0",
// Media
"react-native-track-player": "^4.0.0",
"react-native-video": "^5.2.1",
// Biometrics
"react-native-biometrics": "^3.0.1"
}
}
// App Structure
interface MobileApp {
navigation: NavigationContainer;
store: ReduxStore;
modules: {
auth: AuthModule;
therapy: TherapyModule;
assessment: AssessmentModule;
progress: ProgressModule;
messaging: MessagingModule;
resources: ResourceModule;
};
services: {
api: APIService;
sync: SyncService;
notifications: NotificationService;
health: HealthKitService;
analytics: AnalyticsService;
};
}
// Offline-First Data Strategy
class OfflineDataManager {
private localDB: SQLite.Database;
private syncQueue: SyncOperation[];
async saveTherapySession(session: TherapySession): Promise {
// Save locally first
await this.localDB.execute(
`INSERT INTO therapy_sessions
(id, data, synced)
VALUES (?, ?, ?)`,
[session.id, JSON.stringify(session), false]
);
// Add to sync queue
this.syncQueue.push({
type: 'CREATE',
entity: 'session',
data: session,
timestamp: Date.now()
});
// Attempt immediate sync if online
if (await this.isOnline()) {
await this.syncData();
}
}
async syncData(): Promise {
const online = await this.isOnline();
if (!online) {
return { success: false, reason: 'offline' };
}
const operations = [...this.syncQueue];
const results = [];
for (const op of operations) {
try {
await this.executeSync(op);
await this.markSynced(op);
this.syncQueue = this.syncQueue.filter(q => q !== op);
results.push({ op, success: true });
} catch (error) {
results.push({ op, success: false, error });
}
}
return {
success: results.every(r => r.success),
results
};
}
private async isOnline(): Promise {
const netInfo = await NetInfo.fetch();
return netInfo.isConnected && netInfo.isInternetReachable;
}
}
Mobile platforms offer unique capabilities that can enhance therapeutic interventions beyond what's possible on desktop web applications.
| Capability | Therapeutic Application | Technical Implementation | Privacy Considerations |
|---|---|---|---|
| Camera & Photos | Mood tracking via facial expressions, photo journaling | react-native-camera, ML Kit face detection | All processing on-device, no photo uploads |
| Microphone | Voice journaling, speech pattern analysis | react-native-audio-recorder-player | Encrypted local storage, opt-in only |
| GPS Location | Context-aware prompts, activity tracking | react-native-geolocation-service | Minimal accuracy, general areas only |
| Accelerometer | Physical activity detection, sleep monitoring | react-native-sensors | Aggregated data only, no raw sensor logs |
| Health App Integration | Sleep, exercise, heart rate data | Apple HealthKit, Google Fit | User-controlled permissions |
| Biometric Auth | Face ID/Touch ID for secure access | react-native-biometrics | Device-level, no biometric data stored |
// Example: Location-based mindfulness prompts
class ContextAwarePrompts {
private geofences: Geofence[] = [];
async setupGeofences(userId: string): Promise {
// User defines helpful reminder locations
this.geofences = [
{
id: 'home',
latitude: 37.7749,
longitude: -122.4194,
radius: 100, // meters
prompt: 'Taking a moment to practice mindfulness?',
action: 'breathing-exercise'
},
{
id: 'work',
latitude: 37.7849,
longitude: -122.4094,
radius: 200,
prompt: 'Stressful day? Try a 3-minute breathing space.',
action: '3-minute-breathing-space'
}
];
await GeofencingService.register(this.geofences);
}
async onGeofenceEnter(geofenceId: string): Promise {
const geofence = this.geofences.find(g => g.id === geofenceId);
if (!geofence) return;
// Check if user wants notifications right now
const userPrefs = await this.getUserPreferences();
const now = new Date();
const hour = now.getHours();
if (userPrefs.quietHoursEnabled &&
hour >= userPrefs.quietHoursStart ||
hour < userPrefs.quietHoursEnd) {
return; // Skip during quiet hours
}
// Send contextual notification
await NotificationService.send({
title: 'Mindfulness Moment',
body: geofence.prompt,
action: geofence.action,
priority: 'default'
});
}
}
// Wearable Integration
interface WearableDataService {
// Fetch health metrics from connected devices
async getHeartRateData(
startDate: Date,
endDate: Date
): Promise;
async getSleepData(
startDate: Date,
endDate: Date
): Promise;
async getStepsData(
startDate: Date,
endDate: Date
): Promise;
// Analyze patterns
analyzeHeartRateVariability(): Promise;
detectSleepDisturbances(): Promise;
assessActivityLevel(): Promise;
// Correlate with mental health
correlateWithMood(
healthData: HealthMetrics,
moodData: MoodRating[]
): Correlation[];
}
Secure, HIPAA-compliant messaging enables asynchronous communication between patients and therapists, providing a safety net for patients while reducing therapist burden compared to synchronous appointments.
interface MessagingService {
// Send message
sendMessage(message: MessageData): Promise;
// Retrieve conversation
getConversation(
userId: string,
otherUserId: string,
pagination: PaginationParams
): Promise;
// Real-time subscription
subscribeToMessages(
userId: string,
callback: (message: Message) => void
): Subscription;
// Read receipts
markAsRead(messageId: string): Promise;
// Crisis detection
analyzeSafetyRisk(content: string): Promise;
// File attachments
uploadAttachment(file: File): Promise;
}
// End-to-End Encryption Implementation
class E2EEMessaging {
private userKeyPair: CryptoKeyPair;
async sendEncryptedMessage(
recipientPublicKey: CryptoKey,
content: string
): Promise {
// Generate ephemeral symmetric key
const symmetricKey = await crypto.subtle.generateKey(
{ name: 'AES-GCM', length: 256 },
true,
['encrypt', 'decrypt']
);
// Encrypt message content
const iv = crypto.getRandomValues(new Uint8Array(12));
const encryptedContent = await crypto.subtle.encrypt(
{ name: 'AES-GCM', iv },
symmetricKey,
new TextEncoder().encode(content)
);
// Encrypt symmetric key with recipient's public key
const exportedKey = await crypto.subtle.exportKey('raw', symmetricKey);
const encryptedKey = await crypto.subtle.encrypt(
{ name: 'RSA-OAEP' },
recipientPublicKey,
exportedKey
);
return {
encryptedContent: Array.from(new Uint8Array(encryptedContent)),
encryptedKey: Array.from(new Uint8Array(encryptedKey)),
iv: Array.from(iv),
timestamp: Date.now()
};
}
async decryptMessage(
encrypted: EncryptedMessage
): Promise {
// Decrypt symmetric key with private key
const decryptedKey = await crypto.subtle.decrypt(
{ name: 'RSA-OAEP' },
this.userKeyPair.privateKey,
new Uint8Array(encrypted.encryptedKey)
);
// Import decrypted symmetric key
const symmetricKey = await crypto.subtle.importKey(
'raw',
decryptedKey,
{ name: 'AES-GCM' },
false,
['decrypt']
);
// Decrypt message content
const decryptedContent = await crypto.subtle.decrypt(
{
name: 'AES-GCM',
iv: new Uint8Array(encrypted.iv)
},
symmetricKey,
new Uint8Array(encrypted.encryptedContent)
);
return new TextDecoder().decode(decryptedContent);
}
}
// Crisis Keyword Detection
class CrisisDetectionService {
private crisisKeywords = [
// Direct suicidal ideation
'kill myself', 'end my life', 'want to die',
'suicide', 'suicidal', 'better off dead',
// Self-harm
'hurt myself', 'cut myself', 'harm myself',
// Plans/methods
'pills', 'overdose', 'jump off', 'hanging',
// Hopelessness
'no point', 'cant go on', 'no way out', 'give up'
];
async analyzeMessage(content: string): Promise {
const lowerContent = content.toLowerCase();
// Check for crisis keywords
const foundKeywords = this.crisisKeywords.filter(
keyword => lowerContent.includes(keyword)
);
if (foundKeywords.length === 0) return null;
// Calculate risk level
let riskLevel: 'low' | 'medium' | 'high' | 'severe';
if (foundKeywords.length >= 3) riskLevel = 'severe';
else if (foundKeywords.length >= 2) riskLevel = 'high';
else riskLevel = 'medium';
// Enhanced analysis with NLP
const sentiment = await this.analyzeSentiment(content);
const context = await this.analyzeContext(content);
if (sentiment.score < -0.8 && context.includesPlan) {
riskLevel = 'severe';
}
return {
riskLevel,
foundKeywords,
sentiment,
context,
timestamp: new Date(),
requiresImmediateResponse: riskLevel === 'severe' || riskLevel === 'high',
recommendedActions: this.getRecommendedActions(riskLevel)
};
}
private getRecommendedActions(riskLevel: string): string[] {
switch (riskLevel) {
case 'severe':
return [
'Immediate therapist notification',
'Emergency services contact information',
'988 Suicide & Crisis Lifeline display',
'Safety plan activation',
'Emergency contact notification (if authorized)'
];
case 'high':
return [
'Urgent therapist notification',
'Crisis resources display',
'Safety plan review',
'Check-in scheduling'
];
default:
return [
'Therapist notification',
'Supportive resources',
'Coping skills reminder'
];
}
}
}
Thoughtful push notifications can significantly improve engagement and outcomes. However, poorly designed notifications lead to annoyance, app deletion, and reduced trust.
| Notification Type | Timing | Frequency | User Control |
|---|---|---|---|
| Practice Reminders | User-scheduled (e.g., daily 9am) | Once daily max | Full customization: time, days, snooze |
| Session Follow-ups | 24 hours after incomplete session | One reminder only | Can disable per session type |
| Assessment Reminders | Biweekly at user's preferred time | Biweekly | Can set preferred day/time |
| Therapist Messages | Immediate | Per message | Cannot disable (clinical safety) |
| Progress Milestones | Upon achievement | As earned | Can disable celebrations |
| Crisis Resources | When crisis keywords detected | Per crisis event | Cannot disable (safety) |