Help with my Skip Stage script only working in studio, not actual game

Hello everyone, i have a Skip Stage script and it only works in roblox studio, not in the actual game. When you buy it on studio, it works perfectly, you get teleported to the next stage/checkpoint, but when ingame, you buy it and nothing happens. I need help, anything is greatly loved and appreciated!

Skip stage text button ui script:

script.Parent.MouseButton1Down:Connect(function()
	local marketPlaceService = game:GetService("MarketplaceService")
	marketPlaceService:PromptProductPurchase(game.Players.LocalPlayer, 1884330488)
end)

Skip Stage script:

local marketPlaceService = game:GetService("MarketplaceService")

marketPlaceService.ProcessReceipt = function(receiptInfo)
	local player = game.Players:GetPlayerByUserId(receiptInfo.PlayerId)

	if receiptInfo.ProductId == 1884330488 then
		player.leaderstats.Stage.Value += 1
		wait(1)
		player:LoadCharacter()
		return Enum.ProductPurchaseDecision.PurchaseGranted
	end
end

I think that’s all. There’s also a folder in workspace named: “Checkpoints” that contains numbered part that works as checkpoints.

2 Likes
  • Does it change your stages value in game?
  • What is in the output?
  • Have you tried printing when then receipt fires and also check the product id?

It doesn’t change the value.
Nothing is said about the script.
I don’t think i did, i probably didn’t.


Here’s the output in game.

What is that “Donation Board” output? It seems to me that it is overriding your ProcessReceipt callback, which can only be assigned once.

That is the case, in my obby I use game:GetService("MarketplaceService").PromptProductPurchaseFinished:Connect(function(userID, productID, isPurchased) for my skip stages since I didn’t feel like changing the donation board.

My game had 25k mau and not a single purchase failed so it works good.

1 Like

You are not supposed to use PromptProductPurchaseFinished for purchase handling as it is only meant to detect the closing of the prompt. There are also reports of it being exploitable from the UGC community.

Not only that, ProcessReceipt allows you to tell Roblox if the purchase was successful or not on your end, cancelling the purchase in case anything goes wrong (DataStore goes down, for example).

1 Like

ProcessRecipt can only be used in one script so we use one big script for all our developer products

Documentation: MarketplaceService | Documentation - Roblox Creator Hub

I made this script using the source code from the documentation page

local MarketplaceService = game:GetService("MarketplaceService")
local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")

-- Data store for tracking purchases that were successfully processed
local purchaseHistoryStore = DataStoreService:GetDataStore("PurchaseHistory")

-- Table setup containing product IDs and functions for handling purchases
local productFunctions = {}


productFunctions[1884330488 ] = function(_receipt, player)
	
	player.leaderstats.Stage.Value += 1
	wait(1)
	player:LoadCharacter()
	return Enum.ProductPurchaseDecision.PurchaseGranted
	
	end

-- The core 'ProcessReceipt' callback function
local function processReceipt(receiptInfo)
	-- Determine if the product was already granted by checking the data store
	local playerProductKey = receiptInfo.PlayerId .. "_" .. receiptInfo.PurchaseId
	local purchased = false
	local success, result, errorMessage

	success, errorMessage = pcall(function()
		purchased = purchaseHistoryStore:GetAsync(playerProductKey)
	end)
	-- If purchase was recorded, the product was already granted
	if success and purchased then
		return Enum.ProductPurchaseDecision.PurchaseGranted
	elseif not success then
		error("Data store error:" .. errorMessage)
	end

	-- Determine if the product was already granted by checking the data store  
	local playerProductKey = receiptInfo.PlayerId .. "_" .. receiptInfo.PurchaseId

	local success, isPurchaseRecorded = pcall(function()
		return purchaseHistoryStore:UpdateAsync(playerProductKey, function(alreadyPurchased)
			if alreadyPurchased then
				return true
			end

			-- Find the player who made the purchase in the server
			local player = Players:GetPlayerByUserId(receiptInfo.PlayerId)
			if not player then
				-- The player probably left the game
				-- If they come back, the callback will be called again
				return nil
			end

			local handler = productFunctions[receiptInfo.ProductId]

			local success, result = pcall(handler, receiptInfo, player)
			-- If granting the product failed, do NOT record the purchase in datastores.
			if not success or not result then
				error("Failed to process a product purchase for ProductId: " .. tostring(receiptInfo.ProductId) .. " Player: " .. tostring(player) .. " Error: " .. tostring(result))
				return nil
			end

			-- Record the transcation in purchaseHistoryStore.
			return true
		end)
	end)

	if not success then
		error("Failed to process receipt due to data store error.")
		return Enum.ProductPurchaseDecision.NotProcessedYet
	elseif isPurchaseRecorded == nil then
		-- Didn't update the value in data store.
		return Enum.ProductPurchaseDecision.NotProcessedYet
	else	
		-- IMPORTANT: Tell Roblox that the game successfully handled the purchase
		return Enum.ProductPurchaseDecision.PurchaseGranted
	end
end

-- Set the callback; this can only be done once by one script on the server!
MarketplaceService.ProcessReceipt = processReceipt

You need to put your developer products from the donation board in here any and all developer products must go in here

I tried doing what you said i think but maybe i didn’t correctly do it and it didn’t work. I decided to use a GUI Donation board and it works. Thanks to everyone, if anyone still has a way to fix it reply to me!

The reason why the donation board and the skip stage script were not working simultaneously is probably because the donation board and the skip stage script both use processReceipt in two or more scripts. Remember, you can only use processReceipt one time in one script. This means you need one script to handle all developer products in one place.

The good thing about donation products is that there is no extra code needed. You buy the product and you’ve donated. That is why the Gui donation method works. All you’re doing is prompting them to buy a product, that’s it.

I would recommend reading this and using the source code it provides

2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.