关于 roblox-monetization
面向 Roblox 商店与购买流程开发者的变现指南,说明商品类型、服务器端发放、收据处理、定价、退款及合规检查。
主要功能
- 01商品类型选择指南
- 02幂等收据处理
- 03通行证与订阅处理
- 04实时定价与商品发现
- 05退款与拒付处理
- 06政策和地区检查
适用场景
- 01安全发放开发者商品购买内容
- 02实现可撤销的订阅权益
- 03显示当前地区价格
- 04退款后撤销已发放权益
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ el4cteo/ roblox-skills --skill roblox-monetization安装后在 Claude Code 中输入/roblox-monetization确认已加载。
附带文件references/ads-and-extras.md
详细介绍
Roblox 变现
产品类型
| 类型 | 购买方式 | 用途 | 发放方式 |
|---|---|---|---|
| 开发者产品 | 可重复购买 | 货币、消耗品、增益、复活 | MarketplaceService.ProcessReceipt(服务器) |
| 通行证 | 一次购买,永久有效 | VIP、永久特权、额外栏位 | 加入时检查 UserOwnsGamePassAsync + 购买完成事件 |
| 订阅 | 按月订阅,可撤销 | 定期特权(日常货币、VIP) | GetUserSubscriptionStatusAsync + UserSubscriptionStatusChanged |
| 激励视频广告 | 免费(观看广告) | 小额奖励(价值约 3–10 Robux) | 通过 ProcessReceipt 发放的开发者产品 |
| 商业产品 | 真实货币(实物商品) | 附带数字权益的周边商品 | CommerceService;数字权益通过 ProcessReceipt 发放 |
| 私人服务器 | 按月订阅 | 付费私人服务器 | 在 Creator Dashboard 中配置 |
所有奖励都必须在服务器上发放。切勿通过 PromptProductPurchaseFinished 等客户端事件发放奖励——客户端可以伪造这些事件。
开发者产品:ProcessReceipt
规则:
- 只能有一个服务器脚本设置
MarketplaceService.ProcessReceipt。 - 只有在奖励已持久化后,才返回
PurchaseGranted。否则返回NotProcessedYet; Roblox 会稍后重试(包括玩家下次加入时),并使用相同的PurchaseId。 - 处理程序必须具备幂等性:在玩家保存的数据中记录已处理的
PurchaseId,确保重试时 不会重复发放奖励。 - 收据可能会在玩家的数据尚未加载或玩家已经离开时到达:请等待其数据加载,或
返回
NotProcessedYet。
--!strict
local MarketplaceService = game:GetService("MarketplaceService")
local Players = game:GetService("Players")
type PlayerData = { coins: number, purchaseIds: { string } }
type ReceiptInfo = {
PlayerId: number,
ProductId: number,
PurchaseId: string,
CurrencySpent: number,
CurrencyType: Enum.CurrencyType,
PlaceIdWherePurchased: number,
}
local MAX_REMEMBERED_PURCHASES = 100
-- Provided by your data layer (ProfileStore profile.Data, etc.).
local function getLoadedData(_player: Player): PlayerData?
return nil
end
local function saveNow(_player: Player): boolean
return true
end
local PRODUCTS: { [number]: (Player, PlayerData) -> () } = {
[1234567] = function(_player, data) -- 100 coins
data.coins += 100
end,
}
local function processReceipt(receipt: ReceiptInfo): Enum.ProductPurchaseDecision
local player = Players:GetPlayerByUserId(receipt.PlayerId)
if not player then
return Enum.ProductPurchaseDecision.NotProcessedYet -- granted on their next visit
end
local data = getLoadedData(player)
local deadline = os.clock() + 20
while not data and player.Parent == Players and os.clock() < deadline do
task.wait(0.5)
data = getLoadedData(player)
end
if not data then
return Enum.ProductPurchaseDecision.NotProcessedYet
end
if table.find(data.purchaseIds, receipt.PurchaseId) then
return Enum.ProductPurchaseDecision.PurchaseGranted -- already granted earlier
end
local handler = PRODUCTS[receipt.ProductId]
if not handler then
warn(`No handler for product {receipt.ProductId}`)
return Enum.ProductPurchaseDecision.NotProcessedYet
end
local ok, err = pcall(handler, player, data)
if not ok then
warn(`Grant failed for {receipt.PurchaseId}: {err}`)
return Enum.ProductPurchaseDecision.NotProcessedYet
end
table.insert(data.purchaseIds, receipt.PurchaseId)
while #data.purchaseIds > MAX_REMEMBERED_PURCHASES do
table.remove(data.purchaseIds, 1)
end
if not saveNow(player) then
return Enum.ProductPurchaseDecision.NotProcessedYet -- the idempotency list prevents a double grant
end
return Enum.ProductPurchaseDecision.PurchaseGranted
end
MarketplaceService.ProcessReceipt = processReceipt :: any
使用 ProfileStore 时,“已持久化”是指等待 PurchaseId 出现在 profile.LastSavedData
中(或调用 profile:Save() 并等待);请参阅 ProfileStore 的开发者产品指南。
从客户端(UI)提示购买——奖励仍由服务器发放:
MarketplaceService:PromptProductPurchase(Players.LocalPlayer, productId)。
通行证
--!strict
local MarketplaceService = game:GetService("MarketplaceService")
local Players = game:GetService("Players")
local VIP_PASS_ID = 987654
local function grantVip(player: Player)
player:SetAttribute("VIP", true) -- apply perks from one place
end
local function checkPass(player: Player)
local ok, owns = pcall(MarketplaceService.UserOwnsGamePassAsync, MarketplaceService, player.UserId, VIP_PASS_ID)
if ok and owns then
grantVip(player)
end
end
Players.PlayerAdded:Connect(checkPass)
for _, player in Players:GetPlayers() do
task.spawn(checkPass, player)
end
-- Fires on the server too; re-verify ownership rather than trusting `purchased` alone.
MarketplaceService.PromptGamePassPurchaseFinished:Connect(function(player, passId, purchased)
if purchased and passId == VIP_PASS_ID then
checkPass(player)
end
end)
UserOwnsGamePassAsync 的结果会按服务器缓存;购买完成处理程序会处理会话期间的购买。
订阅
- 加入时以及收到
Players.UserSubscriptionStatusChanged(player, subscriptionId)时,通过MarketplaceService:GetUserSubscriptionStatusAsync(player, "EXP-...")检查订阅状态 →{ IsSubscribed, IsRenewing }。 - 权益必须可撤销:当
IsSubscribed为 false 时,移除已持久化的特权。 - 使用
MarketplaceService:PromptSubscriptionPurchase(player, subscriptionId)提示购买。 - 将通行证替换为订阅时:继续兑现现有通行证持有者的权益,并下架该通行证。
销售商品的商店
- 使用
MarketplaceService:RankProductsAsync(identifiers)个性化排序(加入时调用一次—— 速率限制严格);使用RecommendTopProductsAsync({ Enum.InfoType.Product, Enum.InfoType.GamePass })显示“热门推荐” (需要在过去 28 天内有过销售;请在task.spawn中调用)。 - 使用
GetProductInfoAsync(id, Enum.InfoType.Product)/GetDeveloperProductsAsync()显示实时价格——切勿 将 Robux 价格硬编码:动态定价(区域定价 + 价格优化)会向不同 用户显示不同价格。receipt.CurrencySpent表示用户实际支付的金额。 - 情境化优惠(死亡时提供复活、卡住时提供增益)比静态菜单效果更好。也请在 Creator Hub 中游戏的商店选项卡列出商品。
- 使用
MarketplaceService:OpenShop(player),从自定义按钮、NPC 或区域打开 Roblox 商店叠加层。 - 已上架的通行证和开发者产品也可以在游戏外销售(主页、搜索、Robux
购买后);玩家加入时,商品已经购买。开发者产品只有正确设置
ProcessReceipt才符合资格——Creator Hub → Monetization → Shop 会标记需要修复的产品。
退款和拒付
已退款的通行证(以及头像物品)会自动失去所有权——请重新检查所有权,而不是永久缓存。开发者产品的发放记录保存在你的数据中,因此你需要自行撤销:订阅 Transaction Refunded webhook(涵盖开发者产品、通行证、私人服务、付费访问),并根据 payload 中的交易 ID/收据 ID 进行匹配(参见 roblox-open-cloud)。将已处理的 PurchaseId 与每项发放内容一并保存,以便在退款时撤销。
合规
- 付费随机物品(战利品箱、扭蛋、使用 Robux 或用 Robux 购买的货币购买的抽奖):购买前必须披露概率,并检查
PolicyService:GetPolicyInfoForPlayerAsync(player):ArePaidRandomItemsRestricted→ 提供免费获取途径、已披露的固定序列,或直接购买选项。IsPaidItemTradingAllowed→ 如果值为 false,则禁用付费物品交易。
- 区域定价套利:使用
MarketplaceService:GetUsersPriceLevelsAsync(userIds)(1–1000,即全球价格的百分比)限制已购物品的赠送/交易;在玩家加入时获取,不要跨会话缓存。 - 激励视频广告的奖励必须是开发者产品,不得随机发放;广告播放期间不得伤害玩家角色。
- 遵守
PolicyService返回的广告、社交链接和交易年龄/区域限制。
激励视频广告、商业产品、Premium/Roblox Plus 挂钩、美国 18+ DevEx 汇率及年龄检查: references/ads-and-extras.md。
相关技能
roblox-data-stores(持久化发放记录)、roblox-security(经济系统漏洞)、roblox-ui(商店 UI)、roblox-analytics-liveops(经济事件、漏斗、实验)。