Originally I tried going through MarketplaceService
as you did, but I noticed it wasn’t returning the total limiteds in stock(the second argument after your "/"
). If you are aware of it, however, you can hardcode it in:
local MarketplaceService = game:GetService("MarketplaceService")
local itemId = 13679439783
local total = 100000
local label = script.Parent
local function onUpdate()
--can error, you may want to pcall this
local info = MarketplaceService:GetProductInfo(itemId)
label.Text = info.Remaining.."/"..total
end
task.spawn(onUpdate)
MarketplaceService.PromptPurchaseFinished:Connect(function(plr, id, isPurchased)
--you may not see the counter decrease by 1, due to Roblox server lag or testing in studio
--but this is the accurate result of remainings the site will show you
if id == itemId and isPurchased then onUpdate() end
end)
Now if you aren’t, you will have to use the actual endpoint(which luckily for you, doesn’t require authentication) to fetch the remainings and total:
local MarketplaceService = game:GetService("MarketplaceService")
local HttpService = game:GetService("HttpService")
local itemId = 13679439783
local label = script.Parent
--Do not pass non-Roblox urls to this, it can have unpredictable behavior
local function proxyUrl(url: string, proxy: string) return url:gsub("roblox.com", proxy, 1) end
local function getLimitedHash(id: number): string
--pcall GetProductInfo, it can fail
return MarketplaceService:GetProductInfo(id).CollectibleItemId
end
local url = "https://apis.roblox.com/marketplace-items/v1/items/details"
local data = HttpService:JSONEncode({itemIds = {getLimitedHash(itemId)}})
url = proxyUrl(url, "roproxy.com")
local function onUpdate()
--pcall PostAsync, it can also fail
local response = HttpService:PostAsync(url, data)
local info = HttpService:JSONDecode(response)[1]
label.Text = info.unitsAvailableForConsumption.."/"..info.assetStock
end
task.spawn(onUpdate)
MarketplaceService.PromptPurchaseFinished:Connect(function(plr, id, isPurchased)
--you may not see the counter decrease by 1, due to Roblox server lag or testing in studio
--but this is the accurate result of remainings the site will show you
if id == itemId and isPurchased then onUpdate() end
end)
The second script uses the same endpoint that gives you the “Quantity Sold” information on the site. Most specifically this is the info.sales
property. In general, this endpoint returns many values you can check by doing print(info)
.
I was able to discover the endpoint by simply going to the item page and checking the network tab using inspect element, there I could see how I had to communicate with it and the format of the expected response.
Also since this is mostly server-sided code, I think a good idea is to split it from the label.Text
part and move it to the server. Then cache the first value it retrieves in ReplicatedStorage
(as a string value) and then every time a player makes a purchase update said value. Then from a local script you can do the following:
local label = script.Parent
local value = game.ReplicatedStorage.LimitedText
function onChanged(val) label.Text = val end
onChanged(value.Value)
value.Changed:Connect(onChanged)
On your server script(any of the ones shown above) the only change you have to do is replace local label = script.Parent
with:
local value = Instance.new("StringValue", game.ReplicatedStorage)
value.Name = "LimitedText"
and label.Text
with value.Value
. Also, change its location to ServerScriptService
and move the local script in your UI instead.
That way when a player makes a purchase the update will replicate to the other clients as well.