Shipnative includes comprehensive monitoring with PostHog for analytics and Sentry for error tracking. All utilities are pre-built and ready to use.
Setup
The wizard prompts for your PostHog API key and host URL.
Or manually add to apps/app/.env:
EXPO_PUBLIC_POSTHOG_API_KEY=your_api_key
EXPO_PUBLIC_POSTHOG_HOST=https://app.posthog.com
Without keys: Mock mode logs events to console. Connect real PostHog early to capture usage data.
Usage
useAnalytics Hook
import { useAnalytics } from '@/hooks/useAnalytics'
function MyComponent() {
const { trackEvent, trackScreen, isFeatureEnabled } = useAnalytics()
// Track events
trackEvent('button_clicked', { button: 'submit' })
// Track screens
trackScreen('HomeScreen')
// Feature flags
if (isFeatureEnabled('new-feature')) {
// Show feature
}
}
Utility Functions
For use outside React components:
import {
trackEvent,
trackScreen,
identifyUser,
clearUser,
} from '@/utils/analytics'
trackEvent('purchase_completed', { amount: 9.99 })
trackScreen('ProductScreen', { product_id: '123' })
identifyUser('user-123', { email: 'user@example.com' })
clearUser() // on logout
Direct Client Access
import { posthog } from '@/services/posthog'
posthog.track('event_name', { property: 'value' })
posthog.identify('user-id', { email: 'user@example.com' })
Feature Flags
const { isFeatureEnabled, getFeatureFlag } = useAnalytics()
// Boolean flag
if (isFeatureEnabled('dark-mode-v2')) {
// Use new dark mode
}
// Multivariate flag
const variant = getFeatureFlag('pricing-test') // 'control' | 'variant-a'
Create flags in PostHog Dashboard → Feature Flags. See PostHog Feature Flags.
Pre-built Event Helpers
import { trackAuth, trackSubscription } from '@/utils/analytics'
// Auth events
trackAuth.signupCompleted('user-123', { method: 'email' })
trackAuth.loginCompleted('user-123', { method: 'google' })
trackAuth.logout()
// Subscription events
trackSubscription.started({ plan: 'pro_monthly' })
trackSubscription.completed({ plan: 'pro_monthly', price: 9.99 })
Testing
Mock mode: Events logged to console as [MockPostHog] Event: ...
Real PostHog:
- Add API key and host to
.env
- Trigger events in app
- View in PostHog Dashboard → Events / Persons
Troubleshooting
Events not showing in PostHog?
- Verify API key and host are correct
- Allow a few minutes for events to process
- Check console for PostHog errors
Still in mock mode?
- Verify
apps/app/.env has correct keys
- Restart Metro:
yarn start --clear
For more, see PostHog React Native SDK.
Error Tracking with Sentry
Sentry automatically captures JavaScript errors, native crashes, and performance issues. It’s configured to work seamlessly with your app.
Setup
Run the setup wizard:
The wizard will prompt for your Sentry DSN. Or manually add to apps/app/.env:
SENTRY_DSN=your_sentry_dsn
Without DSN: Mock mode logs errors to console. Connect real Sentry early to catch production issues.
Automatic Error Capture
Sentry automatically captures:
- JavaScript errors - Unhandled exceptions and promise rejections
- Native crashes - iOS and Android native errors
- React errors - Component render errors via Error Boundaries
- Performance issues - Slow screens and network requests
No additional code needed - errors are automatically reported.
Manual Error Reporting
Capture errors manually with context:
import * as Sentry from '@sentry/react-native'
try {
processPayment(data)
} catch (error) {
Sentry.captureException(error, {
level: 'error',
tags: { section: 'payments' },
extra: { userId: user.id, amount: 9.99 },
})
}
Breadcrumbs
Add breadcrumbs for debugging context:
import * as Sentry from '@sentry/react-native'
Sentry.addBreadcrumb({
category: 'navigation',
message: 'User navigated to Profile',
level: 'info',
data: {
from: 'Home',
to: 'Profile',
},
})
User Context
Associate errors with users:
import * as Sentry from '@sentry/react-native'
// Set user (on login)
Sentry.setUser({
id: user.id,
email: user.email,
username: user.name,
})
// Clear user (on logout)
Sentry.setUser(null)
Track custom operations:
import * as Sentry from '@sentry/react-native'
// Track async operation
await Sentry.startSpan(
{
name: 'fetch-user-data',
op: 'http.client',
},
async (span) => {
const response = await fetch('https://api.example.com/users')
const data = await response.json()
span?.setAttribute('http.status_code', response.status)
span?.setAttribute('user.count', data.length)
return data
}
)
Utility Functions
Pre-built helpers in utils/crashReporting.ts:
import { logError, logWarning, logInfo } from '@/utils/crashReporting'
logError('Payment failed', { userId: '123', amount: 9.99 })
logWarning('Slow network detected', { latency: 5000 })
logInfo('Feature flag evaluated', { flag: 'new-ui', value: true })
Testing Sentry
Trigger a test error:
import * as Sentry from '@sentry/react-native'
// Capture test error
Sentry.captureMessage('Test error from app', {
level: 'error',
tags: { test: true },
})
// Or throw error
throw new Error('Test native crash')
View errors in Sentry Dashboard → Issues.
Filtering Errors
Configure what gets reported in services/sentry.ts:
Sentry.init({
beforeSend: (event, hint) => {
// Filter out specific errors
if (event.exception?.values?.[0]?.value?.includes('Network request failed')) {
return null // Don't send
}
// Remove sensitive data
if (event.user) {
delete event.user.email
}
return event
},
})
Production Best Practices
- Environment tagging - Automatically set via
EXPO_PUBLIC_ENV
- Release tracking - Set release version for tracking issues across versions
- Source maps - Uploaded automatically for readable stack traces
- User privacy - Avoid sending PII (personally identifiable information)
For more, see Sentry React Native SDK.