Building a search engine for Trackmania's lost web
Trackmania United Forever had an in-game internet, and most of it is gone. Here's how I built a search engine for what's left of it.
A little history on ManiaLinks and TrackMania United Forever
Trackmania is an ongoing series of primarily PC based racing games by french developer NADEO (acquired by NADEO in 2009). The gameplay is heavily arcade-based with the main gamemode being “race against your own time”. The series is heavily built with custom community content in mind, with car 3d models, textures and tracks released to this day.
In November 2006, NADEO released “Trackmania United” which included all 7 previously released scenarios and car physics in one single package and in December of 2008 they released “Trackmania United Forever”, a big free update that updated the engine and added even more track editor models to use.
But TMU/TMUF was more than just a compilation, it also featured a full community ecosystem with a non-premium ingame-earnable currency called coopers and a dedicated server setup. Some of those servers still exist to this day and it’s not hard to find a small group of people racing, 20 years after it’s initial release.
One of those community ecosystem features are ManiaLinks. In-game “websites” that are created soly for this game and have special features such as providing new tracks, 3d car models and horns that can be downloaded and installed with a single click. Users can even get “paid” in coppers for their work.
The technical side of ManiaLinks
Under the hood, ManiaLinks are custom written XML files. A full suite of elements (such as <frame>, <quad> or <label>) exist and provide special functionality and layouting options. I’ve already tried documenting the ManiaLink format in 2025 out of sheer frustration and fear that good sources on it are starting to dry up and become dead links.
ManiaLinks are usually registered on the Trackmania player page, an ancient website, probably running on an old PHP server. There is no directory or search ingame, if you want to find a ManiaLink back in the days, you would frequent the NADEO forums and find threads where people shared their creations. The Trackmania web services resolve a manialink (such as laura or kripke) and return back the direct URL to the XML document. The game then renders this XML document via the ingame UI system.
Note: The successor game “Trackmania²” also supports ManiaLinks. They are not cross-compatible but share a lot of the features and systems. This article only focusses on Trackmania United (Forever) ManiaLinks.
The lost web
As I’ve said, the ManiaLink system has no public directory of registered sites. There used to be an ingame way to advertise your ManiaLinks through ManiaHome but that system has been broken for years now, restricting access to two ManiaLinks that never left. The official Trackmania forums were also shutdown a while back, so your only realistic option is to find an old thread and hope archive.org has a copy of the list. And even then, it will take a good chunk of time to filter out 2011 era ManiaLinks that have since been shut down.
It was awful seeing this part of the game disappear. I used to buy Trackmania United for this very system, I thought it was incredibly cool that you can create your own little in-game websites and put your own tracks on them.
As with the ManiaLink documentation before, I needed to do something. I don’t want this part of my childhood, of the internet, to just vanish. So I’ve decided to build ManiaFind a “ManiaLink search engine” in late 2025.
Version 1.0 - The initial set
For the first version of ManiaFind, I created a simple Database driven ManiaLink directory. The initial set of ManiaLinks came from myself by researching old blogposts from 2006 - 2018. As expected, most of them were hosted on free hosting websites and were shutdown ages ago. But even with those restrictions and a lot of manual research, I managed to create a set of 100 ManiaLinks that still work to this day.
Quickly, I’ve setup my own ManiaLink maniafind to easily find and navigate to this initial set of ManiaLinks.

Version 2.0 - Crawlin’ like it’s 2010 Google
I showed this initial version around in the community and got really great responses. At the same time, it was also clear that my setup was not sustainable. At the rate I was manually researching active links, I would have to dedicate a big chunk of my life just typing in links into a game, add them to a database and repeat.
I wanted to build a real crawler. This crawler could not only extract all cross-referenced ManiaLinks, it could also periodically check if my database entries are still live.
There was only one problem: How does the game resolve ManiaLinks to actual XML document urls.
An old code project
My first idea was to use wireshark to intercept requests from the game and potentially find a server that is used as a “custom mini DNS”. While I did find some requests to a NADEO server when entering a ManiaLink, there wasn’t a simple API that I could just use. One thing was interesting though: Most requests came back as plain HTTP urls. In all my tests, I’ve only found plain HTTP urls or TLS 1.0 HTTPS urls. This at least confirmed that we’re dealing with “ancient technology” and explains why a lot of NADEO’s own Trackmania services stopped working (They seemingly use a variant of oauth behind TLS 1.0, which was deprecated in Windows 10 and seemingly removed in Windows 11).
With wireshark being a dead-end, I did some more research. I’ve used GitHub Grep by Vercel to find some code projects related to Trackmania United, maybe someone had already solved this problem before. I just had to ignore Trackmania² ManiaLink content, because as I’ve said before, they work entirely different.
And indeed, some projects used what is called the Trackmania Web Services SDK. At this point I have not heard about this SDK, so after another quick search I found an old Google code archive of a PHP 5 SDK NADEO created in 2011 to showcase how a NADEO API can be used to receive various Trackmania United related information.
Jackpot! That’s exactly what I needed. It even includes an example to resolve a ManiaLink that returns the direct URL and the original playerlogin associated with it!
I just needed to figure out how to get an API token. And I had to pray that system still exists.
Getting an API token in 2026
Finding an SDK was one thing, getting my own API token was another. You see, not only did NADEO use TLS 1.0 for their own ManiaLinks, they also used it for large portions of their developer page.
To get an API token, I had to install a Windows 7 VM that would still allow TLS 1.0 connections and override my host systems protections to just let those connections go through. It wasn’t as hard as I thought, but it also wasn’t trivial. After some trial and error, I finally had my keys and was able to probe this new API. The API limits are REALLY low (~360 requests per hour) but with enough planning, this would be no problem to me. We can cache all responses and optimize our crawler queue to work within these requirements.
My first alotted 360 requests were me playing around with the API and checking out the source-code of the ManiaLinks I’ve seen on a daily basis back then. It also helped me understand how the XML code is written “in the wild”. Up until then, I only had a number of examples/tutorials from back then and my own ManiaLink, which I’ve written from scratch based on the documentation I’ve found in my previous project.
Building the crawler
With the research phase concluding on a high-note, I wanted to start developing the crawler. The research phase helped a lot, because there were some important things I had to keep in mind:
- The queue has to be split between ManiaLinks (counting towards our API limit) and normal URLs
- Almost all ManiaLinks are served via HTTP or TLS 1.0 HTTPS. A modern HTTP client will likely refuse any connections
- Some ManiaLinks have a UserAgent check to direct web browsers to a different page
- The queue must both be lenient enough to not dry up but also hard capped to not fill up with 200 subpages of the same page
Point 1 and 2 were easy enough, through some CURL options, I was able to suppress any warnings and get access to the pages. For point 3, I created a small “dummy XML” that I could enter ingame that just dumped the full request headers into a txt file that I was able to cross-check with a web request. As it turns out, most of those switches just check for the string GameBox in the User-Agent. (GameBox being the name NADEO gave the Trackmania game engine).
Point 4 was a bit more tricky. I’ve decided to create a multi-tier system to get the most out of what I have. We have 360 API request per hour. I took a round 300 (5 per minute) and split them up into two buckets: Refreshing an existing entry (1 out of 5 requests) and exploring a new entry (4 out of 5 requests). If a ManiaLink came back as not-existing (either because NADEO or the player removed it), it is placed in a database entry so we don’t throw away API requests for dead links.
The resolved direct URLs are then put into a second queue for closer examination. For this step, I wanted to have clear rules because I don’t want to overwhelm those old web hosters. For every crawler step (1 every 60 seconds) my crawler takes 6 URLs, fetches their XML and analyzes them. It was important to setup the XML parser to be as lenient as possible, because some ManiaLinks never properly encoded their text labels.
If the URL to the XML is dead, it will be placed into the queue with a cooldown of a few days, sometimes it’s just not the right time. After a few failed requests, the URL (and the manialink) are placed into the “dead links” list with a much higher cooldown of a few months. Never say never. This also happens when the URL is not dead but responds back non-manialink content. Some of those used hosters have a dedicated “We’re currently down” HTML response, even when requesting an XML file. Obvious non-ManiaLink related files (.zip, .gbx, .jpg etc) are also entirely skipped.
If the URL does respond back a valid ManiaLink document, the crawler generates a content hash (So we can track when/if the content changed) and extracts all links from the source-code. A ManiaLink can both link directly to an XML document AND other ManiaLinks, so it was important to differentiate them and put them in the right buckets.
And because we want to detect stale links as well, we also document the last timestamp a ManiaLink was online and the last time it was checked. Currently, each ManiaLink is rechecked every few days, but this might change, based on how full the queue is. If a link is dead for more than 30 days, it is marked as stale and may be moved to the list of dead links eventually. We’ll also document each cross-link, maybe I can create a node graph for this in the future.
Combatting clusters
I also needed a solid system to detect clusters. While most ManiaLinks just link to other XML documents via plain HTTP, some users were very experimental and created a new ManiaLink for every single subpage. I don’t know if this was common back in the day, but I really needed to detect and group these links together to not clog up the queue with a single page.
I came up with a small system that both compares ManiaLink likelyness (eg: mylink1, mylinkhome, mylink2, mylinkmaps) and the resolved servers/paths and groups them after a certain number of cross-links and ManiaLinks were found. We currently have at least two ManiaLinks in the directory that have ~100 sub-ManiaLinks each. On the actual search, they are grouped when a certain threshold is reached.
The results
I’ve let the crawler run for a few weeks now and we’ve successfully expanded the searchable directory from 100 to over 600 active ManiaLinks with thousands of cross-linked subpages. While I know that this is just the beginning and that there probably are still ManiaLinks out there that cannot be found, I am incredibly happy to make this set of pages from this 20 year old game available again.
Over the last couple of days I’ve also decided to finally build a web interface for the project. Check it out if you’re interested!
