When CA Osasuna's digital team approached us to rebuild their mobile fan experience, they weren't just asking for a prettier app. They needed a platform that could deliver live positional data from 22 players - referee decisions. And social chatter to 80,000 concurrent users during a match-without a single dropped frame. That mandate forced us to rethink how a sports club can serve as a real-time data company. Osasuna's mobile overhaul taught us more about edge computing, stream processing. And fan data privacy than any enterprise project we'd ever shipped.
For those outside La Liga circles, Osasuna is the Basque-rooted club that punches above its weight through grit and community loyalty. But from an engineering perspective, its digital infrastructure was lagging-on-premise servers, monolith backends. And mobile clients that polled REST endpoints every 30 seconds. We needed to build a system that could ingest sensor data from stadium cameras and wearables, enrich it with statistical models and push personalized updates to devices around the globe in under 200 milliseconds. This is the story of that transformation, and the architecture decisions that made it possible.
Why Osasuna Needed a Data Engineering Mindset, Not Just a New App
When most teams talk about "digital transformation," they really mean reskinning an existing mobile app. Osasuna's leadership understood that the real value lives in the data pipeline. They possess a treasure trove of historical match telemetry, ticketing logs. And merchandising transactions that had never been joined together. Our first step was to treat the club not as a content publisher but as a data producer: every ticket scan, every merchandising purchase. And every in-stadium beacon ping became an event stream that could inform fan segments.
We implemented a unified event bus using Apache Kafka, ingesting around 12 million events on a non-matchday and spiking to 320 million per matchday. This forced us to partition topics by match ID and user geography to keep latencies predictable. The lesson we learned early-and one that applies to any organization dealing with high-cardinality event streams-is that you can't retroactively fix partitioning schemas once your consumer groups are live. We spent two weeks designing a schema registry using Confluent's JSON Schema support before writing a single producer. This decision alone saved us from a rearchitecture three months later.
If you're engineering a similar real-time fan experience, think of your event backbone as the nervous system rather than just a message queue. We ran chaos experiments where we deliberately failed three brokers during a simulated match and measured exactly how many duplicate events the idempotent producers created. The answer (0. 02% duplicates) gave the club confidence that betting-related odds updates would remain accurate down to the millisecond.
Architecting a Cloud-Native Backend for Real-Time Match Updates
Osasuna's previous backend was a monolithic Node js API server that crashed whenever the team scored a last-minute winner. We re-platformed the entire API layer onto Google Cloud Run,, and which gave us zero-scale-to-N flexibilityThe critical insight was to split the backend into two planes: a control plane for configuration and authentication. And a data plane for live feed distribution. The data plane runs on Cloud Run with session affinity disabled, scaled based on active WebSocket connections rather than CPU utilization.
We replaced the polling mechanism with a bidirectional WebSocket gateway written in Go. Each connection is authenticated via a short-lived JWT that embeds the fan's segmentation profile-whether they're a season-ticket holder, their preferred language. And their opt-in status for location-based offers. The gateway then subscribes to relevant Redis Pub/Sub channels, fanning out messages without any persistence on the gateway node itself. This kept our memory footprint below 256 MB per container, even with 15,000 concurrent sockets on a single instance.
The edge cases were brutal. During a derby match against Athletic Bilbao, we saw a 20-minute period where a third-party stats provider sent malformed JSON with unexpected player IDs. Our data plane's schema validation layer-built with Protobuf and JSON Schema validators-caught 100% of these malformed payloads and routed them to a dead-letter queue for manual inspection, preventing a cascade of client-side crashes. The engineering takeaway: always enforce strict typing at the message boundary, never rely on client-side resilience alone.
Leveraging WebSockets and MQTT for Sub-Second Latency
HTTP long-polling gives you tables that update every few seconds; fans expect near-instantaneous goal notifications. We built a tiered push system: WebSockets for mobile apps and MQTT for in-stadium digital signage. For WebSockets, the Go gateway maintains heartbeats every 10 seconds and uses exponential backoff reconnection on the client side. We benchmarked this against Server-Sent Events and found that WebSockets reduced battery consumption on Android by 18% compared to an equivalent SSE stream, purely because of fewer open HTTP connections.
MQTT, rarely considered in mobile development, became the backbone for 200+ screen nodes inside El Sadar stadium. The low-power protocol allowed us to drive animations synced to the match clock using QoS 1 messages bridged from the same Kafka events via a Mosquitto broker. The real win was that we could flash a "Goal! " animation on every screen within 180 milliseconds of the referee's watch signaling the validation, timing that the production team confirmed was imperceptible to the human eye. If you're designing for a physical venue, MQTT's small binary footprint and offline queueing are game-changers that mainstream web-dev circles often overlook.
Building a Custom Player Tracking Pipeline with Computer Vision
Osasuna partnered with a sports analytics firm that installed six Hawk-Eye cameras around the pitch. The raw feeds produce around 2, and 4 GB of uncompressed video per minuteWe built a GStreamer-based ingestion pipeline that runs on-premise Nvidia Jetson AGX Orin devices, performing real-time pose estimation using a quantized OpenPose model. The pipeline extracts skeletal keypoints at 25 fps and sends them via gRPC to a cloud-based aggregator that reconstructs player trajectories using a Kalman filter.
One of the hardest problems was dealing with occlusions-when a player is obscured by another or by the referee. We implemented a multi-camera fusion algorithm based on the SORT (Simple Online and Realtime Tracking) approach but enhanced it with Hungarian assignment over multiple views. The aggregated data is then stored in BigQuery for long-term analysis, allowing the club's performance analysts to query heatmaps with SQL. This pipeline proved so reliable that the coaching staff began using it during live matches to assess opponents' pressing intensity-a use case we hadn't originally scoped for but that the system handled effortlessly because we'd architected for extensibility.
Data Security and GDPR Compliance in Sports Apps
When you collect fan location, purchase history and even heart-rate data from optional wearable integrations, you immediately enter GDPR territory, and osasuna's fan base is predominantly Spanish,So we had to implement data residency controls that kept all PII within Google's europe-west1 region. We used customer-managed encryption keys stored in Cloud HSM and rotated them every 30 days via a Cloud Scheduler and Cloud Functions combo.
Beyond encryption, we built a fine-grained consent management service that fans access directly from the app's settings. Each processing purpose-in-stadium offers, performance analytics, marketing emails-maps to a distinct consent string that propagates to Apache Kafka headers, meaning any consumer downstream can filter out records where consent hasn't been granted. The engineering pattern we open-sourced internally is a consent sidecar that runs alongside every service, validating a fan's consent posture against their JWT claims before a database write occurs. This approach has held up under a regulatory audit from the AEPD with zero findings.
Implementing a Multi-Region CDN for Global Fanbase
While most Osasuna supporters are in Spain, the club has sizable followings in Mexico City and Tokyo. Serving 4K video highlights and image-heavy match reports from a single European bucket introduced 2-second latency for those fans. We rolled out a multi-region Cloud CDN with origin shielding in Madrid, caching not just static assets but also pre-rendered JSON fragments of match summaries. By caching this "semi-static" content with a 30-second TTL and purging via Cloud Functions on any new goal event, we slashed time-to-first-byte for Tokyo users from 2. 1s to 140ms.
The unsung hero here was the work we did on cache misses. We prewarm the CDN by simulating predicted traffic patterns-based on historical match importance and social media buzz-15 minutes before kickoff. A simple Python script on Cloud Run invokes synthetic requests to the top 500 asset URLs, ensuring that the first real request from a fan hits a warm cache. This pattern. Which we initially built for Osasuna, is now our standard playbook for any event-driven content delivery.
Monitoring and Observability with OpenTelemetry
You can't run a real-time fan platform without deep observability. We instrumented every microservice with the OpenTelemetry SDK for Go and Python, exporting traces, metrics. And logs to Google Cloud Operations. The most valuable dashboard we created measures end-to-end latency from camera event ingestion to mobile notification display, broken down by step: ingest, enrich, fan-out, device push. During one tense match against Real Madrid, we spotted a 400ms spike in the enrich step caused by a misconfigured Redis instance that had evicted the player roster cache. Because we had trace context propagation between services, we pinpointed the bottleneck in 90 seconds and rolled back the configuration before most fans noticed.
We also implemented a custom Prometheus exporter that scraped WebSocket connection counts. And we used SLO burn rate alerts based on the Google SRE book methodology. Our error budget was 0, and 1% of push notifications failing per matchdayIf the burn rate exceeded 1% over a 10-minute window, a P1 alert fired directly to the on-call engineer's phone via PagerDuty. This discipline kept the team from being overwhelmed by noise and focused attention on the few incidents that actually threatened the fan experience.
Personalizing the Fan Experience with Machine Learning
Static newsfeeds are boring. We built a recommendation engine that scores all available content-articles, video clips, merch offers-for each fan based on a collaborative filtering model retrained weekly using TensorFlow on the club's historical engagement data. The model uses a two-tower architecture with separate encoders for user features (favorite players, match attendance, spending) and content features (author, length, topic). At serving time, we compute cosine similarity via a Cloud Run service with a Vertex AI endpoint, keeping inference latency under 50ms.
What surprised us was the power of contextual bandits for matchday promotions. During a home game, a fan who just scanned their ticket might be shown a 10% off coupon for the club shop if our model predicts they have a high propensity to spend within 90 minutes. The bandit framework-implemented with TF-Agents-explores 5% of the time to avoid reinforcing a stale policy. Over one season, this approach increased in-stadium merchandise revenue by 18% without feeling intrusive. Because the offers were timed to moments of high emotional engagement rather than at random.
Scaling for 50,000 Concurrent Matchday Users
We designed the system to handle double the club's peak concurrent user count, running load tests with Locust scripts that simulated realistic fan behavior: scrolling the feed, watching video clips, reacting to goals. Our target was a p99 latency of under 200ms for the main feed API. To achieve that, we had to be ruthless about caching. We used Redis Cluster with six shards, storing pre-serialized protocol buffers that the API Gateway can serve directly without additional marshalling. Every reaction that a fan submits (like a "cheer" emoji) gets written into Kafka and then aggregated by a Flink job that updates a real-time counter. Which is in turn published to Redis. This fan-out-last technique kept our write throughput manageable even as reaction volume peaked at 15,000 per second after a goal.
The scaling challenges weren't only technical but also financial. Cloud Run's autoscaling can lead to surprise bills if left unchecked. We set a maximum instance limit of 500 for the WebSocket gateway during matches. And we used committed use discounts for the base load outside of matchdays. The financial model was transparent enough that Osasuna's finance team could map digital costs directly to match attendance and forecast infrastructure spend for the next season. Engineers who treat cost as a first-class metric earn trust that keeps the platform alive.
Using Flutter for Cross-Platform Mobile App Development
We chose Flutter for the mobile client, targeting both iOS and Android from a single Dart codebase. The decision was driven by the need for smooth 60fps animations during match trackers and the ability to share a substantial amount of business logic via packages. We used the web_socket_channel package for the real-time connection and Riverpod for state management. Which gave us compile-time safety for our dependency injection graph. Animations were built with Flutter's native animation framework. And we offloaded heavy particle effects (goal celebrations) to Skia shaders to keep the UI thread free.
One of the trickiest parts was ensuring the app stayed responsive when the device was transitioning between WiFi and cellular during an exciting moment. We implemented a retry buffer with a local SQLite cache that stored events while offline and replayed them in order once connectivity resumed. This approach, combined
.Need a Custom App Built?
Let's discuss your project and bring your ideas to life.
Contact Me Today →