BLOXBUILDS
Discord
Back
UI/UX

Shop UI

Split this at the SPLIT line. Paste the top into StarterPlayerScripts as a LocalScript and the bottom into ServerScriptService as a Script. The window prompts game pass and developer product purchases. Replace the ids.

-- LOCAL SCRIPT. Paste into StarterPlayer > StarterPlayerScripts.
-- Replace the ids. 0 hides that button's purchase prompt.

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

local GAMEPASSES = {
	{ name = "Auto Collect", id = 0 },
}
local PRODUCTS = {
	{ name = "100 Coins", id = 0 },
}

local player = Players.LocalPlayer
local playerGui = player:WaitForChild("PlayerGui")

local gui = Instance.new("ScreenGui")
gui.Name = "ShopUi"
gui.ResetOnSpawn = false
gui.Parent = playerGui

local toggle = Instance.new("TextButton")
toggle.Size = UDim2.fromOffset(88, 36)
toggle.Position = UDim2.fromOffset(16, 16)
toggle.BackgroundColor3 = Color3.fromRGB(99, 102, 241)
toggle.Text = "Shop"
toggle.TextColor3 = Color3.new(1, 1, 1)
toggle.Font = Enum.Font.GothamBold
toggle.TextSize = 16
toggle.Parent = gui

local panel = Instance.new("Frame")
panel.Size = UDim2.fromOffset(280, 220)
panel.Position = UDim2.fromOffset(16, 60)
panel.BackgroundColor3 = Color3.fromRGB(19, 22, 28)
panel.Visible = false
panel.Parent = gui

local layout = Instance.new("UIListLayout")
layout.Padding = UDim.new(0, 8)
layout.Parent = panel

local padding = Instance.new("UIPadding")
padding.PaddingTop = UDim.new(0, 12)
padding.PaddingLeft = UDim.new(0, 12)
padding.PaddingRight = UDim.new(0, 12)
padding.Parent = panel

local function addButton(text: string, callback: () -> ())
	local button = Instance.new("TextButton")
	button.Size = UDim2.new(1, 0, 0, 36)
	button.BackgroundColor3 = Color3.fromRGB(30, 35, 48)
	button.Text = text
	button.TextColor3 = Color3.new(1, 1, 1)
	button.Font = Enum.Font.GothamMedium
	button.TextSize = 15
	button.Parent = panel
	button.MouseButton1Click:Connect(callback)
end

for _, pass in ipairs(GAMEPASSES) do
	addButton(pass.name, function()
		if pass.id ~= 0 then
			MarketplaceService:PromptGamePassPurchase(player, pass.id)
		end
	end)
end

for _, product in ipairs(PRODUCTS) do
	addButton(product.name, function()
		if product.id ~= 0 then
			MarketplaceService:PromptProductPurchase(player, product.id)
		end
	end)
end

toggle.MouseButton1Click:Connect(function()
	panel.Visible = not panel.Visible
end)

-- SPLIT
-- SERVER SCRIPT. Paste into ServerScriptService.
-- Keep only one ProcessReceipt handler in the whole game.
-- PRODUCT_REWARDS maps a developer product id to the coins it grants.

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

local PRODUCT_REWARDS = {
	[0] = 100,
}

local function getCash(player: Player): IntValue
	local leaderstats = player:FindFirstChild("leaderstats")
	if not leaderstats then
		leaderstats = Instance.new("Folder")
		leaderstats.Name = "leaderstats"
		leaderstats.Parent = player
	end
	local cash = leaderstats:FindFirstChild("Cash")
	if not cash then
		cash = Instance.new("IntValue")
		cash.Name = "Cash"
		cash.Value = 0
		cash.Parent = leaderstats
	end
	return cash :: IntValue
end

MarketplaceService.ProcessReceipt = function(receipt)
	local reward = PRODUCT_REWARDS[receipt.ProductId]
	if not reward or receipt.ProductId == 0 then
		return Enum.ProductPurchaseDecision.NotProcessedYet
	end
	local player = Players:GetPlayerByUserId(receipt.PlayerId)
	if not player then
		return Enum.ProductPurchaseDecision.NotProcessedYet
	end
	getCash(player).Value += reward
	return Enum.ProductPurchaseDecision.PurchaseGranted
end