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.







