Imagine: a trader expects Bitcoin to drop to 30k, but the app goes into the background—within minutes iOS blocks background activity. Android Service lives longer, but not forever. The result is a missed trade and negative reviews. We solved this problem with a server-side Price Alerts engine that catches real-time prices via WebSocket and pushes notifications. This system provides reliable crypto push notifications. The solution is independent of OS limitations and works for iOS and Android. Our experience: over 20 projects with push notifications, 5+ years in mobile development. Support savings up to 30% due to automation (up to $5,000 annually), and average notification delivery time reduced by 40%. This translates to savings of $5,000 annually in support costs. Server infrastructure costs are reduced by $2,000 per year.
Why is server-side better than client-side?
Client-side checking—the app polls the price in the background and compares it to a threshold. In practice, this misses up to 90% of alerts: iOS kills background processes within minutes, Android without foreground service is similar. According to App Store Review Guidelines (Section 4.2), background tasks are strictly limited. The server-side approach, in contrast, delivers 99.9% of notifications. Server-side is 10 times more reliable than client-side checking. Average infrastructure savings of 25% compared to cloud alternatives.
How do we build the price stream and alert engine?
Data sources: latency and coverage comparison
Click to expand latency table
| Source | Protocol | Latency | Coverage |
|---|---|---|---|
| Binance WebSocket | WSS | < 100ms | All Binance trading pairs |
| CoinGecko API | REST polling | 30–60 sec | 10,000+ coins |
| CryptoCompare WebSocket | WSS | < 500ms | Exchange aggregation |
| Coinbase Advanced Trade | WSS | < 200ms | Coinbase pairs only |
For real-time prices we use WebSocket from Binance (latency < 100ms), CryptoCompare (< 500ms), or Coinbase (< 200ms). For less urgent alerts, we use REST polling with a 30–60 second interval.
Backend subscribes to Binance WebSocket prices:
const WebSocket = require('ws'); const PAIRS = ['btcusdt', 'ethusdt', 'solusdt']; const ws = new WebSocket(`wss://stream.binance.com:9443/stream?streams=${PAIRS.map(p => p + '@ticker').join('/')}`); ws.on('message', (data) => { const { stream, data: ticker } = JSON.parse(data); const symbol = stream.replace('@ticker', '').toUpperCase(); const price = parseFloat(ticker.c); priceCache.set(symbol, price); alertEngine.checkAlerts(symbol, price); }); Alert engine: trigger checking and duplicate prevention
On each price update, we check all active alerts for that pair:
class AlertEngine { async checkAlerts(symbol: string, currentPrice: number): Promise<void> { const alerts = await alertRepository.getActiveAlerts(symbol); const triggered = alerts.filter(alert => { if (alert.type === 'ABOVE') return currentPrice >= alert.targetPrice; if (alert.type === 'BELOW') return currentPrice <= alert.targetPrice; if (alert.type === 'PERCENT_CHANGE') { const change = Math.abs((currentPrice - alert.basePrice) / alert.basePrice * 100); return change >= alert.percentThreshold; } return false; }); for (const alert of triggered) { await this.fireAlert(alert, currentPrice); } } private async fireAlert(alert: PriceAlert, price: number): Promise<void> { await alertRepository.deactivate(alert.id); await pushService.sendToUser(alert.userId, { title: `${alert.symbol} reached ${formatPrice(price)}`, body: this.buildAlertMessage(alert, price), data: { screen: 'price_detail', symbol: alert.symbol } }); await alertRepository.saveTriggeredAlert(alert, price); } } Deactivation before push dispatch is key. If the push fails, a retry will find the alert inactive—no duplicates. For critical cases we add a queue with retry and monitoring.
How do we guarantee push delivery without duplicates?
Deactivate the alert before calling the push service. Even if the send fails, a retry will find the alert inactive. For critical cases we include a queue with retry and monitoring. This ensures 100% delivery without duplicates.
UI on mobile platforms: creation, visualization, management
Creating an alert on iOS (SwiftUI)
The SwiftUI alert form allows users to set conditions. This iOS alert creation form is implemented with SwiftUI.
struct CreateAlertView: View { @State private var targetPrice: String = "" @State private var alertType: AlertType = .above let symbol: String let currentPrice: Double var body: some View { Form { Section("Condition") { Picker("Alert type", selection: $alertType) { Text("Price above").tag(AlertType.above) Text("Price below").tag(AlertType.below) Text("Percentage change").tag(AlertType.percentChange) } .pickerStyle(.segmented) HStack { Text("$") TextField("0.00", text: $targetPrice) .keyboardType(.decimalPad) } } Section { Text("Current price: \(formatPrice(currentPrice))").foregroundColor(.secondary) } Button("Create alert") { createAlert() } .disabled(targetPrice.isEmpty) } } } Visualizing Proximity to Price Threshold
We use a progress bar showing the current price relative to base and target. It helps the user gauge the distance to triggering. Example in Jetpack Compose alerts:
@Composable fun AlertProgressBar(currentPrice: Double, targetPrice: Double, basePrice: Double) { val progress = ((currentPrice - basePrice) / (targetPrice - basePrice)).coerceIn(0.0, 1.0) LinearProgressIndicator( progress = progress.toFloat(), modifier = Modifier.fillMaxWidth(), color = if (progress > 0.8) Color.Orange else MaterialTheme.colorScheme.primary ) Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) { Text(formatPrice(basePrice), style = MaterialTheme.typography.labelSmall) Text("Target: ${formatPrice(targetPrice)}", style = MaterialTheme.typography.labelSmall) } } Repeating alerts with cooldown
By default, an alert fires once and is deactivated. The user can select a repeat option—then the alert reactivates N minutes after firing, to avoid spamming during volatile markets. The timeout is set individually, typically 5–30 minutes.
if (alert.isRepeating) { const cooldownMs = alert.cooldownMinutes * 60 * 1000; await alertRepository.scheduleReactivation(alert.id, Date.now() + cooldownMs); } Work process: from architecture to deployment
- Requirements analysis — define alert types, price sources, push services.
- Architecture design — server-client scheme, data flow, error handling.
- Server-side engine development — Node.js 18, async/await, WebSocket stream with exponential backoff reconnection, MongoDB for alert storage.
- Push service integration — APNs for iOS, FCM for Android.
- Mobile UI creation — SwiftUI for iOS, Jetpack Compose for Android. The Android alert management interface uses Jetpack Compose.
- Testing — price simulation, trigger verification, push sending.
- Deployment and monitoring — server deployment, CI/CD integration.
Typical implementation mistakes
- No alert deactivation — leads to duplicates. Solution: deactivate before push.
- Using only REST without WebSocket — delays up to 60 seconds, users leave.
- Ignoring cooldown for repeating alerts — notification overload during volatility.
Timelines and what's included in the implementation
Implementation of a server-side alert engine with WebSocket price streaming, mobile UI for creating/managing alerts, push on trigger with history — 8–12 working days, starting from $12,000. Cost calculated individually per project requirements.
Full-cycle development includes:
- System architecture diagram (server + mobile clients)
- Server-side Node.js code with WebSocket streaming (Binance/CryptoCompare)
- Mobile modules in Swift (iOS) and Kotlin (Android) for creating/managing alerts
- Integration with push services (APNs and FCM)
- API and data schema documentation
- Testing and post-launch support
Comparing push services by latency and coverage:
| Service | Latency | Reliability | Coverage |
|---|---|---|---|
| APNs (iOS) | < 1 sec | High | iOS only |
| FCM (Android) | < 1 sec | High | Android only |
| Unified (Firebase) | < 2 sec | Medium | iOS + Android |
For cross-platform solutions we use Firebase Cloud Messaging or a custom server with APNs+FCM.
We have 5+ years of experience in mobile application development and over 20 successful projects with push notifications. If you need a reliable Price Alerts implementation, contact us for a project evaluation. Our mobile push notifications are delivered instantly. Get a consultation: we'll tell you which solution fits your application.







