Skip to content

A deep dive on how the Roblox bootstrapper works

pizzaboxer edited this page Dec 27, 2023 · 44 revisions

Bloxstrap essentially works by mimicking the behaviour of the official Roblox bootstrapper, and then expanding on it to provide additional useful functionality, much of which would not be possible otherwise. Thus, I would like to provide useful information on how the Roblox bootstrapper works, as I think it would be useful to many people.

I won't touch on history too much here unless necessary (which there is lots of, it dates back to 2008 after all). This will simply focus on the current state of how it functions.

This will also only concern Windows, as I actually have no idea how it works on Mac. I don't own a Mac. lol.

Bootstrapper installation

Roblox installs to %LOCALAPPDATA%\Roblox, under a single user account only. It used to support being installed system-wide as Administrator, but not anymore, as it results in a lot of mess relating to permissions and stuff. I will only talk about functionality in the context of it being installed and ran in single-user mode only.

Installing/Updating Roblox

Identifying game client versions

Each version of the Roblox game client has several identifiers. However, the only one that you need to worry about is the version GUID, which is what is used to identify versions on Roblox's deployment system. An example of one is version-824aa25849794d67.

The latest version GUID can be fetched from https://clientsettingscdn.roblox.com/v2/client-version/WindowsPlayer, which delivers a JSON response, where the version GUID is attributed under clientVersionUpload.

The bootstrapper keeps track of the version GUID for the version of Roblox it currently has installed. It will check that API whenever it's launched, and carry out a Roblox update if the latest version GUID has changed.

The deployment system

Roblox distributes the game client across several categorized .zip files called packages, and uploads them to Amazon S3. Roblox then mirrors their S3 storage across several different CDNs. Here's all of the domains of which you can download Roblox from.

Type Base URL Notes
Amazon S3 https://s3.amazonaws.com/setup.roblox.com/ Where everything is sourced from. Also the slowest, that's why the CDNs exist.
Amazon S3 http://setup.roblox.com/ A direct alias for S3 above. Avoid using this, HTTPS doesn't work properly on it.
Akamai https://setup-ak.rbxcdn.com/ CDN mirror for S3
Cachefly https://roblox-setup.cachefly.net/ CDN mirror for S3
Cachefly https://setup-cf.rbxcdn.com/ A direct alias for the domain above on rbxcdn.com.
Balanced https://setup.rbxcdn.com/ Preferred, CDN balancer that automatically chooses between Akamai and Cachefly.

The bootstrapper uses the balanced one whenever it can. However, it will also used the other ones mentioned for redundancy in case setup.rbxcdn.com is inaccessible, if it's ever down or happens to be blocked or something.

The self-updating mechanism

You may have noticed that the latest version API supplies a version number for the bootstrapper. What's that about?

Aside from updating Roblox, the bootstrapper can also update itself. The bootstrapper is always built and deployed alongside a Roblox version. When the bootstrapper is about to install a new version of Roblox, it checks that latest bootstrapper version number against its own, and updates itself if it needs to, before updating Roblox.

You'll see this happening if you see a briefly-flashing "Please wait..." or "Getting the latest Roblox..." message when launching Roblox.

Downloading and assembling an installation

Now, we'll get to actually downloading files. Alongside the packages, there are also files that contain manifest data, named rbxManifest.txt, rbxPkgManifest.txt.

How do you actually get these files? The files for every version GUID are stored at the root of the base URL, with their file names being prefixed with the version GUID. For example, rbxPkgManifest.txt for version-824aa25849794d67 on the CDN balancer will be located at https://setup.rbxcdn.com/version-824aa25849794d67-rbxPkgManifest.txt.

rbxManifest.txt records information of every single game client file, with data being grouped two lines at a time. It really just records the MD5 hash. As far as I'm aware, this is no longer used. At one point, it was used for checking the integrity of a Roblox installation, but the bootstrapper hasn't appeared to do that for years. Regardless, the file is still generated for new version deployments.

rbxPkgManifest.txt records information of every single downloadable package, with data being grouped four lines at a time. It records compressed size, uncompressed size, and MD5 hash. File sizes are recorded as number of bytes. You can use this manifest for identifying what packages you need to download, or for determining how much disk space is needed to install/update Roblox.

The bootstrapper has a hardcoded table that records the associated extraction directory for each package. You can easily find these yourself using a hex editor or something. You can check them all out here.

Roblox installations are stored in %LOCALAPPDATA%\Roblox\Versions\<version GUID>\. Downloaded packages are cached in %LOCALAPPDATA%\Roblox\Downloads. These are (or should be) regularly cleaned out after a period of time or whenever it's suitable to do so, such as after an update.

In short, the bootstrapper will gather the list of packages to download from the package manifest, download them, and extract them accordingly. It's pretty simple.

Installing WebView2

One minor note: unlike every other package, WebView2RuntimeInstaller.zip is only extracted conditionally, based on if the WebView2 runtime is not installed. It checks for that according to these registry keys.

If it's not installed, it extracts the package, which contains the runtime installer, and then runs it with the provided args of /silent /install, so it automatically installs quietly in the background, while the bootstrapper shows its own indefinite progress dialog.

Starting Roblox

If the bootstrapper is being launched standalone (e.g. by being ran directly or through the 'Roblox Player' shortcut), Roblox will be started only with the --app argument to indicate a desktop app launch.

Protocol/URI handling

Roblox registers two protocols: roblox and roblox-player. The former is relatively new and used only for universal deeplinking, whereas the latter is more traditional and is used for everything else. Here's some examples of launch URIs that you can try out which use these protocols by pasting them into your browser's URL bar:

roblox-player:1+launchmode:app
roblox://experiences/start?placeId=1818

This is how Roblox launches itself from your web browser.

Brief disambiguation:

  • The term "protocol" refers to protocol identifiers such as roblox and roblox-player
  • The term "launch URI" refers to the full string used for launching the application such as roblox-player:1+blahblahblah
  • The term "protocol handler" refers to the application that's launched to handle the protocol

I won't go in-depth on how Windows protocol handlers work. If you don't know how, it's fairly easy to grasp. If you have Roblox installed, just open the Registry editor, go to HKEY_CURRENT_USER\SOFTWARE\Classes\roblox-player, and examine how it's structured.

Though, I'll explain this. Every protocol has an protocol handler, which is just an application. You can determine how the launch URI is fed to the protocol handler. in Windows, it's denoted as %1, if you look in shell\open\command under the protocol's registry key. From there, you can then process it. The Roblox game client is directly registered as the protocol handler, and is done whenever Roblox updates.

When the bootstrapper starts Roblox, it passes the protocol string directly into RobloxPlayerBeta.exe as the first launch argument. You don't really need to do anything, unless you want to manipulate the data given so you can control Roblox to behave in a certain way.

Parsing roblox-player protocol URIs

On that topic, I'd like to briefly mention something about how the roblox-player protocol is handled. Here's a longer example URI:

roblox-player:1+launchmode:play+robloxLocale:en_us+gameLocale:en_us+LaunchExp:InApp

If you look closely at this, you may notice that this is designed to cleverly form a stream of key-value pairs, all delimited by '+' symbols. Even the protocol identifier itself is part of it! If we serialized this to JSON form for the sake of clarity, it would look something like this:

{"roblox-player": 1, "launchmode": "play", "robloxLocale": "en_us", "gameLocale": "en_us", "LaunchExp": "InApp"}

If you ever need to parse/modify the string, you don't need to do anything special or complicated, it's really simple.

The bootstrapper isn't actually that relevant anymore

So, remember when I said earlier that the Roblox game client is what's registered as the protocol handlers? That wasn't a typo, that's actually how it is - well, how it's recently been. Roblox did this in a effort to cut down on the time spent waiting for the game client to launch, by cutting out the bootstrapper completely from the launch process. Which is pretty clever, I won't deny. Good job client team!

Nonetheless, how the hell does that work? Well, when the game client is launched, it does the version check itself. Actually, it checks against the version number, not the version GUID. If there's an update available, then it launches the bootstrapper so an update can be carried about.

You can see this for yourself by cracking open a Roblox log file, where you'll see this at the top:

2023-12-27T08:37:46.538Z,0.538225,7544,6,Info [FLog::UpdateController] UpdateController: versionQueryUrl: https://clientsettingscdn.roblox.com/v2/client-version/WindowsPlayer/channel/zflag
2023-12-27T08:37:46.538Z,0.538225,7544,6,Info [FLog::UpdateController] WindowsUpdateController: updaterFullPath: C:\Users\pizzaboxer\AppData\Local\Roblox\Versions\version-48a28da848b7420d\RobloxPlayerInstaller.exe
2023-12-27T08:37:46.539Z,0.539225,792c,6,Info [FLog::UpdateController] Update thread: started with protStr roblox-player:1+roblox-player:1+launchmode:play+robloxLocale:en_us+gameLocale:en_us+LaunchExp:InApp
2023-12-27T08:37:46.539Z,0.539225,792c,6,Info [FLog::UpdateController] Checking if updater exists at C:\Users\pizzaboxer\AppData\Local\Roblox\Versions\version-48a28da848b7420d\RobloxPlayerInstaller.exe. Returning true
2023-12-27T08:37:46.730Z,0.730281,7544,6 [FLog::Output] Settings Date header was Wed, 27 Dec 2023 08:37:47 GMT
2023-12-27T08:37:46.730Z,0.730281,7544,6 [FLog::Output] Settings Date timestamp is 1703666267
2023-12-27T08:37:46.959Z,0.959281,792c,6,Debug [FLog::UpdateController] version response: {"version":"0.605.3.6050660","clientVersionUpload":"version-48a28da848b7420d","bootstrapperVersion":"1, 6, 3, 6050660"}
2023-12-27T08:37:46.960Z,0.960281,792c,6,Info [FLog::UpdateController] Update thread: isUpdateRequired FALSE

Fortunately for Bloxstrap, this check is completely skipped if RobloxPlayerInstaller.exe doesn't exist in the game client's folder.

If the game client was started with a launch URI, then it passes that URI back into the bootstrapper as an arg when starting it.


Thanks for reading. That's about all you need to know for how the Roblox bootstrapper works. Hopefully this isn't too long or too confusing, and that it's helped to clear up any questions you may have about it.

Clone this wiki locally