Check Badge Awards in Batches with CheckUserBadgesAsync

Hi Creators!

We’re excited to announce the launch of a new BadgeService method to check badge ownership in batches: BadgeService:CheckUserBadgesAsync().

This method is similar to the existing BadgeService:UserHasBadgeAsync() method, but it allows you to check ownership of up to 10 badges at once for a user. It has a separate rate limit of 10 + 5 * [number of players] per minute for each server.

The following code sample demonstrates how to use this new method to check badge ownership:

local BadgeService = game:GetService("BadgeService")
local Players = game:GetService("Players")
local badgeIds = { 0000000000, 1111111111, 2222222222 } -- Change this to a list of your badge IDs
local function onPlayerAdded(player)
      -- Check if the player has any of the badges
      local success, result = pcall(function()
         return BadgeService:CheckUserBadgesAsync(player.UserId, badgeIds)
      end)
      -- If there's an error, issue a warning and exit the function
      if not success then
            warn("Error while checking if player", player.Name, "has badges:", result)
            return
      end

      local ownedBadgeIds = result

      if #ownedBadgeIds == 0 then
            print(player.Name, "does not have any of the badges")
      else
            print(player.Name, "has the following badges:", table.concat(ownedBadgeIds, ", "))
      end
end

Players.PlayerAdded:Connect(onPlayerAdded)

If you’re currently using multiple BadgeService:UserHasBadgeAsync() calls to check badge awards for a user, we encourage you to switch to a single BadgeService:CheckUserBadgesAsync() call; it will reduce the number of network requests your experience makes and improve its badge reading speed!

Please let us know if you have any questions or run into any issues using this new method.

282 Likes

This topic was automatically opened after 10 minutes.

This is awesome! In Virtual Valley Games, we load all the badges for a player on start to make badge queries much faster later on, which is dozens of badges in Tsunami Game. It added so much time to the start (3-5 seconds, which meant every test session had a 3-5 second delay), that we had to put all of those requests in parallel. I look forward to tearing down our multitasking workflow.

Edit: Totally missed the limit of 10, but at least we will only do a few requests in parallel instead of a few dozen.

How does the response time scale with more badges? For example, if I double the badges I am querying, does it take twice as long, or less than that?

47 Likes

I was literally doing a check for badges to define “genres” since I am waiting for Analytics to support the kind of users that are joining my game.

Anyways, this will be helpful since there are a lot of badges I am checking for…

But why is the Limit 10…? :smiley: I would love even if it automatically waits internally to perform a a new request of 10 badges, I can do it myself I know, but just why…

Anyways, Thank you!

15 Likes

Slightly disappointed its limited to 10 at once, but its better than nothing I guess.

Similar function for gamepasses when?

16 Likes

You can expect very small, likely unobservable increases in request latency the more badges you add. In your example, it would take much less than twice as long.

21 Likes

Finally it’s been out, been waiting for this no more hacky ways!

@CoffeeBurg3r One question though, what does this return though? I store my badges as frame as a way to showcase players their badges and I also use UserHasBadgeAsync, could this new method be a better practice or what?

local function _doAchievements(Inst)
	if script.Parent._achievements._list.ScrollingFrame:FindFirstChild(Inst.Name) then return end
	local _badgeFrame:TextButton = Inst:Clone()
	table.insert(_badgeIDs, _badgeFrame:GetAttribute("_id"))
	if BadgeService:UserHasBadgeAsync(Player.UserId, _badgeFrame:GetAttribute("_id")) then
		print("has")
		_badgesAmount += 1
		_badgeFrame.LayoutOrder = 0
		_badgeFrame.ImageLabel.ImageTransparency = 0
		_badgeFrame.ImageLabel.ImageLabel:Destroy()
	else
		_badgeFrame.LayoutOrder = 1
	end
	_badgeFrame.Parent = script.Parent._achievements._list.ScrollingFrame
	_badgeFrame.MouseButton1Down:Connect(function()
		print(_badgeFrame:GetAttribute("_description"))
		ReplicatedStorage._remotes._ct._effect:Fire("_attention", _badgeFrame:GetAttribute("_description"), 5)
	end)
	script.Parent._achievements.Frame._howMany.Text = _badgesAmount.."/"..#ReplicatedStorage._allClientsAssets._Achievemnts:GetChildren()
end

11 Likes

I’d recommend checking all of the badges at once, outside of each frame instance. You can then take the list of badge IDs returned and update each corresponding frame based on each ID.

15 Likes

This is a very useful feature, thanks!

Are there plans to eventually increase the limit of 10, if this goes smoothly?

9 Likes

this is a good update, i really needed this for my horror game.

8 Likes

Probably just a faster way and without for loops.

7 Likes

Faster way, it’s in bulk. Multiple badge ids instead of just the 1 checking for multiple times.

8 Likes

This is great, can we expect batch APIs for GetNameFromID/GetIDFromName anytime soon?

8 Likes

now add CheckUserGamepassAsync


18 Likes

Is there any reason why this is 10 and not 100? The badge web-API allows for the checking of up to 100 badges at once and I can only assume the lua API is either using this API behind-the-scenes or some variation which would be able to handle 100 badges at once. I understand if there may be a different system architecture which makes handling such a large badge count infeasible but if not, it just doesn’t make much sense to have the lua APIs have this decreased limit.

Also, this may be a very niche use-case but is there any chance we could see awardedDate being opened up to the lua API? Currently, we can only check whether a player owns a badge, knowing awarded dates can be helpful for creating badge leaderboards, etc.


GetUserInfosByUserIdsAsync should cover this use-case (at least for the UserId->Name side of things), albeit the API is finicky to work with (the response is an unordered array which you’ll have to re-construct into a usable form + the API can’t even convert strings to numbers)


A slight bit off-topic but is AwardBadge and UserHasBadgeAsync a shared rate-limit? This has been something that I’ve been questioning for ages as both documented limits are the same in-value yet aren’t ever specified as “seperate” or “shared”.

15 Likes

Type

Roblox engineers try to add proper types challenge (impossible).


Why’d this take 5 1/2 months to enable? And why is it limited to 10 ids when the web API allows 100?

15 Likes

Can we expect an increase to this limit? Either the # of requests / player / min or the badges that can be included in a single request?

My game has a Bestiary which allows you to view all of the badges for the game, including limited edition ones that are no longer available, and with the current rates it takes several minutes to load the ownership status of each badge. This wouldn’t increase the update rate so there’s less friction for my players by much, if at all.

RobloxPlayerBeta_5AD1G0Cav2

Games with hundreds of badges (like badge hunt games) currently suffer from this using Roblox’s current studio APIs.

Would also love to see a multi-get method for listing all badges of an experience, or at least the badge information (like description). Currently I have a large table of hundreds of badges, as well as their descriptions, and it’s easy for them to be outdated with changes I make on the website. Having this reliably up-to-date would be nice.

17 Likes

Ten seems low for addressing the need to check badges in bulk. Many experiences on Roblox have well north of this quantity. Meaning, running checks for each user will have to be split into multiple requests anyways—largely diminishing the utility. I’m of course glad for any improvements to the speed of this kind of processing, but I would have preferred a more generous limit, or a more comprehensive solution. In most cases, I’d really only want to get badges associated with the game’s universe. It would be nice if these checks could somehow be done cheaply, or with priority.

12 Likes

Would love to see this with other APIs! Although the limit is disappointing, when the limits on their web APIs are much higher.

9 Likes

only 10? :frowning:

not too useful unless it’s 50+ tbh

10 Likes