Game passes and developer products are the two main ways to earn Robux from your players. Game passes are permanent one-time purchases—think VIP memberships or permanent perks. Developer products are consumable items that players can buy repeatedly, like power-ups or currency bundles. Both need to be created in the Creator Dashboard before you use them in scripts.

What's the Difference?

Game passes are one-time, permanent purchases. Once a player buys one, they own it forever. Perfect for VIP status, permanent stat boosts, or exclusive cosmetics.

Developer products are consumable. Players can buy them multiple times. Use these for temporary power-ups, in-game currency packs, respawns, or revival items.

Create a Game Pass

Game passes live in the Creator Dashboard, not in Studio itself.

  1. Go to create.roblox.com and sign in.
  2. Select your game from the Creations list.
  3. Click Monetization in the left sidebar.
  4. Click Game Passes.
  5. Click Create a Game Pass.
  6. Upload an icon (at least 512×512 pixels).
  7. Enter a name and description.
  8. Set the price in Robux (minimum 10, maximum 999).
  9. Click Create Game Pass.

Once created, note your game pass ID. You'll need it in your script.

Create a Developer Product

Developer products are also created in the Creator Dashboard.

  1. Go to create.roblox.com and sign in.
  2. Select your game.
  3. Click Monetization in the left sidebar.
  4. Click Developer Products.
  5. Click Create a Developer Product.
  6. Upload an icon (at least 512×512 pixels).
  7. Enter a name and description.
  8. Set the price in Robux.
  9. Click Create Developer Product.

Save the product ID for scripting.

Script Game Pass Purchases

Use MarketplaceService to handle game pass sales. This script goes in ServerScriptService.

ServerScriptService Script — Game Pass Handler
local MarketplaceService = game:GetService("MarketplaceService")
local Players = game:GetService("Players")

-- Your game pass ID (replace with your actual ID)
local GAME_PASS_ID = 12345678

-- Handle purchase completion
local function onGamePassPurchased(player, productId)
    if productId == GAME_PASS_ID then
        -- Give the player the perk
        player.leaderstats.VIPStatus.Value = true
        print(player.Name .. " purchased the VIP game pass!")
    end
end

-- Listen for purchases
MarketplaceService.ProcessReceipt = function(receiptInfo)
    local player = Players:FindFirstChild(tostring(receiptInfo.PlayerId))
    if player then
        onGamePassPurchased(player, receiptInfo.ProductId)
        return Enum.ProductPurchaseDecision.PurchaseGranted
    end
    return Enum.ProductPurchaseDecision.NotProcessedYet
end

-- Optional: Check if a player owns the pass
function playerOwnsGamePass(player, gamePassId)
    local success, result = pcall(function()
        return MarketplaceService:UserOwnsGamePassAsync(player.UserId, gamePassId)
    end)
    return success and result or false
end

-- When a player joins, check if they own the pass
Players.PlayerAdded:Connect(function(player)
    if playerOwnsGamePass(player, GAME_PASS_ID) then
        print(player.Name .. " already owns the VIP pass")
        onGamePassPurchased(player, GAME_PASS_ID)
    end
end)

Why this works:

  • ProcessReceipt fires whenever someone buys anything in your game.
  • We check the ProductId against our game pass ID.
  • UserOwnsGamePassAsync checks if a player already owns it when they rejoin.
  • Return PurchaseGranted so the transaction completes; NotProcessedYet to retry later.
💡 Tip — Always wrap UserOwnsGamePassAsync in pcall() because it makes a web request. If the connection fails, you don't want your script to break.

Script Developer Product Purchases

Developer products use the same MarketplaceService and ProcessReceipt system. This script also goes in ServerScriptService.

ServerScriptService Script — Developer Product Handler
local MarketplaceService = game:GetService("MarketplaceService")
local Players = game:GetService("Players")

-- Your developer product IDs (replace with your actual IDs)
local CURRENCY_PACK_100 = 87654321
local CURRENCY_PACK_500 = 87654322
local REVIVE_POTION = 87654323

-- Handle developer product purchases
local function onProductPurchased(player, productId)
    if productId == CURRENCY_PACK_100 then
        player.leaderstats.Currency.Value = player.leaderstats.Currency.Value + 100
        print(player.Name .. " bought 100 currency")
    elseif productId == CURRENCY_PACK_500 then
        player.leaderstats.Currency.Value = player.leaderstats.Currency.Value + 500
        print(player.Name .. " bought 500 currency")
    elseif productId == REVIVE_POTION then
        player.leaderstats.Revivals.Value = player.leaderstats.Revivals.Value + 1
        print(player.Name .. " bought a revive potion")
    end
end

-- Listen for all purchases
MarketplaceService.ProcessReceipt = function(receiptInfo)
    local player = Players:FindFirstChild(tostring(receiptInfo.PlayerId))
    if player then
        onProductPurchased(player, receiptInfo.ProductId)
        return Enum.ProductPurchaseDecision.PurchaseGranted
    end
    return Enum.ProductPurchaseDecision.NotProcessedYet
end

Key points:

  • Every purchase triggers ProcessReceipt, whether it's a game pass or developer product.
  • Use if statements to check the ProductId and give the right reward.
  • Developer products can be purchased repeatedly, so you just add to the player's value.
  • Return PurchaseGranted immediately to complete the sale.

Prompt a Purchase in Game

Use a LocalScript in StarterPlayer > StarterCharacterScripts or StarterPlayer > StarterPlayerScripts to let players buy items with a button click.

LocalScript — Purchase Prompt
local MarketplaceService = game:GetService("MarketplaceService")
local Players = game:GetService("Players")

local player = Players.LocalPlayer
local GAME_PASS_ID = 12345678

-- Create a simple GUI button
local screenGui = Instance.new("ScreenGui")
screenGui.ResetOnSpawn = false
screenGui.Parent = player:WaitForChild("PlayerGui")

local buyButton = Instance.new("TextButton")
buyButton.Name = "BuyVIPButton"
buyButton.Size = UDim2.new(0, 150, 0, 50)
buyButton.Position = UDim2.new(0.5, -75, 0, 10)
buyButton.Text = "Buy VIP Pass"
buyButton.Parent = screenGui

-- Handle button click
buyButton.MouseButton1Click:Connect(function()
    MarketplaceService:PromptGamePassPurchase(player, GAME_PASS_ID)
end)

For developer products, use a different method:

LocalScript — Developer Product Purchase Prompt
local MarketplaceService = game:GetService("MarketplaceService")
local Players = game:GetService("Players")

local player = Players.LocalPlayer
local CURRENCY_PACK_ID = 87654321

local screenGui = Instance.new("ScreenGui")
screenGui.ResetOnSpawn = false
screenGui.Parent = player:WaitForChild("PlayerGui")

local buyButton = Instance.new("TextButton")
buyButton.Name = "BuyCurrencyButton"
buyButton.Size = UDim2.new(0, 150, 0, 50)
buyButton.Position = UDim2.new(0.5, -75, 0, 70)
buyButton.Text = "Buy Currency"
buyButton.Parent = screenGui

buyButton.MouseButton1Click:Connect(function()
    MarketplaceService:PromptProductPurchase(player, CURRENCY_PACK_ID)
end)

The key difference: PromptGamePassPurchase for game passes, PromptProductPurchase for developer products. Both open Roblox's official purchase dialog—you never handle payment directly.

💡 Tip — Test purchases in Studio with your own account. Purchases only go live on your published game.

Check Ownership Before Granting Access

When a player joins or requests a perk, check if they own the game pass first. This prevents exploiting and handles rejoin scenarios.

ServerScriptService Script — Ownership Check
local MarketplaceService = game:GetService("MarketplaceService")
local Players = game:GetService("Players")

local GAME_PASS_ID = 12345678

local function grantVIPPerks(player)
    -- Give the player their VIP benefits
    player.leaderstats.VIPStatus.Value = true
    print(player.Name .. " has VIP access")
end

Players.PlayerAdded:Connect(function(player)
    local success, owns = pcall(function()
        return MarketplaceService:UserOwnsGamePassAsync(player.UserId, GAME_PASS_ID)
    end)
    
    if success and owns then
        grantVIPPerks(player)
    elseif not success then
        print("Error checking game pass for " .. player.Name)
    end
end)

Run this whenever a player joins. If they own the pass, activate their benefits immediately without waiting for a purchase event.

Best Practices

  • Use leaderstats or tags: Track purchase status with values players can see, so they know what they own.
  • Wrap async calls in pcall(): Web requests can fail. Always catch errors.
  • Test thoroughly: Use test accounts before publishing to ensure purchases grant the right rewards.
  • Return PurchaseGranted immediately: Don't wait for other systems. Once the script says the purchase succeeded, Roblox bills the player.
  • Price appropriately: Game passes range 10–999 Robux. Developer products have no upper limit, but high prices deter purchases.
  • Make purchases optional: Never lock core gameplay behind a paywall. Perks should enhance, not restrict.

Common Issues

ProcessReceipt never fires: Check that your game is published and you're testing with a real account, not in Studio solo mode. Purchases don't work in test mode.

Player loses perks on rejoin: You need an ownership check when they join (see "Check Ownership Before Granting Access" above). Don't rely only on ProcessReceipt.

Script error: "UserOwnsGamePassAsync is not a valid member": Use the exact spelling and capitalization. Always wrap it in pcall().

Button click doesn't prompt purchase: Make sure you're using a LocalScript in the player's PlayerGui or StarterPlayer. Server scripts can't show purchase dialogs.