How To Make A Membership System

Hello everyone! In this tutorial, I will show you guys how to make a Membership System. This means a player can purchase a membership with robux and the membership only lasts for a specific amount of time (1 Month, 1 Year, etc.).

Step 1: GUI

First off, use this GUI and put it in StarterGui. This is the default layout and you can change it however you like. Just make sure not to change scripts unless you are sure of what you’re doing! Also try not to change names or it could get confusing in the future steps.

Step 2: Create Products

Go to your game’s configure page and go to Developer Products. When you are there, create a new product called whatever you like, determine the price, and add an image for it (Image is required). When you created it, it should look something like this:

Step 3: Configuring Scripts

If you go into the GUI from step 1 and go into the TextButton called “Buy”, there is a LocalScript. Open that script so that we can configure it.
MembershipGuiEx1
Once you open the script, you will see a variable called ProductId. Change that to the ID of the product you created in the last step. Code Example:

local MarketPlaceService = game:GetService("MarketplaceService")
local ProductId = 1067787625 -- Change this to the Product Id

script.Parent.MouseButton1Click:Connect(function()
	MarketPlaceService:PromptProductPurchase(game.Players.LocalPlayer,ProductId)
end)

Step 4: The main script

Create a Script in ServerScriptService and call it whatever you like. Create the following variables in the script:

local DataStoreService = game:GetService("DataStoreService")
local MembershipData = DataStoreService:GetDataStore("MembershipData")
local MarketPlaceService = game:GetService("MarketplaceService")
local ProductId = 1067787625 -- Change to id
local MembershipDuration = 	2628000 -- The duration of the membership (In seconds). It is default set to 1 month.

After that, we will create a PlayerJoined event to load the Membership data. The Membership data is the os.time() value that the Membership ends. Add this code below the code we made above:

game.Players.PlayerAdded:Connect(function(Player)
	-- Creates a folder in the Player containing the Player's Membership data
	local Folder = Instance.new("Folder",Player)
	Folder.Name = "Membership"
	local IsMember = Instance.new("BoolValue",Folder)
	IsMember.Name = "IsMember"
	local MembershipTime = Instance.new("IntValue",Folder)
	MembershipTime.Name = "MembershipTime"
	
	-- Gets membership data. Data will be the os.time() the membership expires
	local MembershipInfo
	local Success,Error = pcall(function()
		MembershipInfo = MembershipData:GetAsync(Player.UserId.."-MembershipInfo")
	end)
	
	-- Loads data
	if not MembershipInfo then MembershipInfo = 0 end -- Sets to 0 if no data given
	MembershipTime.Value = MembershipInfo
	if os.time() <= MembershipInfo then
		IsMember.Value = true
	else
		IsMember.Value = false
	end
	while true do
		wait(30)
		if os.time() <= MembershipInfo then
			IsMember.Value = true
		else
			IsMember.Value = false
		end
	end
end)

Now that the data loads when the player joins the game, we have to make it so when the player purchases the membership, it saves the time until the membership ends. To make this work, we have to add this code below:

MarketPlaceService.ProcessReceipt = function(PurchaseInfo)
	print("Purchase Processing...")
	local Player = game:GetService("Players"):GetPlayerByUserId(PurchaseInfo.PlayerId)
	
	if PurchaseInfo.ProductId == ProductId then
		-- Get info
		local MembershipTime = Player.Membership.MembershipTime.Value
		-- Save info
		local UntilTime
		-- Checks if user already purchased membership in case
		if os.time() <= MembershipTime then
			UntilTime = MembershipTime + MembershipDuration
		else
			UntilTime = os.time() + MembershipDuration
		end
		local Success,Error = pcall(function()
			MembershipData:SetAsync(Player.UserId.."-MembershipInfo",UntilTime)
		end)
		
		-- Checks if successful
		if Success then
			Player.Membership.IsMember.Value = true
			Player.Membership.MembershipTime.Value = UntilTime
			print("Purchase Granted!")
			return Enum.ProductPurchaseDecision.PurchaseGranted
		else
			-- If there is an error, the purchase is not processed yet and it prints the error.
			print("Error while purchasing membership: "..Error)
			return Enum.ProductPurchaseDecision.NotProcessedYet
		end
	end
end

We are now pretty much done! Here is what your script should look like all together:

local DataStoreService = game:GetService("DataStoreService")
local MembershipData = DataStoreService:GetDataStore("MembershipData")
local MarketPlaceService = game:GetService("MarketplaceService")
local ProductId = 1067787625 -- Change to id
local MembershipDuration = 	2628000 -- The duration of the membership (In seconds). It is default set to 1 month.

-- Player Membership Info
game.Players.PlayerAdded:Connect(function(Player)
	-- Creates a folder in the Player containing the Player's Membership data
	local Folder = Instance.new("Folder",Player)
	Folder.Name = "Membership"
	local IsMember = Instance.new("BoolValue",Folder)
	IsMember.Name = "IsMember"
	local MembershipTime = Instance.new("IntValue",Folder)
	MembershipTime.Name = "MembershipTime"
	
	-- Gets membership data. Data will be the os.time() the membership expires
	local MembershipInfo
	local Success,Error = pcall(function()
		MembershipInfo = MembershipData:GetAsync(Player.UserId.."-MembershipInfo")
	end)
	
	-- Loads data
	if not MembershipInfo then MembershipInfo = 0 end -- Sets to 0 if no data given
	MembershipTime.Value = MembershipInfo
	if os.time() <= MembershipInfo then
		IsMember.Value = true
	else
		IsMember.Value = false
	end
	while true do
		wait(30)
		if os.time() <= MembershipInfo then
			IsMember.Value = true
		else
			IsMember.Value = false
		end
	end
end)

-- Purchase Handler
MarketPlaceService.ProcessReceipt = function(PurchaseInfo)
	print("Purchase Processing...")
	local Player = game:GetService("Players"):GetPlayerByUserId(PurchaseInfo.PlayerId)
	
	if PurchaseInfo.ProductId == ProductId then
		-- Get info
		local MembershipTime = Player.Membership.MembershipTime.Value
		-- Save info
		local UntilTime
		-- Checks if user already purchased membership in case
		if os.time() <= MembershipTime then
			UntilTime = MembershipTime + MembershipDuration
		else
			UntilTime = os.time() + MembershipDuration
		end
		local Success,Error = pcall(function()
			MembershipData:SetAsync(Player.UserId.."-MembershipInfo",UntilTime)
		end)
		
		-- Checks if successful
		if Success then
			Player.Membership.IsMember.Value = true
			Player.Membership.MembershipTime.Value = UntilTime
			print("Purchase Granted!")
			return Enum.ProductPurchaseDecision.PurchaseGranted
		else
			-- If there is an error, the purchase is not processed yet and it prints the error.
			print("Error while purchasing membership: "..Error)
			return Enum.ProductPurchaseDecision.NotProcessedYet
		end
	end
end

Also, if your script is not working in studio, make sure you have API services enabled (Can be found in game settings)


Alright, that is basically it for this tutorial, I hope it helped you out! If it did, please make sure to reply on how useful this was. If there is a problem, please reply with your problem and I will try to help you out as soon as possible! Also please leave a like if you enjoy :smile:

Was this tutorial useful?

  • Yes
  • In the future maybe
  • No

0 voters

Also, please comment any tutorial ideas!

208 Likes

This tutorial was very simple, I may use it in the future thank you. BuilderDolphin

3 Likes

No problem, PoweringCCards. Thank you for the feedback.

1 Like

This is pretty epic! Can you please show me how to add a custom chat tag for users with a membership and how to award a badge in the game for those users?

Btw, you can provide a template for the GUIs so we won’t have to make them ourselves.

Anyways, I am pretty sure this will help me with my game!

4 Likes

Ah, so this is using Timestamps and DataStores?

2 Likes

Basically, it is using the os.time() method to get the current time in seconds and it is saving the time it ends to a DataStore so yes.

2 Likes

I might make a ModuleScript using this method for everyone to use. Of course, I will link your post.

I love this! Quite honestly I am surprised the idea isn’t utilized more. Thanks for the material though might help out on a future project!

Have a good one.
Dev

3 Likes

I am not very familiar with chat tags, but I know you can find a tutorial on those somewhere and just have an if statement seeing if the player has membership and if they do, it gives the tag. I also hope this will be helpful!

1 Like

I think there’s a flaw in this that needs considering.

ProcessReceipt doesn’t always fire immediately. If there’s a delay, the user could easily purchase multiple of the product, however your function always resets it back to os.time() + membership duration. This is an issue.

One way around it could be to set a value in game to let you know you’re currently waiting to hear back from a purchase, and ensure you don’t prompt it again in the meantime.

Another method could be to allow it, but to simply add duration to the existing expiry date if there is one. That way if they purchase the month twice, they get two months. This also opens it up to allow them to purchase the next month before the current month has run out, to avoid any downtime where their membership has expired.

I don’t actually see anything at all that prevents the player opening the purchase prompt again even if your ProcessReceipt function acted immediately, so if I purchased it again 10 days in, I’d lose the remaining 20 days as it gets reset to now + 1 month.

8 Likes

This sounds good I will give it a try thanks.

This tutorial sounds great! I will definitely have to try it in a future game, and maybe see what else I can do with it. Nice job!

Seems nice! However a few things I would like to point out:

This is a huge waste of resources, every ~30 seconds you are checking if the membership is over. There is almost certainly a better way of doing this but I am not sure what it is trying to do. Polling in general is bad when you have event-based programming as a choice.

This can be shortened to IsMember.Value = os.time() <= MembershipInfo


Additionally, while these aren’t released yet nor documented:

it looks like these will fulfill the use case for stuff like monthly memberships. Every other issue seems to be pointed out in replies above but that is my feedback.

2 Likes

Thank you for the feedback, I will try to fix this asap!

2 Likes

I was able to simply fix this with an if statement to check if the player already has a membership. I thank you for pointing this out and if I have any other mistakes, please point them out :smile:

4 Likes

Thank you SO much for this. Will 100% be using this.

2 Likes

No problem :wink:! I hope this will be useful!

1 Like

Thanks for pointing that out! I fixed the problem on the top and yes, I have heard of Subscriptions and probably when they come out, I will update this tutorial or just make a new one. But other than that, thanks for the feedback and please point out any errors you see if you ever see one :smile:

1 Like

Thank you for messaging me, I will get with you shortly.

1 Like

I added a poll to see how useful this really is, please feel free to put and it’s ok if it’s not useful :slight_smile:

2 Likes