Mobile App Error Reporting Integration
This guide explains how to integrate the Rails Error Dashboard with your React Native/Expo mobile application.
Overview
The gem provides a centralized error tracking system that works seamlessly with mobile apps. Mobile errors are:
- Reported to the API via dedicated endpoints
- Stored in the same database as server errors
- Displayed in the same dashboard with platform detection (iOS/Android)
- Trigger the same notification system (Slack + Email)
Benefits
✅ Centralized error tracking - All errors (API + iOS + Android) in one place ✅ Platform detection - Automatically tagged as iOS or Android ✅ Real-time notifications - Team gets alerted via Slack/Email ✅ Offline support - Errors stored locally and synced when online ✅ Batch processing - Multiple errors sent efficiently ✅ User context - Errors associated with logged-in user
Backend Setup (Rails API)
1. Create Mobile Errors Controller
# app/controllers/api/v1/mobile_errors_controller.rb
module Api
module V1
class MobileErrorsController < BaseController
# POST /api/v1/mobile_errors
def create
mobile_error = MobileError.new(error_params)
RailsErrorDashboard::Commands::LogError.call(
mobile_error,
{
current_user: current_user,
request: request,
source: :mobile_app,
additional_context: {
component: error_params[:component],
device_info: error_params[:device_info]
}
}
)
render json: { success: true }, status: :created
end
# POST /api/v1/mobile_errors/batch
def batch
# Handle batch error reporting
# See full implementation in the gem's example
end
private
def error_params
params.require(:error).permit(
:error_type, :message, :stack, :component, :timestamp,
device_info: [:platform, :version]
)
end
class MobileError < StandardError
attr_reader :mobile_data
def initialize(data)
@mobile_data = data
super(data[:message] || 'Mobile app error')
end
def name
@mobile_data[:error_type] || 'MobileError'
end
def backtrace
@mobile_data[:stack]&.split("\n") || []
end
end
end
end
end
2. Add Routes
# config/routes.rb
namespace :api do
namespace :v1 do
resources :mobile_errors, only: [:create] do
collection do
post 'batch'
end
end
end
end
Mobile App Setup (React Native/Expo)
1. Add Error Reporting Methods to API Client
// src/services/api.ts
class APIClient {
// ... existing code ...
async reportError(errorData: {
error_type: string;
message: string;
stack?: string;
component?: string;
timestamp: number;
device_info: {
platform: string;
version: string;
};
}): Promise<{ success: boolean; message: string }> {
const response = await this.client.post('/mobile_errors', {
error: errorData
});
return response.data;
}
async reportErrorsBatch(errors: Array<{...}>): Promise<{...}> {
const response = await this.client.post('/mobile_errors/batch', { errors });
return response.data;
}
}
2. Update Error Logger Service
// src/services/errorLogger.ts
import { api } from './api';
class ErrorLogger {
async syncErrors(): Promise<void> {
const unsyncedErrors = (await this.getLocalErrors()).filter(e => !e.synced);
if (unsyncedErrors.length === 0) return;
const batches = this.chunkArray(unsyncedErrors, 10);
for (const batch of batches) {
try {
// Send to backend
const result = await api.reportErrorsBatch(batch.map(error => ({
error_type: error.error_type,
message: error.message,
stack: error.stack,
component: error.component,
timestamp: error.timestamp,
device_info: error.device_info,
})));
// Mark as synced
await this.markErrorsAsSynced(batch);
} catch (e) {
console.error('Failed to sync batch:', e);
}
}
}
}
3. Use Error Logger Throughout App
// In components
import { errorLogger } from '../services/errorLogger';
try {
// Your code
} catch (error) {
await errorLogger.logError(
error as Error,
'RecordingScreen',
{ action: 'startRecording' }
);
}
4. Add Global Error Boundary
// src/components/common/ErrorBoundary.tsx
import React from 'react';
import { errorLogger } from '../../services/errorLogger';
class ErrorBoundary extends React.Component {
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
errorLogger.logError(error, 'ErrorBoundary', {
componentStack: errorInfo.componentStack,
});
}
render() {
return this.props.children;
}
}
Error Flow
┌─────────────────┐
│ Mobile App │
│ Error Occurs │
└────────┬────────┘
│
▼
┌─────────────────────┐
│ ErrorLogger │
│ - Store locally │
│ - Sync to API │
└────────┬────────────┘
│
▼
┌─────────────────────────────────┐
│ Rails API │
│ POST /api/v1/mobile_errors │
└────────┬────────────────────────┘
│
▼
┌───────────────────────────────────┐
│ Rails Error Dashboard Gem │
│ RailsErrorDashboard:: │
│ Commands::LogError.call │
└────────┬──────────────────────────┘
│
├────────────────┬──────────────────┐
▼ ▼ ▼
┌─────────────┐ ┌──────────────┐ ┌────────────────┐
│ Database │ │ Slack Alert │ │ Email Alert │
│ Storage │ │ (async job) │ │ (async job) │
└─────────────┘ └──────────────┘ └────────────────┘
│
▼
┌─────────────────────────┐
│ Error Dashboard │
│ /error_dashboard │
│ - View by platform │
│ - iOS/Android filters │
│ - Analytics │
└─────────────────────────┘
Features in Dashboard
Once integrated, you’ll see:
- Platform Badges: iOS 📱 or Android 🤖 tags on errors
- Device Info: OS version, app version
- Component Context: Which screen/component errored
- Stack Traces: Full JavaScript stack traces
- User Context: Which user experienced the error
- Filtering: Filter dashboard by platform (iOS/Android/API)
- Analytics: Charts showing errors by platform
Notifications
When a mobile error occurs:
Slack Notification:
🚨 Error Alert
━━━━━━━━━━━━━━━━━━━━━
Error Type: TypeError
Environment: Production
Platform: 📱 iOS
Occurred: December 24, 2025 at 10:30 AM
Message:
Cannot read property 'id' of undefined
User: user@example.com
Component: RecordingScreen
[View Details] → Dashboard link
Email Notification:
- Beautiful HTML email with error details
- Platform badge (iOS/Android)
- Stack trace (first 10 lines)
- Link to dashboard
- Sent to configured recipients
Testing
1. Test Error Logging
// In your app
errorLogger.logError(
new Error('Test mobile error'),
'TestScreen',
{ test: true }
);
2. Check Local Storage
const stats = await errorLogger.getStats();
console.log('Errors:', stats.total, 'Synced:', stats.synced);
3. Verify in Dashboard
- Open
http://localhost:3000/red - Filter by platform: iOS or Android
- Check error details
- Verify user association
- Check notifications (Slack/Email)
Best Practices
1. Error Context
Always provide component name and relevant context:
await errorLogger.logError(error, 'RecordingScreen', {
action: 'startRecording',
recordingId: recording.id,
duration: 120,
});
2. Sync Strategy
- Sync immediately for critical errors
- Batch sync for non-critical errors
- Periodic sync every 15 minutes (default)
- Sync on app foreground
3. Storage Management
- Keep max 50 errors locally
- Clean up synced errors > 20
- Implement exponential backoff for failed syncs
4. Privacy
- Don’t log sensitive user data
- Sanitize error messages
- Avoid logging tokens/passwords
Configuration
Backend
# config/initializers/rails_error_dashboard.rb
RailsErrorDashboard.configure do |config|
config.enable_slack_notifications = true
config.enable_email_notifications = true
config.notification_email_recipients = ['dev@example.com']
config.dashboard_base_url = 'https://myapp.com'
end
Mobile App
// Start periodic sync when app loads
errorLogger.startPeriodicSync(15); // Every 15 minutes
// Stop sync when app closes
errorLogger.stopPeriodicSync();
Troubleshooting
Errors not appearing in dashboard?
- Check API endpoint is accessible
- Verify authentication token is valid
- Check Rails logs for controller errors
- Verify error format matches expected params
Notifications not sending?
- Check notification settings in initializer
- Verify Slack webhook URL is valid
- Check email recipients are configured
- Check background job queue is running
High error volume?
- Implement client-side error deduplication
- Add rate limiting to error reporting
- Filter out known/handled errors
- Set up error grouping by type
Security
- ✅ Error endpoints require authentication
- ✅ Rate limiting on error reporting endpoints
- ✅ Input validation and sanitization
- ✅ No PII in error messages
- ✅ Secure token storage on mobile
Performance
- ✅ Async error reporting (non-blocking)
- ✅ Batch processing (max 10 errors per request)
- ✅ Local storage with cleanup
- ✅ Background job processing
- ✅ Minimal app overhead
Made with ❤️ by Anjan for the Rails community