Table of contents
La Table des Scores
La Table des Scores is a private leaderboard tracking app for french quiz game La Table des Savoirs.
Introduction
La Table des Savoirs is a french quiz website where everyday at noon, you have 24 hours to play a game of 10 general knowledge questions.
Source: La Table des Savoirs
Each day you get points for answering right on questions and there is also a bonus system where you can bet on your answers. Each season corresponds to a month and your total is the sum of all your daily scores. This means that you have to be constant in your performance to avoid being the last on the leaderboard. Finally because you can bet on a maximum of 3 answers and the lower the percentage of correct answers, the higher the bonus, you can have a higher score than another player while having less right answers.
I started playing this game with a group of friend and we were always sending our daily scores but we wanted more.
The scoreboard
First steps
What I wanted was a leaderboard with all my friends to compare our total points. So I started to poke around the API and look at the network console to find the relevant requests. Luckily the useful ones do not require authentication.
I started working on the app and with the help of AI coding tools I was able to have a first working version that I could share in less than an afternoon. It was simply hosted with GitHub Pages because it was a purely static website and the API allowed requests from any source.
With this version, one could add players to their list and they would be sorted by total score for the season, highest to lowest.
First problems
It worked fine for about a month but then the original website issued an update that broke my API calls.
They restrained their CORS policy and my API requests were all being rejected. Fortunately, this was the only restriction they added and it was possible to avoid this restriction using a backend but this was not possible using GitHub Pages so I switched to Cloudflare Pages and used a worker to proxy my API requests.
With that fix, I wanted the website to be able to be found from a Google search but even using the Google Search Console the website was not being crawled, probably because of the default domain name given by Cloudflare. When I added a custom domain then the search console accepted the website.
Daily scores
As I was working again on the app, I dug a little deeper on the API side to see if I could get more information back.
Turns out that the game developer made some modifications and now the top 10 players of the day with their score were displayed.
The request done by the website is :
https://api.latabledessavoirs.fr/leaderboards/day/{dayNumber}/facile/top?limit=10
I thought that by changing the limit to an arbitrary high number I would be able to get the whole table but the limit is capped at 50. Unless… you use 0. Then you retrieve the entire player list with their score.
Using a negative number also avoids the limit but -X remove X elements so using -10 remove the last 10 scores.
Players names are anonymized on screenshots
At the time this was the only way to retrieve a player score for the day. You had to fetch the entire leaderboard and search for players using their username (cf Future evolutions).
Edition
I decided to add the option to have multiple “Leagues” i.e. multiple player lists to compare yourself with different group of friends. You can add players by searching for their name (or similar string) and confirm by seeing the list of players and their score. Each league must have a name to differentiate them and you can easily share a league with a name with a simple URL so that the other members don’t have to search all the pseudonyms manually.

The league name and player names are in the URL GET parameters like this :
https://latabledesscores.adrienchamussy.com/?players={name1}%2C{name2}%2C{name3}&league={leagueName}
Note
%2Cis the URI encoded version of a comma (,)
Statistics Graphs
One feature that does not exist in the base game when looking at your profile statistics is to see your score evolution.
Profile statistics. Source: La Table des Savoirs
By fetching the top leaderboard of the current season, I can find all players score and derive the accumulation of points, draw the daily score and the score average to see it vary through the month.
What i wanted also to have is a distinction between score and number of right answers. The betting is part of the game but it is first a general knowledge quiz game. I added a toggle to switch between score and number of correct answers for the graphs.
Graphs anonymized : Accumulation of points, Daily score, Daily average
Optimizations
Since we are using an open API without any identification, we don’t have real restrictions. However if we want to keep it that way and hope that they do not change that, we try to keep the amount of requests controlled to avoid tripping any alarms.
There are multiple optimizations to reduce the number of requests done to the real API, this also helps to reduce loading time on this leaderboard site.
By design
On the August 2026 season, there were 35 516 participants registered to play in “easy” difficulty and 4 200 in “hard” mode (hard mode requires a subscription). With this data we can estimate that there is a high probability that the player only wants to see the easy leaderboard. To avoid making useless requests, the hard mode leaderboard is disabled by default but a single click can activate it and it’s activation is stored in the localStorage.
Drawing the Statistics Graphs requires more data. The majority of the time, players only want to check the score of their friends on this day and compare their total score so they are hidden inside a collapsible section. If a user wants to see the graphs it is just 1 click away but if they do not care, it’s that many requests saved.
Caching
The most obvious one is caching. Once we fetched the data to the API there is no need to ask the server for the same information. The issue, as always is cache invalidation. Serving out-of-date or just false information must be avoided as much as possible.
To better understand what “out-of-date” information could be on this app I need to explain something : Because this is a general knowledge quiz game and the answers are free text, the game might flag your answer as false while it’s technically correct (the best kind of correct). To solve this issue, there is a contestation button : if you think that your answer should be accepted but has been refused, you can ask for a moderator to evaluate your answer. If your answer is validated, all players with the same answer will receive the points. But those contestation can take days to be solved, or weeks. Between typos, synonyms and answers that are technically true because the question wasn’t sufficiently “locked”, and maybe just frustrated players, there are a lot of contestations.
The solution is simple : don’t do any caching. But I think I found a balanced middle-ground :
- Total score for the season are not cached at all. Those requests are very light and fast and it is the most valuable information of the website.
- Daily score for days older than 2 days have a 7 day TTL. Since we fetch the entire scoreboard for days, those requests are heavy but the results are unlikely to change : new players cannot play, the only thing that can change are contestations for the answers. Since the total score is not cached, this is only important when viewing the Statistics Graphs.
- Daily score for today and yesterday’s game : TTL of 2 hours. The most obvious contestations are generally solved within the first few days so refreshing this data is worthwhile. Also when the current day changes, we automatically refresh this data because that’s the moment when bonuses are applied so the score of players change.
- Daily score is also only cached for players who have played today. If a player in the scoreboard has no data for the current day in the cache, we try to refresh it to check if they played. This is done to ensure that a player who has just finished playing see their score in the leaderboard.
Future evolutions and conclusion
The API always evolves with frequent update and the app has to be updated to match the backend evolutions. Since it is a “pirate” app it breaks without any warning and I have to fix it as soon as possible. In the future if the backend is tighten to prevent unauthorized use of the API the app might be unfixable.
In the meantime I try to get as much data as possible from the API and a recent change added public profiles. With a single requests I can get the entire season scores for a single player :
https://api.latabledessavoirs.fr/public-profile/{playerName}/season-progress/{seasonNumber}
This is efficient and lightweight but if I wanted to use this request to replace how the Statistics Graphs are currently drawn, there would always be a trade-off :
- The current way does
xrequests wherexis the number of days in the displayed season. Between 1 and 31. - Switching to this endpoint would change it to
yrequests whereyis the number of players in the scoreboard.
For small leaderboard the new endpoints seems less expensive but we save a lot of requests with the current caching method that we could not use with the new one.
Because of these modifications of the API, this article might not be totally accurate with the current implementations. Either way, the code is open-source so the implementation can be checked at any time.
This app was a lot of fun to work on. I was able to test different models of AI assistant and even free models are enough for simple projects like this. It also shows how much I am able to continue to perfect a project in a good working state. I always had new ideas of features and “improvements”.
