Common Data Loss in Ev Charging Apps: Causes and Fixes
Data loss in EV charging apps usually means the app or backend loses a state transition that matters: a reservation, payment authorization, charging session, energy delivered, coupon redemption, or wa
1. What causes data loss in EV charging apps
Data loss in EV charging apps usually means the app or backend loses a state transition that matters: a reservation, payment authorization, charging session, energy delivered, coupon redemption, or wallet balance update. The most common technical causes are:
- Unreliable mobile connectivity: EV drivers often use apps in parking garages, rural charging sites, basements, or areas with weak cellular coverage.
- Background app suspension: Mobile OSes may pause the app while a charging session is active.
- Poor offline handling: Apps cache data locally but fail to sync it safely when connectivity returns.
- Non-idempotent API calls: Retrying the same request can create duplicate charges, duplicate sessions, or inconsistent balances.
- Race conditions: A user may scan QR code, tap “Start”, receive a push notification, and refresh the session screen at the same time.
- Event ordering bugs: Backend systems receive events out of order, such as
session_started,meter_value,session_stopped, andpayment_captured. - Local database migration failures: SQLite/Realm/Core Data schema changes can drop saved sessions, vehicles, payment methods, or preferences.
- Push notification and WebSocket gaps: A missed notification can leave the user unaware that charging started, stopped, failed, or cost more than expected.
- Backend eventual consistency: Wallet balance, charging history, and invoice records may update at different times without clear reconciliation.
- State stored only in memory: If the app crashes or the OS kills it, the current charge state disappears.
For EV charging, this is worse than a normal e-commerce bug. A lost state can mean the user is stranded, overcharged, unable to prove energy delivered, or unable to reconcile expense reports.
2. Real-world impact
Data loss in EV charging apps creates high-friction support cases because users need proof of what happened at a physical charger.
Common complaints include:
- “The app says charging failed, but my car charged.”
- “I was charged twice for one session.”
- “My wallet balance disappeared after I started charging.”
- “The coupon was deducted, but the session says no discount.”
- “My reservation is gone when I arrived at the charger.”
- “The session history does not show the kWh I used.”
- “I cannot export my receipt for reimbursement.”
The business impact is direct:
| Impact area | Why it matters |
|---|---|
| Store ratings | Users punish payment and charging failures quickly with one-star reviews. |
| Support cost | Teams must reconcile charger logs, payment gateway records, backend events, and user screenshots. |
| Revenue leakage | Failed captures, lost sessions, or abandoned reservations reduce billable charging time. |
| Refund risk | Duplicate charges and missing receipts trigger refunds and chargebacks. |
| Charger utilization | Users stop using networks where session state feels unreliable. |
| Compliance risk | Missing audit trails make disputes harder to resolve. |
3. Examples of how data loss manifests
| Example | What the user sees | Likely cause |
|---|---|---|
| 1. Charging session disappears after app restart | User starts charging, leaves the screen, reopens the app, and the active session is gone. | Session state stored only in memory or not restored from backend/local DB. |
| 2. kWh delivered is lower than actual usage | Receipt shows 8 kWh, but vehicle or charger display shows 14 kWh. | Meter values lost during reconnect, dropped WebSocket events, or incomplete aggregation. |
| 3. Duplicate payment authorization | User taps “Start” twice due to slow UI and sees two pending holds. | Missing idempotency key on session creation or payment authorization. |
| 4. Wallet balance changes but invoice does not | Balance decreases, but no charging history or receipt is created. | Payment debit and invoice creation are not in the same transaction or reconciliation job. |
| 5. Reservation lost after backgrounding app | User reserves a charger, switches to maps, then returns to find the reservation gone. | Reservation timeout not persisted or not synced across devices/sessions. |
| 6. Coupon or promo code is consumed without applying discount | User applies code, starts charging, but final invoice has no discount. | Promo redemption and session pricing are not atomic. |
| 7. Charging history missing after logout/login or app update | Previous sessions disappear from “My Activity.” | Local cache overwritten, pagination bug, or backend query filter excludes completed sessions. |
4. How to detect data loss
Use detection at three layers: client, backend, and charger network.
Client-side checks
Look for:
- Active sessions missing after app restart.
- Local cache diverging from backend state.
- Failed writes to SQLite/Realm/Core Data.
- Lost meter values after network reconnect.
- Duplicate API calls from retry logic.
- UI actions that can be tapped multiple times.
Useful tools:
- Appium for Android/iOS flow testing.
- Playwright for web app flows.
- Charles Proxy or mitmproxy for request inspection.
- Device logs with strict network throttling.
- Crash and ANR monitoring.
- Local DB integrity checks after app kills.
Backend checks
Look for:
- Missing
session_startedorsession_stoppedevents. - Meter values with gaps in sequence numbers.
- Payment authorizations without matching sessions.
- Wallet balance changes without invoice records.
- Coupons marked used without associated discount.
- Reservations without terminal states.
Useful tools:
- Distributed tracing with correlation IDs.
- Event logs from OCPP or charger APIs.
- Payment gateway reconciliation jobs.
- Database audit tables.
- Outbox/inbox pattern checks.
- Idempotency key validation.
What to look for in logs
Each charging session should have one durable identifier from start to invoice. Track:
user_idcharger_idconnector_idsession_idreservation_idpayment_authorization_ididempotency_keykWh_startedkWh_stoppedtotal_energy_kwhsession_statuspayment_statusinvoice_id
If any of these change unexpectedly across systems, data loss or inconsistency is likely.
5. How to fix each example
1. Restore active sessions after app restart
Do not rely on memory. Persist the current session locally and restore it from the backend on launch.
let session = try db.activeChargingSession()
if session == nil {
api.fetchActiveSession(userId: user.id)
}
On backend, expose a single source of truth:
GET /users/{id}/active-charging-session
The mobile app should treat this as authoritative after local restore.
2. Prevent lost kWh meter values
Use sequence numbers for meter events.
{
"session_id": "ses_123",
"meter_sequence": 104,
"kwh": 12.4,
"timestamp": "2026-05-15T10:20:00Z"
}
Backend should detect gaps:
SELECT *
FROM meter_values
WHERE session_id = 'ses_123'
AND meter_sequence > 102
ORDER BY meter_sequence;
If sequence 103 is missing, request a charger status refresh or reconcile from charger logs.
3. Make session creation idempotent
Every “Start Charging” request should carry an idempotency key.
POST /charging-sessions
Idempotency-Key: user123-connector45-20260515T102000
Backend should return the same session if the request is retried:
def create_session(request):
existing = db.find_session_by_idempotency_key(request.idempotency_key)
if existing:
return existing
with db.transaction():
session = create_new_session(request)
db.save_idempotency_key(request.idempotency_key, session.id)
return session
Disable double-tap on the start button until the request completes.
4. Keep wallet balance and invoices consistent
Debit wallet and create invoice in the same transaction, or use a reconciliation job with explicit states.
BEGIN;
INSERT INTO invoices (session_id, amount, status)
VALUES ('ses_123', 18.40, 'pending');
UPDATE wallets
SET balance = balance - 18.40
WHERE user_id = 'user_123';
COMMIT;
If you cannot use one transaction, use an outbox table and replay failed events until invoice and balance match.
5. Persist reservations reliably
A reservation should survive app backgrounding, network loss, and device restart.
Store:
reservation_idcharger_idconnector_id
Test Your App Autonomously
Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts.
Try SUSA Free