How I built a Serverless, P2P Parental Control app using WebRTC and Kotlin
Source: Dev.to
Introduction
As a parent and Android developer, I wanted to monitor my child’s activity on TikTok and YouTube without the privacy implications of commercial parental‑control apps.
Almost every commercial solution works the same way:
- Collect child’s data (location, history, app usage).
- Upload everything to a centralized cloud database.
- Display it on the parent’s phone.
I didn’t want my child’s location history sitting on a third‑party server, so I built SafeStream, a completely server‑less, peer‑to‑peer monitoring system using Kotlin, Jetpack Compose, and WebRTC.
The Architecture: “No Backend” approach
The core idea is simple: the Parent device acts as the server. Data flows directly from Device A (Child) to Device B (Parent) without persisting anywhere in between.
- Guardian App (Child) – runs a background service that collects data locally and acts as a WebRTC peer.
- Parent App – acts as the viewer peer, receives JSON payloads directly and stores them in a local Room (SQLite) database.
- Signaling – Firebase Realtime Database is used only for the handshake (SDP Offer/Answer exchange). No user data touches Firebase.
The Tech Stack
| Component | Technology |
|---|---|
| Language | 100 % Kotlin |
| UI | Jetpack Compose (Material 3) – modern “Reel‑like” feed |
| P2P | Google’s WebRTC library wrapped in a custom WebRTCConnectionManager |
| Traversal | STUN/TURN servers to bypass NATs and firewalls (essential for 4G/5G) |
| Encryption | AES‑256‑GCM on top of WebRTC’s DTLS (Paranoia level: High) |
Key Technical Challenges
1. Extracting Video Metadata (The ethical hack)
TikTok and YouTube don’t provide APIs for watch history. I implemented an Accessibility Service (GuardianAccessibilityService.kt) that scans the UI hierarchy:
- Detects when the user is in a video app (
com.zhiliaoapp.musicallyorcom.google.android.youtube). - Scrapes the
contentDescriptionor text of visible views to extract the video title and channel.
Optimization: The logic is heavily debounced and runs only when the screen content changes, minimizing battery impact.
2. The WebRTC Handshake in Background
Keeping a WebRTC connection alive in the background on modern Android is challenging due to Doze Mode and App Standby Buckets.
Solution:
- A foreground service with a persistent notification keeps the connection alive.
- Turn‑on‑demand: The Parent sends a high‑priority FCM (Firebase Cloud Message) to “wake up” the Child device, which then initiates the WebRTC signaling process.
3. Transferring Images over P2P
High‑resolution screenshots exceed WebRTC’s safe message size (~16 KB). I wrote a chunking algorithm that:
- Compresses the
Bitmapas WebP. - Splits the binary data into small packets.
- Sends packets sequentially over the DataChannel.
- Reassembles them on the Parent side.
The Business Model (Indie Dev Reality)
SafeStream is released for free, but running TURN servers (bandwidth relay) incurs costs. To stay sustainable without subscriptions or data selling, I introduced a Credit System:
- Text logs and real‑time location are free (low bandwidth).
- Downloading high‑resolution screenshots consumes “Credits”.
- Users receive free daily credits or can watch a rewarded AdMob ad to refill them, covering TURN bandwidth expenses.
What’s Next?
I’m launching an open beta next week and seeking feedback on P2P stability across different network carriers (CGNAT is a particular challenge).
If you’re curious about the P2P implementation or want to test it out, check it out here: SafeStream Guardian Architecture – beta subscription
Happy coding! 🚀