How to Create a Rank Management System using Glitch

Introduction

Hey there! I am CAP7A1N, or Cap for short.

I have created this tutorial to show you how to create a rank management center with all open source/free resources.

Why?

There are far too many rank management ‘services’ out there on ROBLOX.

Most of these services are just selling you a slightly modified (if modified at all) version of someone else’s open source API, along with some UI’s. You shouldn’t have to pay for something open source.

Please note that I said ‘most’, there are some ranking services that are actually real businesses trying to help you. These tend to be the ones that host everything for you.

You most likely have seen this article before by TechSpectrum.

While this has a lot of useful information, the tutorial itself for in game promotions using Heroku is very confusing for anyone without detailed knowledge in JavaScript and with web hosting.

In this tutorial, I will teach you how to create an in game rank system using Glitch . com, a free hosting site, using an open source API called noblox.js. Documentation can be found here:

Shout out to @H_mzah for the assistance in updating this tutorial to the updated version.

No prior knowledge is needed whatsoever!
So lets get started!


Part 1: Glitch Hosting

First, you must create an account on Glitch.
Go to Glitch . com and click sign up.


Like most modern sites, (excluding ROBLOX,) you can sign up with multiple other accounts that you most likely have already (Google, Facebook) or with email.

Once signed in, go to: Glitch . com/edit/#!/remix/rank-api-code
This will clone a template set up with noblox.js for you. (Alternatively, you can create a ‘hello-express’ site and add each file in yourself.)
Once loading is complete, your page should look like the following:


(This site is copied directly from the documentation so it has Heroku as the hosting tutorial in README.md, please ignore this!)

Your site name is in the top left of the screen. In the picture above, the site name is ‘this-is-the-site-name’. The link for your site will be the name followed by ‘.glitch.me’. This site would be ‘this-is-the-site-name.glitch. me’ (Without the space before me.)

Click on the site name, and a drop down will appear. Click on the box just left of the lock to make your project private.
image

The only file you will need to ever edit is config.json’, so open that file by clicking on it.
The inside of the file should look like this:


The three components to this file are as follows:

  1. Cookie - This is the account identifier for your bot account, and the API uses this to log in and rank.
  2. Key - This is the sites security. I suggest using a trusted random character generator (or spamming on your keyboard) but do not make this something easy to guess!
  3. Max Rank - This is the maximum rank that your site can rank. Meaning if the maximumRank = 50 and someone tries to rank to 100 it will return an error.

Some of this is briefly explained in ‘README.md’.

Why does max rank exist?

Most groups have developers, who have access to the game. If your bot account is ranked higher than the developer, then the developer could make a simple function to promote themselves. (Since they have access to the code in ROBLOX Studio.) This variable prevents them from doing that as they won’t have access to the site.

Before we continue, you should create a key. As said before, this should be random characters and not a basic string. For the purpose of this tutorial, I will use ‘THISWOULDBEYOURRANDOMKEYTHATYOUCREATEDEARLIERINTHETUTORIAL’, although for a real system this would fall right into the category of being a basic string. I suggest using a trusted random character generator.

Insert your key inside the quotations on the right of “auth_key”, like the example below.
image

Want increased security? (SUGGESTED)

Check out this ‘mini-tutorial’ from the reply’s below.

Next we are going to set up the code inside ROBLOX Studio, and will come back to this later.


Part 2: Lua

Open ROBLOX Studio to the desired game for this ranking system.

Go into game settings, and make sure HTTPS requests are enabled or else this will not work.

In ServerScriptService, insert a Script. Name this script ‘Main’.

Open this script, and delete its contents so that is blank.

Under ‘Main’, create 2 ModuleScripts and delete any code inside them.
Name one ‘Configs’ and the other ‘Server’.

Inside Configs, paste the following.

'Configs' Code
return {
	-- NOTE: The final '/' in the URL is very important!
	["BaseUrl"] = "http://test-app.glitch.me/"; -- The base URL of your deployed server. Example: http://test-app.glitch.me/ 
	["AUTH_KEY"] = "SECRET_REQUEST_AUTH_KEY"; -- Secret Key defined as 'auth_key' in the config.json file of your server
}

In this code, change the value of BaseUrl to be your site’s name. In this example, the site name would be ‘https://this-is-the-site-name.glitch .me/’. (Without the space before .me/.)

Next, inside Server paste the following.

'Server' Code

local Server = {}

local HttpService = game:GetService("HttpService")

local Configs = require(script.Parent.Configs)
 
local function Request(Function, RequestBody)
	
	--Before sending the request, add our auth_key to the body
	RequestBody["auth_key"] = Configs.AUTH_KEY
	
	local response = HttpService:RequestAsync(
		{
			-- The website to send the request to. Function is the extended part of the URL for specific functions.
			-- In this case, Function = 'GroupShout'
			-- Example: 
			--	"Configs.BaseUrl..Function" would be equal to: http://test-app.glitch.me/GroupShout
					
			Url = Configs.BaseUrl..Function, 

			-- The request method (all of ours will be POST)
			Method = "POST",

			-- We are sending JSON data in the body
			Headers = {
				["Content-Type"] = "application/json"
			},
			-- The body of the request containing the parameters for the request
			Body = HttpService:JSONEncode(RequestBody)
		}
	)
 
	if response.Success then
		print("Status code:", response.StatusCode, response.Body)
		print("Response body:\n", response.Body)
		
		return response.Body
	else
		print("The request failed:", response.StatusCode, response.Body)
		return response.Body
	end
end

Server.Promote = function(GroupId, UserId)
	assert(typeof(GroupId) == "number", "Error: GroupId must be an integer") -- Throw error if GroupId is not an integer
	assert(typeof(UserId) == "number", "Error: UserId must be an integer") -- Throw error if UserId is not an integer

	local Body = {
		Group = GroupId;
		Target = UserId;
	}
	
	 -- pcall the function 'Request', with arguments 'Promote' and Body
	local Success, Result = pcall(function()
	    return Request('Promote', Body)
	end)
	
	print(Result)
end

Server.Demote = function(GroupId, UserId)
	assert(typeof(GroupId) == "number", "Error: GroupId must be an integer") -- Throw error if GroupId is not an integer
	assert(typeof(UserId) == "number", "Error: UserId must be an integer") -- Throw error if UserId is not an integer
	
	local Body = {
		Group = GroupId;
		Target = UserId;
	}
	
	local Success, Result = pcall(function()
	    return Request('Demote', Body)
	end)
	
	print(Result)
end

Server.SetRank = function(GroupId, UserId, RankId)
	assert(typeof(GroupId) == "number", "Error: GroupId must be an integer") -- Throw error if GroupId is not an integer
	assert(typeof(UserId) == "number", "Error: UserId must be an integer") -- Throw error if UserId is not an integer
	assert(typeof(RankId) == "number", "Error: RankId must be an integer") -- Throw error if RankId is not an integer

	local Body = {
		Group = GroupId;
		Target = UserId;
		Rank = RankId;
	}
	
	local Success, Result = pcall(function()
	    return Request('SetRank', Body)
	end)
	
	print(Result)
end

Server.HandleJoinRequest = function(GroupId, PlayerUsername, Boolean)
	assert(typeof(GroupId) == "number", "Error: GroupId must be an integer") -- Throw error if GroupId is not an integer
	assert(typeof(PlayerUsername) == "string", "Error: PlayerUsername must be a string") -- Throw error if PlayerUsername is not a string
	assert(typeof(Boolean) == "boolean", "Error: Boolean must be a boolean value") -- Throw error if Boolean is not a boolean value

	local Body = {
		Group = GroupId;
		Username = PlayerUsername;
		Accept = Boolean; -- true or false
	}
	
	local Success, Result = pcall(function()
	    return Request('HandleJoinRequest', Body)
	end)
	
	print(Result)
end

Server.GroupShout = function(GroupId, ShoutMessage)
	assert(typeof(GroupId) == "number", "Error: GroupId must be an integer") -- Throw error if GroupId is not an integer
	assert(typeof(ShoutMessage) == "string", "Error: ShoutMessage must be a string") -- Throw error if ShoutMessage is not a string

	local Body = {
		Group = GroupId;
		Message = ShoutMessage;
	}
	
	local Success, Result = pcall(function()
	    return Request('GroupShout', Body)
	end)
	
	print(Result)
end

return Server

Lastly for code, inside Main paste the following.

'Main' Code
local HttpService = game:GetService("HttpService")
local Server = require(script.Server)

Here is how your scripts should look:
image

Lets move onto the next part.


Part 3: The Cookie

Almost there!

ROBLOX currently uses a Security Cookie to log in (via API or non-human). This cookie allows the rank API to log in, and change a users rank.

Since you can log in with this, please use a bot account, or an account with NOTHING of value.

Create a bot account and join the group that this system will be used in. Make sure that the bot account
has ranking permissions.

Why?

As I said before, the cookie can be used to log in to an account on ROBLOX.
Just how this system uses the ranking API, someone can use the cookie for any other API there is on ROBLOX. Anything on this page can be used with a cookie.

By using a bot account, you won’t be affected if your site is somehow hacked. (Except for the extremely minor inconvenience that you will need to create a new account.

With this being said, the cookie expires every so often, and ROBLOX generators a new one. You will either need to set up an automated cookie retrieval system, or update the cookie manually.

How do you know if your cookie has expired?

Please note that this will only work after you have set up your site completely.

Visit your glitch site, and check if the following appears:
{“error”:“Server configuration error: You are not logged in.”}
If this error appears, then your cookie has expired. To update your cookie, repeat Part 3 and paste your cookie in the correct place in your site.

To get the cookie, first log into ROBLOX with your bot account.

For the next step, you will need to be on a browser that supports Inspect Element. (Most do, although in some you will need to enable it in settings.) Default browsers like Chrome, Safari, and Edge all have this feature.

Open Inspect Element by using CTRL + SHIFT + I (CTRL is CMD on Mac) or by right clicking in a blank area and clicking ‘Inspect’ or ‘Inspect Element’ (each browser is different).
Pic4

A section of your page should now be taken up by this new window:

Locate the top bar, which consists of ‘Elements’, ‘Console’, ‘Sources’, etc., and find the ‘Application’ tab.
(I have a large screen so it is visible but you may need to click the 2 arrows on the right of the right most tab for a drop down to appear with ‘Application’ in it.

Your application screen look something like this:

As long as you see the word ‘Cookies’ under ‘Cache’, you are on the right page.

Click on the ‘https://www.roblox.com’ tab (you may need to click the drop down arrow left of ‘Cookies’) and your next screen should have something roughly like this on it:
Pic7

If it is not already, open your Glitch site to ‘settings.json’.

The cookie is the Value of ‘.ROBLOSECUTIRY’, located 3rd on my screen although it may be different for you. Copy this value.
Pic8

In your site, clear anything in the quotations after cookie and paste the copied cookie.

Your site should look like this, but with your own values:

Once that is set up, visit your site in your browser. (your site name + .glitch.me)

Your site should look like the following:
image

Good job! You’ve created your own ranking system.
But wait…
How do you use this to rank players? Continue reading below for examples.


Part 4: Example Usage

This part will contain scripts with example usage, and requires basic knowledge in ROBLOX Studio.

Remote Event Usage
The most common usage of rank systems is through a UI, whether a quiz or management center.
First create a RemoteEvent inside ReplicatedStorage, I will name mine RankPlayer for this example.
Put this inside a LocalScript inside a UI button:

script.Parent.MouseButton1Click:Connect(function()
--For a gamepass checker, use the following:
if game:GetService("MarketPlaceService"):UserOwnsGamePassAsync(00000, game.Players.LocalPlayer.UserId) then
    local rankid = 0 --This is the rank that the user will be promoted/demoted to.
    game.ReplicatedStorage.RankPlayer:FireServer(game.Players.LocalPlayer, rankid)
end

--For just a button that sets a rank, use the following:
local rankid = 0 --This is the rank that the user will be promoted/demoted to.
game.ReplicatedStorage.RankPlayer:FireServer(game.Players.LocalPlayer, rankid)

end)

This script 1. checks if a user has a gamepass and fires a ranking function if they do, and 2. fires a ranking function a user when they click the button.

Put this inside ‘Main’ in ServerScriptService:

game.ReplicatedStorage.RankPlayer.OnServerEvent:Connect(function(player, rank)
    local groupId = 0000000
    Server.Promote(groupId, player.UserId)
end)

This script ranks a user to the desired rank when an event is fired.

Here are all the functions from this API.
This is a direct quote from the documentation:

-- EXAMPLE USAGE

--[[

	Server.Promote(GroupIdHere, PlayerUserIdHere)

	Server.Demote(GroupIdHere, PlayerUserIdHere)

	Server.SetRank(GroupIdHere, PlayerUserIdHere, RankIdHere)


	Server.HandleJoinRequest(GroupIdHere, "PlayerUsernameHere", true) -- Accept the request

	Server.HandleJoinRequest(GroupIdHere, "PlayerUsernameHere", false) -- Decline the request


	Server.GroupShout(GroupIdHere, "MessageToShoutHere")

	Server.SetRank(GroupIdHere, PlayerUserIdHere, RankIdHere)

]]--

Bonus

Since not everyone is, or can afford a UI designer, here are 2 UI’s I made. (You still have to insert scripts from Parts 2 and 4.)


This Rank Management Center.rbxm (12.4 KB) has a lot of ranks, and you can set the name and price for each. The ‘BUY’ button has 2 functions. If a user owns a gamepass then it will rank them, if not it will prompt the gamepass to be purchased.

Quick Note About Rank Selling

Selling ranks on ROBLOX is a grey area in the ToS. This means depending on the circumstances you could get punished for it.

I have provided this UI as a learning material, while you may use it how ever you like I personally do not support rank selling in any way, shape, or form.


This Quiz Center.rbxm (18.7 KB) has 10 questions and can rank a user depending on how many they get correct.

I have provided both these UI’s as learning materials. You are welcome to use them, although they are intended to show how this ranking system can be used. No credit is needed, but you cannot claim that you created them.


Conclusion

I hope this helps you create your own rank management system.

If you have any questions, comments, or suggestions, please don’t hesitate to reply below or message me!

Thanks for reading! :smiley:

-Cap

EDIT (3/22/20): While I am more than happy to help with any errors or clarify anything that may be confusing, please do not contact me and ask me to ‘set up’ the whole tutorial.

62 Likes

I honestly do not recommend Glitch for the sole fact that their file protection there is crap. I have been using Glitch for the longest time and was happy with it until I accidentally name dropped my project and people started remixing them.

7 Likes

Sorry to hear about that.

While I dont know much about security, I do know that you can make Glitch projects private. This makes it so that anyone other than you (or people you invite) will get a 404 page if they try to view your project.

5 Likes

Yea the project was private. Glitch apparently glitched when it happened (oh the irony).

7 Likes

Another thing to be added to this is: if something happens and your project gets opened to public/the name gets leaked then whatever account you configured this with will most likely get hijacked. The cookie is stored in a settings.json file, which on Glitch can be viewed by anyone that is able to view your project files. The cookie should be stored in .env which Glitch does not allow everyone to view.

If you follow this tutorial, I highly recommend you make the project private and move the cookie into .env otherwise whatever Roblox account you used will most likely get hijacked if Glitch accidentally makes the project public or you leak the glitch project name.

I also recommend OP updates the topic with at the very least steps to make the Glitch project private, because by default it is public and since your .json file is a public file for anyone to view on a public project, your cookie will be wide open to be taken by anyone. Moving the cookie to .env would also be a good change as an extra step incase your private project somehow becomes public.

Other than the security concerns, I’m glad this tutorial was made. I’ve seen probably 4 different rank centers which require payment and more often than not, they are all practically the same thing, with varying quality.

11 Likes

As @fireboltofdeath said, you should place the user_cookie in a .env file called :old_key:.env. For some of you who don’t understand js particually well may find this difficult but here’s a short tutorial to explain it and thank you @CAP7A1N for making the initial tutorial, very helpful and insightful.

First we’re going to locate a file called :old_key:.env as shown below:
image
Then we’re going to add your UserCookie inside this env file, while doing so remove it from your json file.

Screenshots


After which we’re going to open up the console located under Tools :arrow_forward: Logs :arrow_forward: Console: In which we’re going to import dotenv by writing: npm install dotenv. Well done, you have just imported dotenv, give yourself or me, as I actually did the work, a pat on the back. Much obliged.

Okay next we’re going to need to set that little key into process so go ahead and type require('dotenv').config({ path: './.env' }). Done? Nice one.

Then scroll down to the login function, here type:
await roblox.cookieLogin(process.env.USER_COOKIE);
:arrow_backward: You need to edit the existing line that was here before to look like this.
image
Well done my man, you did it.
Keep in mind that if you ever change the name of the project, it will automatically unlock it, this could have been your issue @Krunnie but this measure acts as a failsafe if it is ever made public, this should protect it.
Shoutout to @fireboltofdeath who made me aware of a security vunerability which rendered this useless, the post was updated to fix this mistake following his advice. EDIT: Pictures updated alongside fix.

4 Likes

Do not use the name “UserCookie.env” or make your own .env file at all.
Making your own .env file is no different than a .json file. Glitch still shows them publicly.
Glitch provides you with a .env file that is kept private, it’s name is “:old_key:.env” (key emoji) and will not be shown publicly.

You should use that file otherwise there’s no point making the change. Also, Glitch will automatically inject the variables into process.env for you if you use the file they provided.
image

4 Likes

Thank you, post has been updated but from testing, it doesn’t appear that Glitch automatically injects the variable within process.env so I’ve found that I need to keep the: require('dotenv').config({ path: './.env' })
And apologies on my end, not used to glitch.

1 Like

I never changed the project’s name. All of my projects were locked and something happened that made them fully unlocked for a week while it showed that they were locked. Had months of my work plagiarized by people who took advantage of the fact that Glitch didn’t do anything about it.

3 Likes

Ah what a shame, sorry to hear. Hopefully this trick will help you in the future when it comes to keep config data safe, although, ofcourse it doesn’t protect all your code. Hopefully that was a one off occurance.

It does. Here is a quote from their help page:

  • Assign your secrets on its own line in .env starting with a variable name (for example, SECRET ) followed by an equal sign = then followed by the value of your secret. *Note: This is a shell file, so you cannot have spaces around the = .
  • You can then reference your secret with process.env.[secret variable name] (in this example, process.env.SECRET ) in your server-side code.
1 Like

How curious, in testing I get this error when I hash out:
image
It reports it as undefined when referenced.
A console.log(process.env);also doesn’t include USER_COOKIE.

Yea… I just moved to paid cloud services.

NOTICE

There have been reports of errors happening while using this API. I have contacted the creator and will keep this post updated on the status.

FIX
To fix this, please re-create your glitch site with the updated link.

Shoutout to @jeditcdisback for helping to fix this issue.

Note: I have received word that documentation has been updated, and this issue should not occur anymore.

2 Likes

glitch = bad for deployment

Glitch is designed for development and not for deploying production grade apps, especially ones you want to keep under :lock: and :key:

2 Likes

You’re not wrong just look at what happened to Krunnie, what would you recommend as a free or affordable alternative to glitch?
(before glitch I used repl, this is infact the first time I have used glitch and it seems simple but realtively easy and smooth to use for basic stuff like this.)

As glitch is made for web hosting it falls asleep after 5mins since last call so to keep it alive you will want to add a new script, call it what you want, I called it KeepAlive.js; Within this type:

const http = require('http');
const express = require('express');
const app = express();
app.get("/", (request, response) => {
  console.log(Date.now() + " Ping Received");
  response.sendStatus(200);
});
app.listen(process.env.PORT);
setInterval(() => {
  http.get(`http://${process.env.PROJECT_DOMAIN}.glitch.me/`);
}, 280000);

Script via https://anidiots.guide/

2 Likes

Thanks for this!

Alternatively, you could use a site like UpTime Robot to visit your site every so often, although this will make keeping Glitch site’s awake way easier.

I added this into the site template, since it will definitely help.

2 Likes

Nothing in the world is free. I’d personally suggest DigitalOcean—although it can be more costly.

Generally, just look for what you specifically need in a cloud service provider.

2 Likes

I recommend Firebase. You won’t be able to do this on the free plan because you can’t send HTTP requests to non-Google services with Firebase Functions. Your best bet would be to go onto the Pay as you go plan. This plan is 100% free as long as you stay within the free tier usage and you can send HTTP requests wherever you need.

To get started with Firebase Functions check here!

Firebase is backed by Google infrastructure and security. It scales 100% automatically and is designed for production use.

Hope this helps!

1 Like