Roblox GUI Maker logoRoblox GUI Maker
Unofficial third-party tool · Not affiliated with Roblox Corporation

Roblox Shop GUI Tutorial: Build a Working Shop with Luau Code (2026)

2026-07-21 · Roblox GUI Maker Team

Why building a shop GUI by hand is slow

A working shop needs five moving parts: an item grid that reflows on mobile, category tabs that filter the grid, a Buy button per item that calls MarketplaceService, a server that validates receipts so players cannot fake purchases, and a Tween animation so the buy feels rewarding. Most tutorials cover one or two of these and leave you stuck on the rest. This one covers all five, with complete code.

Step 1: Design the shop layout with UIGridLayout

In this step you will lay out the item grid and category tabs. Start with a Frame anchored to the center of the screen, sized with Scale so it works on any device. Inside it, place a ScrollingFrame for the item grid and a horizontal Frame for the category tabs. The item grid uses UIGridLayout with a fixed cell size, so items arrange automatically and scroll when there are more than fit on screen. Use Scale-based sizing everywhere - a shop that only fits your monitor will break on a player's phone.

StarterGui/ShopGui/ShopPanel (create in editor)
lua
1-- Shop layout structure (build this in the web editor or in Studio)
2-- ShopPanel (Frame, Scale 0.5 x 0.6, centered)
3-- CategoryTabs (Frame, top bar)
4-- Tab_Gear (TextButton)
5-- Tab_PowerUps (TextButton)
6-- Tab_Skins (TextButton)
7-- ItemGrid (ScrollingFrame, UIListLayout or UIGridLayout)
8-- GridLayout (UIGridLayout, CellSize 120x140)
9-- CoinHeader (TextLabel, top-right, shows balance)

Step 2: Generate the client Luau

The client script builds the shop UI programmatically and wires each Buy button to call MarketplaceService. Below is the complete client code. Paste it into a LocalScript under StarterGui. Each item card specifies whether it is a Gamepass or Developer Product, and the Buy button calls the correct purchase method.

StarterGui/ShopClient (LocalScript)
lua
1-- Roblox Shop GUI - Client Script
2-- Place in: StarterGui/ShopGui (LocalScript)
3
4local Players = game:GetService("Players")
5local MarketplaceService = game:GetService("MarketplaceService")
6local TweenService = game:GetService("TweenService")
7local ReplicatedStorage = game:GetService("ReplicatedStorage")
8
9local player = Players.LocalPlayer
10local gui = script.Parent
11local itemGrid = gui:WaitForChild("ItemGrid")
12local coinHeader = gui:WaitForChild("CoinHeader")
13
14local purchaseEvent = ReplicatedStorage:WaitForChild("ShopPurchaseResult")
15
16-- Item catalog: replace ids with your own Gamepass/Product ids
17local ITEMS = {
18 { id = 1001, name = "Sword", kind = "gamepass", price = 250 },
19 { id = 1002, name = "Speed Boost", kind = "product", price = 100 },
20 { id = 1003, name = "Golden Skin", kind = "product", price = 150 },
21}
22
23local function playBuyFeedback(card)
24 local flash = TweenService:Create(
25 card,
26 TweenInfo.new(0.2, Enum.EasingStyle.Quad, Enum.EasingDirection.Out),
27 { BackgroundColor3 = Color3.fromRGB(80, 200, 120) }
28 )
29 flash:Play()
30 task.delay(0.4, function()
31 card.BackgroundColor3 = Color3.fromRGB(30, 30, 40)
32 end)
33end
34
35for _, item in ipairs(ITEMS) do
36 local card = itemGrid:WaitForChild(item.name)
37 local buyButton = card:WaitForChild("BuyButton")
38 buyButton.MouseButton1Click:Connect(function()
39 if item.kind == "gamepass" then
40 MarketplaceService:PromptGamepassPurchase(player, item.id)
41 else
42 MarketplaceService:PromptProductPurchase(player, item.id)
43 end
44 end)
45end
46
47purchaseEvent.OnClientEvent:Connect(function(itemId, success)
48 if success then
49 local item = ITEMS[1]
50 for _, it in ipairs(ITEMS) do
51 if it.id == itemId then item = it end
52 end
53 if item then
54 playBuyFeedback(itemGrid:WaitForChild(item.name))
55 end
56 end
57end)

Step 3: Validate purchases on the server

Never trust the client for purchases. The server must validate every receipt with MarketplaceService:ProcessReceipt before granting the item. This is the step that prevents players from faking a buy with an exploit. The server also pushes the result back to the client so the UI can show the success animation.

ServerScriptService/ShopServer (Script)
lua
1-- Roblox Shop GUI - Server Script
2-- Place in: ServerScriptService (Script)
3
4local MarketplaceService = game:GetService("MarketplaceService")
5local ReplicatedStorage = game:GetService("ReplicatedStorage")
6local purchaseEvent = ReplicatedStorage:WaitForChild("ShopPurchaseResult")
7
8-- Grant the purchased item: replace with your real grant logic
9local function grantItem(player, itemId)
10 -- Example: add to inventory, give a tool, or award currency
11 print(string.format("[Shop] Granting item %d to %s", itemId, player.Name))
12end
13
14MarketplaceService.ProcessReceipt = function(receiptInfo)
15 local player = game.Players:GetPlayerByUserId(receiptInfo.PlayerId)
16 if not player then
17 return Enum.ProductPurchaseDecision.NotProcessedYet
18 end
19
20 -- Validate: confirm the player can receive this item
21 grantItem(player, receiptInfo.ProductId)
22 purchaseEvent:FireClient(player, receiptInfo.ProductId, true)
23
24 return Enum.ProductPurchaseDecision.PurchaseGranted
25end

Step 4: Add Tween feedback on purchase

A shop that just silently grants an item feels dead. The playBuyFeedback function above flashes the purchased card green for 0.2 seconds when the server confirms the purchase. You can expand this with a scale-up Tween on the card, a coin counter that counts up to the new balance, or a sound effect. Keep the animation under half a second so it does not block the next purchase.

Common mistakes to avoid

  • Granting items on the client - always validate with ProcessReceipt on the server
  • Using Offset-only sizing - the shop breaks on mobile; use Scale everywhere
  • Forgetting to check kind before prompting - Gamepass and Product use different methods
  • No purchase feedback - players think nothing happened and buy again, costing Robux

Frequently asked questions