Accessing the Roblox API - the comprehensive tutorial

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

:memo: 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.

:warning: You can’t access the Roblox API from within a Roblox game without a proxy.

:globe_with_meridians: 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 :page_facing_up: Docs :closed_book: Tutorial Python 3 Yes Yes @jmkd3v @iranathan
pyblox Python 3 Partial No @Sanjay-B
bloxy :page_facing_up: Docs Node.JS Yes Yes @Visualizememe
noblox.js :page_facing_up: 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:

image

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.

:warning: Please make sure that you do not share this token! Anyone with the token will gain full access to your account.

:warning: 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.

:memo: 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.

131 Likes

This is awesome!!! I’m sure this’ll help people who’ve had issues with user authentication. Great job :+1:

2 Likes

I’m pretty new to this, so I have a question. What is the usefulness of accessing the Roblox API? Honestly, what does that mean?

2 Likes

It helps with scripting as you might not know what a function is or what it does but accessing the API allows you to do just that.

1 Like

The Roblox Web API is the web interface for communicating with Roblox - every single thing you do on the website communicates with the API in some way (sending a message, sending a friend request, joining a game, etc)

That’s the in-game API - I’m talking about the web API.

4 Likes

Very nice! As someone who does not know the Roblox Web API well, this will definitely be helpful.

One feedback I would like to give is possibly changing the title from Roblox API to Roblox Web API, as some might confuse it with the in studio, Roblox Instance API.

1 Like

The title originally stated “Roblox Web API”, but it was changed to help allow people to find the tutorial with “Roblox API” as a search term.

1 Like

Is it possible to use the FunCaptcha Token via the API?

Hello everyone. I just want to bump this to let you all know that we have an updated version of the tutorial up on our Roblox API wiki. I will still keep maintaining this post, given it’s now been linked a few times, but the wiki has more comprehensive code examples which you might want.

3 Likes

How to you make a ranking bot with API?, I still kinda don’t understand this. I ain’t a computer genius or technician genius.

1 Like

Everyone, it’s maybe because roblox updated their api response, the response of https://auth.roblox.com/ 's “X-CSRF-Token” must be lower case now. How I know this is I logged the response to the console and realized that the key of the token inside the response is “x-csrf-token”.

Proof:

So instead of using upper case, you have to change to lower case.

# Change:
if "X-CSRF-Token" in req.headers:
    session.headers["X-CSRF-Token"] = req.headers["X-CSRF-Token"] 
# To:
if "x-csrf-token" in req.headers:
    session.headers["x-csrf-token"] = req.headers["x-csrf-token"]

HTTP headers are not case-sensitive. Your request library should treat “x-csrf-token” and “X-CSRF-Token” the same.

1 Like

I may be a little dumbdumb, but I don’t exactly get the point of doing two API requests. If I will have to provide an X-CSRF-Token with my request, but the response gives me one if I don’t, that doesn’t make too much sense to me. I’m not too experienced in programming.

What are you referring to? Also, how come people haven’t responded to many questions posted in this thread, such as the funcaptcha token and ranking? I’d like to know the answers to them too.

basically
theres this thing called cross server request forgery
i wont get into detail but website can sorta change what you do on a request to what they want
thats bad
so roblox makes you submit a one time code thing to prove its actually you doing it and not anyone else
cause of this, you have to submit the api request twice in a session, so you can get that one session code and use it to authorize your requests
I probably got a lot wrong, but i think thats a good general idea of it

1 Like

How can I retrieve a users role in a group?

send a request to https://groups.roblox.com/v2/users/{userId}/groups/roles with parameters userId, includeLocked and includeNotificationPreferences

1 Like

Copy that, thanks. I wish there was a way to retrieve the users rank in one specific group instead of having to scroll through the users full groups until I find the said group ID. but oh well :sob: