Building a Head-to-Head NFL Betting App from Scratch

Ahmad W KhanAhmad W Khan
9 min read

It was one of those projects that makes you either question your sanity or fall in love with your profession all over again—a head-to-head NFL fantasy football betting app, with real money on the line, and a deadline that loomed as ominously as a fourth-quarter Hail Mary. I was working remotely as a senior software engineer, focusing primarily on backend development but with enough frontend experience to take on both sides of the stack. The task was clear: build a fully functional fantasy football betting app before the first NFL kickoff. The reality? Anything but straightforward.

The Stack Switch

The project initially came to us as a MEAN stack build—MongoDB, Express.js, Angular, and Node.js. The client had already invested in UI mockups using Angular, but as we dug into the requirements and the tight timeline, it became clear that we needed a more flexible and efficient frontend framework. That’s when I suggested we move to React.

The reasons were compelling: React’s component-based architecture would allow us to build reusable components, manage state more efficiently, and iterate quickly—crucial for a project that needed to be live before the NFL season kicked off. The clients, after seeing a few quick demos, were convinced. React it was.

But this decision came with its own set of challenges. The project was now largely in my hands, and while my lead developer was incredibly talented, he was spread thin with client meetings, big-picture planning, and managing an agile process across multiple time zones. This left me as the lone developer responsible for both the frontend and backend. My lead, to his credit, trusted me completely. He gave me free rein over the development process and kept meetings to a minimum, preferring to communicate asynchronously. This was essential given our scattered team—designers in one country, clients in another, and me working late nights from my home office.

Embracing the Grind: My Midnight Work Routine

With everyone in different time zones, my workday started when most people were winding down—6 PM until 2 AM, and often later as the deadline approached. The night became my playground. There’s something uniquely satisfying about coding in the stillness of the night, when Slack notifications are few and far between, and the only sound is the clatter of my mechanical keyboard.

I thrived in this environment. The quiet hours allowed me to focus deeply on the complex problems at hand, without the constant interruptions that come with a typical workday. It was during these late-night sessions that I tackled some of the most challenging aspects of the project.

The Backend Beast

The backend was built using Loopback.js, a framework that was relatively new to me. Loopback’s model-driven approach, however, quickly became a lifesaver. It allowed me to define data models—User, Bet, Game, Transaction—and automatically generate REST APIs. This was a godsend, given the scope of the project and the pressure to deliver quickly.

Automating the Betting Logic

The real heart of the app lay in its betting logic. We needed to automate everything from determining winners to calculating payouts and updating user balances—all in real-time and with no room for error. This is where cron jobs became my secret weapon.

I set up a series of cron jobs to handle critical tasks:

  1. Game Outcome Processing: A cron job would run every hour to fetch the results of completed games, compare them with user bets, and determine winners.

  2. Payout Calculations: Another cron job handled the payout calculations, factoring in the platform’s cut.

  3. Balance Updates: Finally, the system updated user balances based on their wins or losses.

These cron jobs were the unsung heroes of the backend, ensuring the app ran like a well-oiled machine, even as thousands of users placed their bets.

const cron = require('node-cron');

cron.schedule('0 * * * *', () => {
  processGameOutcomes();
});

In processGameOutcomes(), the script fetched games marked as "completed" but not yet processed, iterated through each bet, and updated the Transaction records accordingly. This approach ensured that the app handled thousands of bets efficiently, without missing a beat.

Tackling the Frontend: React, Wallets, and Card Payments

While the backend was complex and required a lot of deep thinking, the frontend came with its own set of challenges. As the sole developer on this side of the project, I was responsible for everything—from designing the user interface to implementing the wallet system and integrating card payments.

Working with React was a joy. The framework’s flexibility allowed me to build a modular, responsive, and dynamic user interface that could handle the fast-paced nature of a fantasy football betting app. But the frontend wasn’t without its hurdles, particularly when it came to implementing the wallet and card payment systems.

Designing the Wallet System

The wallet system needed to be intuitive, secure, and reliable. Users had to be able to deposit funds, place bets, and withdraw their winnings without any friction. I started by designing a user-friendly interface for the wallet, where users could easily manage their funds. The challenge came with the card payment integration.

We needed to support multiple payment gateways, each with its own set of quirks—API inconsistencies, currency conversions, and edge cases like declined transactions. I spent countless hours debugging issues, ensuring that the payment flow was seamless and error-free. After all, we were dealing with real money, and the last thing we wanted was for users to experience any issues when handling their funds.

I created reusable React components to handle different parts of the wallet system. The WalletComponent managed the display and interaction of user funds, while the PaymentComponent handled card payments, providing users with real-time feedback on the status of their transactions.

The Chrome Extension: Real-Time Roster Sync

Just when I thought I had a handle on everything, another challenge landed on my plate: real-time roster synchronization. Our users, being avid fantasy football enthusiasts, often managed their teams on platforms like Yahoo Fantasy. They wanted a seamless way to import their existing rosters into our app, and for the stats to reflect real-time performances.

The solution? A Chrome extension. I proposed building a Chrome extension that would allow users to:

  1. Scrape: Extract the user's roster data from Yahoo Fantasy.

  2. Send: Transmit this data to our backend for processing.

  3. Sync: Update player stats in real-time during NFL games.

Crafting the Scraper

The extension’s content script would run on Yahoo Fantasy’s team page, parsing the DOM to extract player names, positions, and other relevant data.

const players = [];

document.querySelectorAll('.player').forEach(player => {
  const name = player.querySelector('.name').textContent;
  const position = player.querySelector('.position').textContent;
  players.push({ name, position });
});

chrome.runtime.sendMessage({ players });

This script scraped the roster data from Yahoo Fantasy and sent it to our backend, where it was processed and synced with our app's player database. This ensured that our users always had the most up-to-date information, even as games were happening live.

The Launch: A Birthday to Remember

After weeks of burning the midnight oil, the app was finally ready for launch. The night before the NFL season kickoff, we had a virtual launch party on Discord. The team, spread across different time zones, gathered online to celebrate. It was one of those moments where all the hard work, late nights, and challenges seemed to pay off. The client was thrilled with the final product, so much so that they sent me gift cards as a token of appreciation.

The launch of the app coincided with my own special day, making the celebration even more memorable. We spent some time on Discord, toasting to the successful launch, but I had to leave early. A birthday party was waiting for me back home, and after the intense grind of the past few weeks, I was ready to enjoy it.

Reflections

Looking back, this project was one of the most challenging and rewarding experiences of my career. It pushed me to my limits, forced me to learn new frameworks and technologies on the fly, and made me appreciate the value of trust and autonomy in a team. My lead’s hands-off approach allowed me to take full ownership of the development process, and the freedom to make key decisions ultimately led to a successful launch.

Working across multiple time zones, juggling frontend and backend responsibilities, and dealing with the pressure of a tight deadline—all while working remotely—taught me the importance of discipline, communication, and the ability to adapt quickly. It also reinforced my love for coding, especially during those quiet, late-night hours when I could immerse myself in the work without distractions.

As the NFL season kicked off and our users started placing their bets, I felt a deep sense of accomplishment. The app was live, people were using it, and it worked. More than that, it was something I had built from the ground up, tackling every challenge head-on, and coming out the other side with a product that not only met but exceeded expectations.

In the end, it wasn’t just about the technical challenges or the sleepless nights—it was about the journey of creation and the lessons learned along the way. This project reminded me why I became a software engineer in the first place: the thrill of building something from scratch, the satisfaction of solving complex problems, and the joy of seeing people interact with something you’ve crafted with your own hands.

It also underscored the importance of adaptability in the fast-paced world of software development. The decision to switch from Angular to React, the learning curve with Loopback.js, the development of a real-time roster sync via a Chrome extension—each of these challenges required a willingness to pivot and learn on the fly. In the end, these decisions not only saved time but also enhanced the user experience, making the app more responsive, efficient, and user-friendly.

Moreover, this project highlighted the value of trust within a remote team. My lead developer’s confidence in my abilities allowed me to work autonomously, which was crucial given the tight deadlines and the complexity of the project. This level of trust enabled me to experiment, take risks, and ultimately, deliver a product that was both innovative and robust.

The launch of the app marked not just the end of a project but the culmination of a period of intense growth for me as a developer. As this was just the start and now we had to scale the app significantly and start thinking about re-working the architecture into a microservice architecture. I emerged from it more confident in my abilities, more resilient in the face of challenges, and more appreciative of the collaborative spirit that drives successful projects.

And as the NFL season unfolded, with users engaging with the app we had built, I realized that this experience had reignited my passion for coding. Despite the challenges, or perhaps because of them, I was reminded of why I love this work—the thrill of creation, the satisfaction of overcoming obstacles, and the joy of seeing a project come to life.

In the quiet moments after the launch, as I reflected on the journey, I knew that this project was more than just another line on my resume. It was a testament to what can be achieved when you embrace the grind, trust in your abilities, and pour your heart into your work. And as the app continued to thrive, I felt a deep sense of pride—not just in the product we had delivered, but in the personal and professional growth that came with it.

*If you are curious about the product I am talking about:

Then you can take a look at the product being live since 2021 here:
toppropsports.com

Thanks for reading. Happy coding!

0
Subscribe to my newsletter

Read articles from Ahmad W Khan directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Ahmad W Khan
Ahmad W Khan