CareAi is a mobile therapy platform for European users: real-time video, live multilingual transcription, socket-driven EMDR sessions, and AI-assisted summaries. Building it for medical data in Europe meant encryption and identifier aliasing shaped the data model early rather than being retrofitted. The hardest delivery problem wasn't a feature โ it was an iOS bitcode fix that Expo discarded on every build, because it was being applied to a folder Expo regenerates.
Ownership and status. Sole. Software case study, not infrastructure work. I built the real-time media integration, the transcription agent, the EMDR socket layer, the privacy controls and the release fixes. Shipped to both stores for client testing.
The app
The patient-facing surfaces the release had to keep working: browsing therapists, booking, and the profile and session screens either side of a consultation.
How a session runs in real time
Two channels carry a live session: Agora for media and transcription, and Socket.IO for the therapist-controlled EMDR state. They run side by side inside the same call.
Real-time EMDR from the therapist dashboard
EMDR โ Eye Movement Desensitization and Reprocessing โ guides patients through specific visual and auditory patterns to help process trauma, and it had to be fully interactive from the therapist side.
The app already relied on socket-based communication for real-time features, so EMDR leveraged that. On the therapist's web dashboard, a slider or buttons control the animation โ dot direction, color, speed, sound, and background. Each change is sent as a JSON payload over the socket. The patient, connected in the same video session, receives it instantly and updates the EMDR state in real time โ showing, hiding, or changing patterns mid-session as if therapist and patient were in the same room.
Live video and multilingual transcription
Video was the backbone of the app, and the requirement was not just stable streaming but speech-to-text transcripts for English and French. I built an Agora agent that joins the call, captures live audio, and sends the transcription to S3 for storage and real-time display. After some trial and error it ran smoothly, giving therapists live transcripts they could reference mid-session.
Summaries built from real session context
I built an AI assistant that uses previous session context and the live transcription from the call. It summarizes key points, highlights potential concerns, and makes sessions easier to review later. The goal was never to replace therapist judgment โ it was to cut manual note-taking and keep important context from getting lost.
Agora for video plus STT
Building the real-time media layer from scratch
Why: Agora provided reliable video infrastructure and speech-to-text support out of the box, so the work could focus on the transcription agent and session logic instead of media plumbing.
Data handling
Built primarily for European users and carrying medical data, so two controls went in early: encryption at rest and in transit, and patient identifiers replaced with aliases so an exposed internal record doesn't carry direct identity.
Designing that in up front slowed the early work, mostly because it constrained how transcripts and chat could be stored and joined later.
What I'm not claiming: that the product is GDPR compliant. I implemented specific technical controls. Compliance is a legal determination involving data-processing agreements, retention policy, lawful basis and erasure handling โ none of which is an engineering sign-off, and the data lifecycle work below was never completed.
The iOS build blocker
Everything worked in simulators, but the App Store build exposed a different problem: AgoraRTC bitcode errors on iOS.
The common forum fixes for stripping bitcode did not work in our Expo setup. Debugging on an M1 Mac, I found the reason: the script was modifying the local ios/ folder, which Expo regenerates and ignores during the real build. Moving the fix into a post-build Expo script โ run after pod install โ stripped bitcode from the AgoraRTC framework automatically, and the build went through.
A post-build Expo script that strips AgoraRTC bitcode after pod install
Patching the local ios/ folder, which Expo regenerates and ignores
Why: Expo owns the native project generation, so any manual edit to ios/ is discarded at build time โ the fix has to run inside Expo's own build lifecycle to survive.
This is the class of bug that hides between tools: the fix was correct, the failure mode was that a generated folder was silently reverting it. Most of the delivery risk on this project sat outside feature code.
What I'd watch in production
The app shipped for client testing, so these are not measured results โ they are the first signals I'd instrument if I owned this longer-term:
- Agora call quality โ call-drop and reconnect rates, since a dropped call interrupts an active therapy session.
- Transcription latency and accuracy per language โ English vs. French, since the transcript feeds both the therapist view and the AI summaries.
- EMDR socket desync โ whether the patient's EMDR state ever drifts from what the therapist dashboard sent, and how fast it recovers.
- S3 encryption and access auditing โ who and what touches stored transcripts, given the medical data involved.
- Data lifecycle โ retention windows and erasure requests across transcripts, chat and session records. This was not built, and it is the gap between the controls that exist and any real compliance position.
Key results
- Real-time EMDR fully controlled from the therapist dashboard over sockets
- Multilingual (EN/FR) live transcription integrated via Agora STT
- AI assistant for session summaries built from real session context
- Encryption at rest and in transit with aliased patient identifiers โ technical controls, not a compliance claim
- iOS AgoraRTC bitcode blocker resolved with a post-build Expo script
- Deployed to both the App Store and Play Store for client testing