Accessing the Roblox Web API
The Roblox API is extremely powerful - it can be used to create anything from group ranking bots to game statistics websites.
As a developer, there are two main ways you’ll want to access the Roblox API: sending the requests yourself or using one of the multiple wrappers for your favorite programming language. In this tutorial, I’ll go over both of these methods.
Notes
This tutorial currently offers Python code examples. To contribute and add a programming language you are familiar with to this tutorial, please reply to this post or send me a message.
You can’t access the Roblox API from within a Roblox game without a proxy.
If you need more help with the Roblox API, consider joining the RoAPI Discord community for support.
Libraries
If you don’t feel like sending the requests yourself, multiple “wrapper libraries” exist that allow you to stop handling the boilerplate Roblox API code and start writing code that does what you want it to do in less time. These libraries have their own tutorials - feel free to use those rather than this one if you don’t want to deal with sending the requests yourself.
They can also allow you to have the freedom of sending your own requests without forcing you to deal with the Roblox API’s quirks. I’ve got a post explaining how to do this with ro.py, but other libraries have their own systems of doing this.
If you decide to use one of these libraries, most of this tutorial won’t be useful for you, so you should refer to documentation or tutorials for your own library. If you’re sending requests with your library, the Finding endpoints and Understanding documentation sections may be useful.
Here’s a list of some of these libraries:
Name | Resources | Language | OOP | Async | Developers |
---|---|---|---|---|---|
ro.py | Docs Tutorial | Python 3 | Yes | Yes | @jmkd3v @iranathan |
pyblox | Python 3 | Partial | No | @Sanjay-B | |
bloxy | Docs | Node.JS | Yes | Yes | @Visualizememe |
noblox.js | Docs | Node.JS | No | Yes | @suufi |
View More
Name | Language | OOP | Async | Maintained | Developers | More Info |
---|---|---|---|---|---|---|
ro.py | Python 3 | Yes | Yes | Yes | @jmkd3v @iranathan | |
robloxapi | Python 3 | Yes | Yes | No | @iranathan | Predecessor to ro.py. |
robloxlib | Python 3 | Yes? | No | No | @NoahCristino | |
pyblox | Python 3 | Partial | No | Yes | @Sanjay-B | |
bloxy | Node.JS | Yes | Yes | Yes | @Visualizememe | |
noblox.js | Node.JS | No | Yes | Yes | @suufi | |
roblox.js | Node.JS | No | Yes? | No | @sentanos | Predecessor to noblox.js. |
cblox | C++ | Yes | No? | Yes | @Meqolo | |
robloxapi | C# | Yes | Yes | Maybe | @gamenew09 | |
roblox4j | Java | Yes | No? | No | @PizzaCrust | |
javablox | Java | Yes | No? | No | @Pythonic-Rainbow | |
robloxkt | Kotlin | ? | ? | No | ? | I have no information on this. |
KotlinRoblox | Kotlin | Yes? | No? | No | @Pythonic-Rainbow | |
rbx.lua | Lua | N/A | No? | Yes? | @iiToxicity | |
robloxcomm | Lua | N/A | ? | ? | ? | Again, no info on this or link. |
tsblox | TypeScript | Yes | Yes | No | @Dionysusnu | |
roblophp | PHP | ? | ? | ? | ? | Repo seems to be deleted. |
Finding endpoints
The first thing you’ll need to know when accessing the API is what endpoint you’ll need to do something. Try to stay away from endpoints on api.roblox.com or www.roblox.com - there are almost always better alternatives in subdomains.
You should also keep track of the official list of deprecated web endpoints for updates on when endpoints are disabled.
Roblox has a “consolidated page” that contains most domains and endpoints that you can use to find the endpoint you need at https://api.roblox.com/docs?useConsolidatedPage=true. You can also access the documentation for an individual domain by appending /docs to the end of it (e.g. users.roblox.com > users.roblox.com/docs)
@matthewdean has a list of Roblox subdomains available here which can be used as an alternative to the consolidated page. @juliaoverflow has a modified version of this list that you can access here if you’re having trouble finding what you’re looking for.
Some domains don’t have documentation available, like realtime.roblox.com. For these endpoints, there’s not much you can do besides looking at the source code of other wrapper libraries or spying on the requests the Roblox website makes with your browser’s developer tools.
Understanding documentation
Each documentation page contains a list of public endpoints available on that domain and lots of information about how to use them. Documentation for a single endpoint will look something like this:
The text in top left hand corner and the background color differ depending on the method of the request, most often GET or POST.
The Example Value contains an example of what the response from this endpoint might look like - this is useful when you want to build code that requests to an endpoint without sending a request to it yourself to figure out how it responds.
The Response Content Type determines what should be passed to the Accept
header - there’s almost never any reason to change this.
The Parameters change what data is passed to the endpoint when sending the request. The data is passed as a query string or as part of the URL for GET requests and is passed as a JSON body in almost all other requests.
The Response Messages will explain what different HTTP Status Codes mean when returned from the server - if you’re getting an error without enough information, you can check the response messages to see if that status code means something for that endpoint.
The “Try it out!” button will send a request to this endpoint with the data supplied in the Parameters. This will be useful for testing out an endpoint without writing code to send requests.
Here’s an example of an endpoint’s POST documentation:
This one looks a little different - as you can see, we’ve got a parameter labeled request
, which just refers to the body of the request, as you can see from the “Parameter Type” to the right of it.
We also are able to change that data’s content type - you’ll almost always want to keep this on application/json
given most endpoints accept JSON.
You’ll also see an “Example Value” - this shows you an example of data you can pass as the request body. Clicking on that Example Value will immediately set the body to the example data:
This is extremely useful for quickly testing an endpoint before implementing it into your program.
Getting started
At this point, you’re ready to use most of the endpoints that take in GET requests on these domains, as they won’t require authentication, like users.roblox.com/v1/users/userId. This endpoint returns response data that looks like this.
{
"description": "Welcome to the Roblox profile! This is where you can check out the newest items in the catalog, and get a jumpstart on exploring and building on our Imagination Platform. If you want news on updates to the Roblox platform, or great new experiences to play with friends, check out blog.roblox.com. Please note, this is an automated account. If you need to reach Roblox for any customer service needs find help at www.roblox.com/help",
"created": "2006-02-27T21:06:40.3Z",
"isBanned": false,
"id": 1,
"name": "ROBLOX",
"displayName": "ROBLOX"
}
You’ll probably use this endpoint along with other endpoints on users.roblox.com quite a lot, as they are extremely useful for grabbing information about a user.
Here’s an example:
🐍 Python
import requests
user_id = 1 # User ID
user_req = requests.get(f"https://users.roblox.com/v1/users/{user_id}")
user_data = user_req.json()
print("Name:", user_data["name"])
print("Display Name:", user_data["displayName"])
print("User ID:", user_data["id"])
print("Description:")
print(user_data["description"])
Handling errors
Here’s an example of an error returned from the users.roblox.com/v1/users/userId endpoint:
{
"errors": [
{
"code": 3,
"message": "The user id is invalid.",
"userFacingMessage": "Something went wrong"
}
]
}
As you can see, it’s an errors
list containing objects with a code
, message
, and userFacingMessage
. The code
is an identifier used for an error on an endpoint. The message
is information about the error intended for the developer, and the userFacingMessage
is information about the error indented for the user. It isn’t always present and often isn’t as informative as the message
.
We can use this code along with the HTTP response code (400
) and the endpoint’s Response Messages from the documentation to find more information:
In this case, it’s just telling us what we already know from the message
.
There are many cases where the API just doesn’t give us useful information, like this:
{
"errors": [
{
"code": 0,
"message": "Something went wrong with the request, see response status code."
}
]
}
In this case, we don’t get much information - the best we can do is use the documentation to try to figure out what’s wrong here.
Authentication
We can only do so much without authenticating, though. Authenticating will allow us to send API requests as a logged-in user, which will allow you to write bots that can modify content on the Roblox platform (for example, ranking a user in a group). To do this, we need to get our .ROBLOSECURITY cookie.
The .ROBLOSECURITY cookie is a session token, which means that as soon as you log out with the Settings > Logout button you’ll invalidate this .ROBLOSECURITY token and your program will no longer be authenticated. I recommend using an alternate account while messing around with the Roblox API as to not accidentally do something irreversible on your main account.
Please make sure that you do not share this token! Anyone with the token will gain full access to your account.
Do not log out after you have grabbed your cookie, as it will invalidate the cookie. To get around this, you can open an incognito/private window, log in, grab the cookie, and then close that window.
Use an extension
You can use an extension that allows you to read and edit cookies (for example, EditThisCookie)
Chrome, Chromium, Brave, Opera, Vivaldi, new Microsoft Edge, and other Chromium-based Browsers
You can access the cookie by going to roblox.com, pressing the padlock icon next to the URL in your browser, clicking the arrow next to “roblox.com”, opening up the “Cookies” folder, clicking “.ROBLOSECURITY”, clicking on the “Content” text once, pressing Ctrl+A, and then pressing Ctrl+C (make sure not to double-click this field, as you won’t select the entire value!)
Alternatively, you can access the cookie by going to roblox.com, pressing Ctrl+Shift+I to access the developer tools, navigating to the “Application” tab, opening up the arrow next to “Cookies” on the sidebar on the left, clicking the “www.roblox.com” item underneath the Cookies button, and then copying the .ROBLOSECURITY cookie by double-clicking on the Value and then hitting Ctrl+C.
Firefox
You can access the cookie by going to roblox.com and pressing Shift+F9, opening up the arrow next to “Cookies” on the sidebar on the left, clicking the “www.roblox.com” item underneath it, and then copying the .ROBLOSECURITY cookie by double-clicking on the value and then hitting Ctrl+C.
As we’re now sending requests with cookies, it’s easier for us to use a “session” object that maintains our cookies on each new request. Your programming language of choice may not support a “session object”. Requests also allows us to save time by passing a dictionary containing cookies rather than passing a Cookie
header. Due to the fact that your own requests library of choice may differ in features from my own, I’ll demonstrate the same thing with a cookie dictionary, a header, and a session.
🐍 Python
import requests
cookie = "_|WARNING:-DO-NOT-SHARE-THIS.--Sharing-this-will-allow-someone-to-log-in-as-you-and-to-steal-your-ROBUX-and-items.|_RestOfCookieGoesHere"
# No session, with cookie dict
req = requests.get(
url="https://users.roblox.com/v1/users/authenticated",
cookies={
".ROBLOSECURITY": cookie
}
)
# No session, without cookie dict
req = requests.get(
url="https://users.roblox.com/v1/users/authenticated",
headers={
"Cookie": ".ROBLOSECURITY=" + cookie
}
)
# With session
session = requests.Session()
session.cookies[".ROBLOSECURITY"] = cookie
req = session.get(
url="https://users.roblox.com/v1/users/authenticated"
)
X-CSRF-Token
At this point, we’re now authenticated - but there’s one thing missing. If we try to send a POST request, you’ll notice that the request still fails.
For this example, I’ll send a POST request to auth.roblox.com, which won’t actually do anything to your account but can be used for example purposes.
🐍 Python
import requests
cookie = "_|WARNING:-DO-NOT-SHARE-THIS.--Sharing-this-will-allow-someone-to-log-in-as-you-and-to-steal-your-ROBUX-and-items.|_RestOfCookieGoesHere"
session = requests.Session()
session.cookies[".ROBLOSECURITY"] = cookie
req = session.post(
url="https://auth.roblox.com/"
)
print(req.status_code) # output the status code
print(req.json()["errors"][0]["message"]) # output the error message
This code will output the following:
403
Token Validation Failed
The 403 Forbidden
status code is returned when the client is not permitted access to the resource despite providing authentication such as insufficient permissions of the authenticated account.
If you saw this while trying to write your own code to access the API, you might ask “why is this error coming up? My .ROBLOSECURITY token is correct, and it worked when I used the “Try it out!” button on the documentation page.”
The truth is that this error message isn’t referring to “token” as in your .ROBLOSECURITY token - it’s actually referring to a header that you have to supply to all requests that change data called the X-CSRF-Token
.
To handle this token, each time we send a request, we’ll save the X-CSRF-Token
- which is present in the response headers - to a value. Then, if the request failed with a status code of 403, we’ll send the request again with the X-CSRF-Token
we just got the first request as a request header.
With the Session object, we can just store the token in the headers
dictionary, but you can pass them directly to each request as well.
Here’s an example of that:
🐍 Python
import requests
cookie = "_|WARNING:-DO-NOT-SHARE-THIS.--Sharing-this-will-allow-someone-to-log-in-as-you-and-to-steal-your-ROBUX-and-items.|_RestOfCookieGoesHere"
session = requests.Session()
session.cookies[".ROBLOSECURITY"] = cookie
# send first request
req = session.post(
url="https://auth.roblox.com/"
)
if "X-CSRF-Token" in req.headers: # check if token is in response headers
session.headers["X-CSRF-Token"] = req.headers["X-CSRF-Token"] # store the response header in the session
# send second request
req2 = session.post(
url="https://auth.roblox.com/"
)
print("First:", req.status_code)
print("Second:", req2.status_code)
This program will send one request, check if the X-CSRF-Token
was present in the response, and if so will store it back into the session’s headers. We then repeat the first request again, and then outputs the status codes from both requests.
This code should output the following:
First: 403
Second: 200
This solution works - but it doesn’t scale well. If we want to properly do this, we’ll put all of this logic in a function that handles our requests for us and then call that when sending requests. This is (essentially) what the request wrappers in Roblox API wrapper libraries do.
Here’s an example of a function that wraps the requests.request
function:
🐍 Python
import requests
cookie = "_|WARNING:-DO-NOT-SHARE-THIS.--Sharing-this-will-allow-someone-to-log-in-as-you-and-to-steal-your-ROBUX-and-items.|_RestOfCookieGoesHere"
session = requests.Session()
session.cookies[".ROBLOSECURITY"] = cookie
def rbx_request(method, url, **kwargs):
request = session.request(method, url, **kwargs)
method = method.lower()
if (method == "post") or (method == "put") or (method == "patch") or (method == "delete"):
if "X-CSRF-TOKEN" in request.headers:
session.headers["X-CSRF-TOKEN"] = request.headers["X-CSRF-TOKEN"]
if request.status_code == 403: # Request failed, send it again
request = session.request(method, url, **kwargs)
return request
req = rbx_request("POST", "https://auth.roblox.com/")
print(req.status_code)
Now that we’ve done this, it makes it marginally easier to send requests to the API.
Final steps
At this point, you’re ready to roam free and send requests to the API yourself. I hope you found this tutorial informative, and if you have any more questions or have anything I should add, please reply to this post or send me a direct message.