On roblox, there are many ways you can set up a way for someone to donate to you. We’ve had “support me” t-shirts for over a decade now. As roblox evolved, we haven’t really gotten better ways. There’s always these one time purchases of a specific amount.
Donations work much better, and reach much more people when a person can choose the amount their donating. Where a 50 R$ shirt might attract 10 people off, a 10 R$ shirt might reach 100. These numbers are just examples and don’t have any statistics behind them other than the intuition that more people can afford to purchase something when it costs less potentially leading to more revenue in the long term.
Almost 2 years ago now, I released a system that automatically created developer products for you, kept track of them, and allowed people to donate any amount. You can find that here.
This system comes with multiple major downsides. First, it requires a vps of some sort with which to run a small node.js server. Second, it requires your roblox cookie to access the api. This is a security vulnerability, but at the time there was no alternative. Third, it could randomly go down and detract people from donating.
This new system is a single roblox script, allows for donating any amount, uses no http requests, and makes it as easy to use as DonationService:Donate(player, amount)
, which is usable on both the server and the client. If you use this from the client, player
is not necessary.
So without further ado, here’s the script, this goes in a module script.:
local MarketplaceService = game:GetService("MarketplaceService")
local RunService = game:GetService("RunService")
local ExecuteDonation = script:WaitForChild("ExecuteDonation")
local DonationService = {
Products = {}
}
local Players = {}
function DonationService:GetNeededProducts(amount)
local amountLeft = amount
local products = {}
while amountLeft > 0 do
for _, product in ipairs(DonationService.Products) do
if amountLeft >= product.Robux then
table.insert(products, {Robux=product.Robux;Id=product.Id;})
amountLeft -= product.Robux
break
end
end
end
return products
end
function DonationService:Donate(player, amount)
if typeof(player) == "number" then
amount = player
player = nil
end
if amount == nil then return end
if RunService:IsClient() then
ExecuteDonation:FireServer(amount)
else
DonationService:ExecuteDonation(player, amount)
end
end
function DonationService:ExecuteDonation(player, amount)
if amount == nil or RunService:IsClient() then return end
local neededProducts = DonationService:GetNeededProducts(amount)
for _, product in ipairs(neededProducts) do
DonationService:Buy(player, product.Id)
task.wait()
if not Players[player][3] then break end
end
Players[player] = nil
end
function DonationService:Buy(player, id)
if RunService:IsClient() then return end
MarketplaceService:PromptProductPurchase(player, id)
Players[player] = {MarketplaceService.PromptProductPurchaseFinished:Wait()}
end
if RunService:IsServer() then
--[[
IMPORTANT: IF YOU USE THIS ANYWHERE ELSE, REMOVE IT FROM HERE. YOU CAN ONLY HAVE ONE CALLBACK FUNCTION,
AND THAT SHOULD HANDLE YOUR DONATIONS AS WELL AS ANY OTHER PURCHASES
]]
MarketplaceService.ProcessReceipt = function()
return Enum.ProductPurchaseDecision.PurchaseGranted
end
ExecuteDonation.OnServerEvent:Connect(function(player, amount)
DonationService:ExecuteDonation(player, amount)
end)
end
return DonationService
This system requires a small amount configuration. First, you’ll need to create multiple developer products for the system to use to complete the donation. The only required product is one that costs 1 R$. Though I recommend setting up products for (at least) 1, 5, 10, 20, 50, 100, 500, and 1000.
Like so:
Once you make these products, you need to add them to the products table.
It is imperative that you add them in descending robux order. If you set them up any other way, this system will fail. Here’s an example of what it should look like in the end:
local DonationService = {
Products = {
{
Robux=1000;
Id=id;
},
{
Robux=500;
Id=id;
},
{
Robux=100;
Id=id;
},
{
Robux=50;
Id=id;
},
{
Robux=20;
Id=id;
},
{
Robux=10;
Id=id;
},
{
Robux=5;
Id=id;
},
{
Robux=1;
Id=id;
}
}
}
Where Id
is the id of the product that corresponds to that value.
If you set this all up correctly, that’s it. You can make any products you want to make the experience require as few steps as possible, though as stated previously, you will need a product with a value of 1 R$.
After you do this, you can make any kind of UI you want, here’s an example:
As you can see, when a player cancels one, the entire chain is stopped to make the experience as smooth as possible. You don’t need a place dedicated to donations either, you can put this in your actual game somewhere where players can tip you, almost like a built in ko-fi in your game. Basically, this script creates a literal tip jar for your game.
Important note: If you plan to use this from the client, it must be required from the server somewhere at least once. Your structure must look like this or it will fail to load:
Regardless of whether you use it from the client or server, the remote event ExecuteDonation
must be parented to the DonationService
ModuleScript.
The advantages of this script include:
- Not limited to one time purchases, like shirts, game passes, etc.
- Allows a user to donate a custom amount
- No third party requests
- Minimal configuration
- Extremely simple to use from either the server or the client
If you want to check out the place in the above video, you can do so here, I’ve also uncopylocked it so you can copy it if you so choose, just remember to set up the products to ones you make:
You can even leave a tip if you want, but don’t feel obligated to do so.
Hopefully this script can help some people out there that are looking to mimic what it does.
Another potential use case in the commission world. Your client could just load up the game, type in the value and pay you directly with no group payout 2 week wait time, etc., required at all.