Scripting Helpers is winding down operations and is now read-only. More info→
← Blog Home

Developer Products: "In-app purchases" in ROBLOX!

Do you have a smartphone? If you do, you probably have a lot of apps on your phone. Don’t have a smartphone? I’m sure you know what an app is. This article is about implementing something similar to in-app purchases on your smartphone to your roblox place: adding Developer Products.

The power of in-app purchases is that their low-cost really encourages you to buy it. Buying a power-up for a dollar which can probably help solving that stubborn level seems like a bargain. Using Developer Products, you can create something similar to your places!

But wait, you say. We have game passes, right? Why not use that? Well, Developer Products are distinguished from Game Passes by two main features:

  • You can buy them more than once
  • Unlimited Products per place

You should use Developer Products mainly like Game Passes which you wish to sell more than once. Some ideas on which you can use them:

  • Buy chips for a casino (or any other in-game money, either premium or just for a refill)
  • A double XP game pass which gives you twice the XP for a certain period of time
  • For games like Hide and Seek, a game pass which you can buy in the intermission round to immediately be it!
  • Booster Developer Products to boost, for example, your speed for a certain period of time

You should use game passes when you should only buy it once. Think about map unlocks or starter kits.

However, if you find that you don’t have enough space for more game passes, you can also use Developer Products which you can only buy once. The only downside of this is that Developer Products do not get featured on the page of your game.

So, how to use them? One of the first main things to note is that you should double check if the passes work. If they don’t work and people buy your passes, they can report you for scamming! You can get in trouble for this. So, make sure that everything works and stays working!

The Developer Products API: Setting up a sample product

Every Developer Product which you want to add to your game basically needs 3 basic steps: the creation, the client-side code and the server-side code.

The creation isn’t that hard. Go to one of your places and click on Configure. You should notice that there is a tab called Developer Products. Go there and create a new one - this isn’t hard.

You will now see it is added into the Developer Products list. The most important column there is the ID column. The IDs are used to tell Roblox exactly which developer product you are trying to buy. Note this ID down.

The Client-Side code

The Client-sided code basically only uses one method of MarketplaceService, called PromptProductPurchase. This takes four arguments. The last two are optional. The first argument is the Player instance you are calling it on. This makes it possible to also run this code from the server. You will find yourself using this code on the client the most though - think about Shop GUIs to buy Developer Products. The second argument is the ID of the Developer Product, which you have written down. You can always find this on the Developer Products page on the configuration page of your game.

The third optional argument is a boolean which denotes if you want to equip the purchased product. This only applies to gear. Developer products can also be used to buy gear and the ID you need to supply is the asset ID of that gear. The last argument is also optional and can be used to force the currency the player needs to pay. You can use Enum.CurrencyType for this, which has 3 values: Default (the standard currency), Robux and Tickets.

For instance, this code will prompt buying a game pass after being alive for 5 minutes:

wait(5 * 60) 
local Market = game:GetService("MarketPlaceService")
local id = 1337 -- the Developer Product ID
Market:PromptProductPurchase(game.Players.LocalPlayer, id)

This will put up a nice GUI on your game which prompts purchasing that specific product.

The Server-Side code

Now, you would like to know how to process this. This has to be done server-side. You use the Callback of MarketplaceService called ProcessReceipt. ProcessReceipt gets called with one argument, which is a table containing info about the purchase. Note that all purchases will go to this one function - you will need to split up the different actions the servers should do per different product yourself!

The table consists of a number of fields:

  • The PlayerId, denoting the userId of the Player.
  • The PlaceIdWherePurchased, denoting the PlaceId where the product has been bought.
  • The PurchaseId, which is an unique string identifier for that particular purchase.
  • The ProductId, which is the string of the ProductId bought
  • The CurrencyType, a string telling you which currency has been used
  • The CurrencySpend field, which is also a string, telling you how much has been spent

This callback should return Enum.ProductPurchaseDecision.PurchaseGranted. If this is not returned by this function, it will be called until it does return it! If you want to return in a clean way that something went wrong and it should be tried again, return Enum.ProductPurchaseDescision.NotProcessedYet.

This server-side code updates the WalkSpeed of the player after a purchase has been made. It will also save this, using the new Data Store. Always use Data Stores for your purchases: if a game crashes and you use the old Data Persistence, this data is lost and people will get angry if they find out their purchases have not been saved. You have been warned! This code also handles setting up the players which have bought the developer product.

local Market = game:GetService("MarketPlaceService")

local WalkspeedProductID = 1337

local ReceiptStorage = game:GetService("DataStoreService"):GetDataStore("Receipts", "Market")

function PlayerAdded(Player)
Player.CharacterAdded:connect(function(Character)
    local Receipt = ReceiptStorage:GetAsync(tostring(Player.userId)) 
    if Receipt then
        if Receipt.WalkspeedProductBought then 
            Character.Humanoid.WalkSpeed = 24
        end
    end
end)
end

game.Players.PlayerAdded:connect(PlayerAdded)

function GetPlayerByID(id)
    for _, Player in pairs(game.Players:GetPlayers()) do
        if Player.userId == id then
            return Player
        end
    end
end

function Market.ProcessReceipt(ReceiptInfo)
    if ReceiptInfoProductId == tostring(WalkspeedProductID) then
        local Current = ReceiptStorage:GetAsync(tostring(ReceiptInfo.PlayerId))
        if not Current then
            Current = {} — Intialize with an empty table
        end
        Current.WalkspeedProductBought = true
        ReceiptStorage:SetAsync(tostring(ReceiptInfo.PlayerId), Current) 
        -- We can use SetAsync here, as there is no risk that other players are writing to this value at the same time: it is per-player data.
        -- Apply the purchase
        local Player = GetPlayerByID(ReceiptInfo.PlayerId)  
        if Player then
            Player.Character.Humanoid.WalkSpeed = 24
        end
        return Enum.ProductPurchaseDescision.PurchaseGranted
    end
end

So what have we done in this post? We created a developer product for our place and created the client-side code to ask if the player would like to purchase the product. We also created a server-side code which handles and saves purchases!

Do you have an awesome idea with Developer Products or have you already created something really cool using them? Post it in the comments!

Posted in Scripting Tips

Commentary

Leave a Comment

timovaneck says: March 18, 2014
woow nice
TheDarkOrganism says: May 1, 2014
Great work!
JasonTheOwner says: March 30, 2017
Line 29 - shouldn't that read ReceiptInfo.ProductId ?