Robin Quiz — Real-Time Cross-Platform Quiz App
A production quiz application live on both the Apple App Store and Google Play Store, featuring real-time Socket.io scoring, live leaderboards, push notifications, and a full quiz management backend — built with React Native (Expo) and Laravel.
Project Overview
Robin Quiz is a live, commercially deployed mobile quiz application available on both the Apple App Store and Google Play Store. It demonstrates the full lifecycle of cross-platform mobile development: from architecture through to App Store review and production deployment.
The application's defining feature is its real-time competitive quiz experience: players answer questions simultaneously, scores update live on a shared leaderboard, and Socket.io ensures sub-100ms score propagation between all connected clients — without polling.
Core Features
Real-Time Scoring
Socket.io pushes score updates to all connected quiz participants instantly. No refresh, no delay.
Live Leaderboard
Dynamic leaderboard updates after every question answer, showing rank changes in real time.
Push Notifications
Expo push notification system delivers quiz invitations, start alerts, and result notifications.
Quiz Management API
Laravel REST API for creating, scheduling, and managing quizzes from an admin interface.
Cross-Platform
Single React Native codebase runs natively on iOS and Android via Expo managed workflow.
Authenticated Sessions
REST API authentication ensures quiz scores and leaderboard positions are tied to verified user accounts.
Technical Architecture
React Native with Expo — Cross-Platform Strategy
The mobile application is built using the Expo managed workflow, which dramatically simplifies the build-and-deploy cycle for cross-platform mobile apps. Rather than maintaining separate iOS (Swift) and Android (Kotlin) codebases, the entire application — UI, navigation, and business logic — is written in JavaScript/TypeScript once.
Expo's managed workflow provides access to native APIs (camera, push notifications, device info) through pre-built modules, while the EAS (Expo Application Services) build system handles the compilation to native binaries for both platforms — enabling App Store and Play Store submission without requiring macOS for Android builds or Windows for iOS builds.
Real-Time Communication — Socket.io Architecture
The real-time quiz engine is built on a Node.js Socket.io server running alongside the Laravel API. The separation is intentional: Socket.io handles all real-time event broadcasting, while Laravel handles persistent data operations (user management, quiz storage, score recording).
Socket.io — Real-Time Quiz Room Server
// socket-server/quiz.js
io.on('connection', (socket) => {
// Player joins a quiz room
socket.on('join_quiz', ({ quizId, userId, displayName }) => {
socket.join(`quiz_${quizId}`);
// Notify all players in room
io.to(`quiz_${quizId}`).emit('player_joined', {
userId,
displayName,
playerCount: getPlayerCount(`quiz_${quizId}`)
});
});
// Player submits an answer
socket.on('submit_answer', async ({ quizId, questionId, answer, timeRemaining }) => {
const result = await gradeAnswer(questionId, answer, timeRemaining);
// Update this player's score in Redis for fast leaderboard access
await redis.zincrby(`leaderboard_${quizId}`, result.points, socket.userId);
// Emit updated leaderboard to entire room
const leaderboard = await getTopPlayers(`leaderboard_${quizId}`, 10);
io.to(`quiz_${quizId}`).emit('leaderboard_update', leaderboard);
// Confirm score to the submitting player only
socket.emit('answer_result', {
correct: result.correct,
points: result.points,
explanation: result.explanation
});
});
});
Laravel REST API — Quiz Management Backend
The Laravel backend serves as the data persistence and management layer. It handles: user authentication, quiz creation and scheduling via admin API, question bank management, and final score persistence at quiz completion (reading from the Redis leaderboard and writing to MySQL for permanent storage).
Push Notifications with Expo
Expo's push notification infrastructure abstracts over APNs (Apple) and FCM (Google), providing a unified API. Laravel stores each user's Expo push token on device registration and dispatches notifications through Expo's push API via a queued job:
Push Notification Dispatch — Laravel Job
// app/Jobs/SendQuizInviteNotification.php
class SendQuizInviteNotification implements ShouldQueue
{
public function handle(): void
{
$tokens = $this->users->pluck('expo_push_token')->filter()->toArray();
// Send in batches of 100 (Expo API limit)
collect($tokens)->chunk(100)->each(function ($batch) {
Http::post('https://exp.host/--/api/v2/push/send', [
'to' => $batch->values()->toArray(),
'title' => "Quiz Starting: {$this->quiz->title}",
'body' => "Tap to join — starts in 5 minutes!",
'data' => ['quizId' => $this->quiz->id, 'type' => 'quiz_invite'],
]);
});
}
}
Key Challenges and Solutions
Challenge 1
Real-time leaderboard updates for multiple simultaneous players required a data structure that could be read and written faster than MySQL can handle under concurrent load during active quiz sessions.
Solution
Used Redis Sorted Sets for the live leaderboard: each player's score is a member of a sorted set keyed by quiz ID. Redis's ZINCRBY atomically increments scores and ZREVRANGE returns the top N players in O(log N) time. At quiz completion, the final leaderboard is written to MySQL for permanent storage.
Challenge 2
iOS and Android have different push notification permission models and token formats. Inconsistent token registration caused notification delivery failures for a subset of users.
Solution
Expo's notification library normalises the permission request flow across platforms. The token registration is triggered post-login, with a fallback that re-requests the token on each app launch if the stored token is older than 30 days. Invalid tokens returned by the Expo API are automatically pruned from the database.
App Store Deployment
Getting an application live on both app stores involves considerably more than writing code. The submission process required: App Store Connect and Google Play Console account configuration, App Privacy Policy and data usage declarations, screenshot assets for all device sizes (iPhone 6.5", 5.5", iPad), content rating questionnaire completion, and responding to review feedback.
The first App Store submission was rejected for a missing Account Deletion feature — a requirement Apple added in 2023. I implemented the deletion flow within 48 hours and resubmitted successfully. This practical App Store review experience is documented as a guide on my blog.
What I Learned
Building a live app store application teaches you that mobile development is 60% product, 30% platform compliance, and 10% actual code. The technical architecture was straightforward — the real challenge was navigating app store policies, designing for small screens, managing asynchronous network states gracefully, and ensuring the real-time experience held up on weak mobile connections.
The Socket.io + Redis architecture for real-time leaderboards is a pattern I now apply to any feature requiring low-latency data synchronisation across multiple clients.
FAQs
Q: How does real-time scoring work without polling?
The React Native app maintains a persistent WebSocket connection to the Socket.io server via Expo's networking layer. When a player submits an answer, the server scores it, updates the Redis leaderboard, and emits the new rankings to all players in the quiz room within milliseconds — no polling required.
Q: How is a single codebase deployed to both iOS and Android?
React Native's bridge architecture compiles JavaScript logic to native components for each platform. Expo Application Services (EAS) handles platform-specific builds — generating an .ipa for iOS and an .aab for Android from the same JavaScript source.
Q: Can you build a custom mobile app with real-time features?
Yes. I have production experience with React Native, Expo, Socket.io, and mobile app store submission for both iOS and Android. Contact me to discuss your mobile app requirements.
Project Info
Tech Stack
framework