Introduction
In this article, I am going to explain and teach you how to create an auto-ranking JavaScript bot for clothing groups (Based off of clothes owned in the group)
First Steps
Once you are in studio, go straight to “Game Settings” on the top of the screen, then navigate to “Security”. Here, you are going to want to Allow HTTP Requests. Once this is done, make a new script inside of ServerScriptService and name it whatever you like. For this example, I am going to name it “getCatalog”.
Creating your webserver
Once you have set up your Roblox game, you are going to want to make a webserver. This can be done with any hosting provider which allows PHP files to be hosted. I recommend using 000webhost as it is free and allows PHP hosting. Once you have created an account on 000webhost, you can navigate to the file manager, which can be found on your website list.
(Click manage website)
(Click file manager)
Once in your file manager, you want to double click on the public_html folder.
Click the new file button and call it “CatalogReceiver.php”
Understanding the Catalog API
Roblox has their own API for their catalog, in which the documentation can be found here:
There you can find all of the parameters for your URL you will be using to get your group’s catalog. For getting all of the clothing in a group’s catalog, you can use this URL:
https://catalog.roblox.com/v1/search/items/details?Category=1&CreatorType=2&CreatorTargetId=7115611&Limit=30&Cursor=
Replace the CreatorTargetId with your group’s ID.
Now that you have your link you will be using for, copy and paste this code into your PHP file on your webserver.
if (isset($_GET['cursor'])) {
echo file_get_contents('your url' . $_GET['cursor']);
} else {
echo file_get_contents("your url");
}
?>
You will notice that there is no cursor parameter for the second “file_get_contents” function. The cursor parameter allows you to navigate through the different pages of the groups catalog. For the one without the cursor parameter, delete ‘&Cursor=’ from your URL. It should look like this:
if (isset($_GET['cursor'])) {
echo file_get_contents('https://catalog.roblox.com/v1/search/items/details?Category=1&CreatorType=2&CreatorTargetId=7115611&Limit=30&Cursor=' . $_GET['cursor']);
} else {
echo file_get_contents("https://catalog.roblox.com/v1/search/items/details?Category=1&CreatorType=2&CreatorTargetId=7115611&Limit=30");
}
?>
Save and close your PHP file, right click on it, and click View. You should now see a long JSON text on your webpage, meaning you have successfully made your webserver.
Connecting To Your Webserver in Game
In your getCatalog script under ServerScriptService, start off with calling HttpService and MarketplaceService. Then, make a function and connect player added to it. Example below:
local HttpService = game:GetService("HttpService")
local MarketplaceService = game:GetService("MarketplaceService")
game.Players.PlayerAdded:Connect(function(plr)
end)
Next, you want to create your variables and a ‘while’ loop to run, so you can go through every page in your catalog.
game.Players.PlayerAdded:Connect(function(plr)
local cursorAvailable = true
local cursor = ""
local assetIds = {}
while cursorAvailable do
end
end)
Next, you want to connect to your webserver, get the JSON file it is receiving, and turn that into a table on roblox. Replace the url with the url of your PHP file, as seen below.
local url
if cursor == "" then
url = "https://**********.000webhostapp.com/CatalogReceiver.php"
else
url = "https://**********.000webhostapp.com/CatalogReceiver.php?cursor=" .. cursor
end
local response
response = HttpService:GetAsync(url)
if not response:match("creatorType") then
repeat
response = HttpService:GetAsync(url)
print("Request Failed. Trying Again in 15 Seconds")
wait(15)
until response:match("creatorType")
end
local data = HttpService:JSONDecode(response)
You will see a repeat loop in the middle of this code. This checks whether the connection to the catalog API was successful, as Roblox rate limits their API. It then retries until it successfully grabs the catalog.
Next, you want to get all of the asset ids from the table and check if a player owns them. The code for this can be seen below
for i,v in pairs(data.data) do
wait(math.random(0, 0.2))
table.insert(assetIds, #assetIds + 1, v.id)
plr:WaitForChild("PlayerGui"):WaitForChild("mainUi"):WaitForChild("scannedIds").Text = "Scanned Ids: " .. #assetIds
end
if data.nextPageCursor then
cursor = data.nextPageCursor
cursorAvailable = true
else
cursorAvailable = false
end
wait(2)
end
local totalOwned = 0
for i,v in pairs(assetIds) do
local success, playerOwnsAsset = pcall(MarketplaceService.PlayerOwnsAsset, MarketplaceService, plr, v)
if playerOwnsAsset then
totalOwned = totalOwned + 1
end
end
print("You own " .. totalOwned .. " item(s).")
Your final script should now look like this:
local HttpService = game:GetService("HttpService")
local MarketplaceService = game:GetService("MarketplaceService")
game.Players.PlayerAdded:Connect(function(plr)
local cursorAvailable = true
local cursor = ""
local assetIds = {}
while cursorAvailable do
local url
if cursor == "" then
url = "https://**********.000webhostapp.com/CatalogReceiver.php"
else
url = "https://***********.000webhostapp.com/CatalogReceiver.php?cursor=" .. cursor
end
local response
response = HttpService:GetAsync(url)
if not response:match("creatorType") then
repeat
response = HttpService:GetAsync(url)
print("Request Failed. Trying Again in 15 Seconds")
wait(15)
until response:match("creatorType")
end
local data = HttpService:JSONDecode(response)
for i,v in pairs(data.data) do
wait(math.random(0, 0.2))
table.insert(assetIds, #assetIds + 1, v.id)
end
if data.nextPageCursor then
cursor = data.nextPageCursor
cursorAvailable = true
else
cursorAvailable = false
end
wait(2)
end
local totalOwned = 0
for i,v in pairs(assetIds) do
local success, playerOwnsAsset = pcall(MarketplaceService.PlayerOwnsAsset, MarketplaceService, plr, v)
if playerOwnsAsset then
totalOwned = totalOwned + 1
end
end
print("You own " .. totalOwned .. " item(s).")
end)
Note: You can use the totalOwned variable for anything after checking.
Setting up your auto-ranking bot
This auto-ranking bot will be using noblox.js which is a library that connects to Roblox, allowing you to rank people in your group. For our bot, we will be hosting on glitch.com, which hosts for free. After making an account on glitch, head over to Glitch :・゚✧
Here, you want to click on the name in the top right and select “Remix Project”. This will clone the project and allow you to edit the files. Once you are in the remix, head over to the config.json file. Here, you need to add your Cookie and an Authentication Key.
Getting your cookie
To get your cookie, install the chrome extension “EditThisCookie”, open it on the Roblox website, go to .ROBLOSECURITY, and copy and paste the text. You then can paste that into where the cookie goes in the config.json file. MAKE SURE THAT YOU ARE ON AN ALT ACCOUNT AND HAVE A HIGH RANK IN YOUR GROUP SO YOU CAN CHANGE ROLES.
Next, you can make a random key for security reasons. Put this under “auth_key”, and make sure it is long and complex. (Not something simple such as 12345)
It should look like this
Now, check the logs under tools and see if you are logged into your account.
If it says you are logged in, you are all set! If you aren’t follow these steps again and feel free to ask for help.
Connecting your bot to roblox.
In Roblox, create a ModuleScript called “Server” under your “getCatalog” script. Inside, paste this code:
local groups = {}
local module = {}
local setmetatable = setmetatable
local error = error
local wait = wait
local httpService = game:GetService'HttpService'
local postAsync = httpService.PostAsync
local getAsync = httpService.GetAsync
local jsonEncode = httpService.JSONEncode
local jsonDecode = httpService.JSONDecode
local base, key
local function encode (tab)
return jsonEncode(httpService, tab)
end
local function decode (tab)
return jsonDecode(httpService, tab)
end
local function request (url, method, suppress, data)
local body = method(httpService, url, data)
local success, response = pcall(decode, body)
local err
if success then
err = response.error
else
err = 'Response was not valid json, full body: '..body
end
if not err and suppress then
return true, response
elseif not err then
return response
elseif suppress then
return false, err
else
error(err)
end
end
local http = {
post = function (path, data, suppress)
if not data then
data = {}
end
data.key = key
return request(base..path, postAsync, suppress, encode(data))
end,
get = function (path, suppress)
return request(base..path, getAsync, suppress)
end
}
function groups.promote (group, userId)
return http.post('/promote/'..group..'/'..userId)
end
function groups.demote (group, userId)
return http.post('/demote/'..group..'/'..userId)
end
function groups.setRank (group, userId, rank)
return http.post('/setRank/'..group..'/'..userId..'/'..rank)
end
function groups.shout (group, message)
return http.post('/shout/'..group, {message = message})
end
function groups.post (group, message)
return http.post('/post/'..group, {message = message})
end
function groups.handleJoinRequest (group, username, accept)
local acceptString = accept and 'true' or 'false'
return http.post('/handleJoinRequest/'..group..'/'..username..'/'..acceptString)
end
function groups.getPlayers (group, rank, limit, online)
local job = http.post('/getPlayers/make/'..group..(rank and '/'..rank or '')..'?limit='..(limit and limit or '-2')..'&online='..(online and 'true' or 'false')).data.uid
local complete, response = false
repeat
wait(0.5)
local success
success, response = http.get('/getPlayers/retrieve/'..job, true)
if not success and response:match('$Response was not valid json') then
error(response)
elseif success then
complete = response.data.complete
end
until complete
return response
end
function module.message (userId, subject, message)
return http.post('/message/'..userId, {subject = subject, body = message})
end
function module.getBlurb (userId)
return http.get('/getBlurb/'..userId)
end
return function (domain, newKey, group)
local isString = (type(domain) == 'string')
if (not domain) or (not isString) or (isString and #domain <= 0) then
error('Url is required and must be a string greater than length 0')
end
isString = (type(newKey) == 'string')
if (not newKey) or (not isString) or (isString and #newKey <= 0) then
error('Key is required and must be a string greater than length 0')
end
base = 'http://'..domain
key = newKey
if group then
local isNumber = (type(group) == 'number')
if (not isNumber) or (group <= 0) then
error('If group is provided it must be a number greater than 0')
end
for name, func in next, groups do
module[name] = function (...)
return func(group, ...)
end
end
return module
end
for name, func in next, groups do
module[name] = func
end
return module
end
You then want to create a ModuleScript called “Configs” under the “getCatalog” script as well. Inside, paste this code and change it to your config.
return {
-- NOTE: The final '/' in the URL is very important!
["BaseUrl"] = ""; -- The base URL of your deployed server. Example: http://test-app.glitch.me/
["AUTH_KEY"] = ""; -- Secret Key defined as 'auth_key' in the config.json file of your server
}
Your explorer should look like this:
Once done creating your new scripts, go back into your getCatalog script. At the bottom of your playerAdded function, add these variables.
local Server = require(script.Server)
local domain = "https://tin-chartreuse-motorcycle.glitch.me/"
local key = ""
local GroupId = *Your group id*
Change the key to your authentication key, and replace the domain with your live app url from glitch. You can get this by clicking share and then copying the “live site” link on glitch. Then, change the GroupId variable to your group id.
Under these variables, you can make your conditional statements to decide which rank you want to rank people. These format can be found here:
if totalOwned > 5 and totalOwned < 25 then
local roleNumber = ""
Server.SetRank(GroupId, plr.UserId, roleNumber)
end
Replace roleNumber with the role you want to promote your group member to. This should send a request to your noblox server and rank the player.
Conclusions
Thats all for this project, if you have any questions or concerns feel free to ask below. If I messed up, let me know! I’d be happy to fix it.