Thank you, finally I’ve been waiting for this update for so long.! I’ll have some few additional questions in PMs.
except they did…
These endpoints currently allow unauthenticated access to many assets. We’re making this change to enhance security and prevent abuse of creators’ content, including unauthorized content scraping. This update will allow us to protect your content better and provide a more secure platform.
It seems like that projects using the old roblox client contributed the cost, as outside this platform, there is Roblox Revival that mostly use the V1 endpoint.
We’re monitoring all unauthenticated requests right now. If you have any questions about a specific place or asset we can check if it’s in our list and let you know.
As I noticed, you have been planning to work on this API change for months, because it only started to affect unauthenticated requests back in November 2024 with the rate-limiter. Many users found out that using authenticated cookies would bypass the rate-limit, and so on it improved it.
One question it still remains is that this feature was announced due of the overloaded requests, right?
I don’t really get the point
I don’t see how this is even a problem (very vague on how you can abuse someone public assets), and adding an authorization won’t fix anything.
for example in the case of “scraping”, people can just make roblox accounts, get their cookies/oauth and boom it works…
The recommended replacement endpoint for fetching assets:
Does not support authentication via the x-api-key
header for members of a group.
Is this a bug? Is the purpose of these replacement end-points not to support API authentication?
How are members of a group supposed to authenticate themselves?
Unauthenticated asset loading ceased to work between 21:10 and 00:30 UTC.
USER@DESKTOP-0K06777 ~
$ date --iso-8601=seconds
2025-04-03T05:57:23+00:00
USER@DESKTOP-0K06777 ~
$ curl https://assetdelivery.roblox.com/v1/asset/?id=4794911592 -L
Warning: Binary output can mess up your terminal. Use "--output -" to tell curl to output it to your terminal anyway, or consider "--output <FILE>" to save to
Warning: a file.
USER@DESKTOP-0K06777 ~
$ curl -s https://assetdelivery.roblox.com/v1/asset/?id=4794911592 -L --output - | wc --bytes
8929238
Unauthenticated asset loading also worked as of 07:03 (past midnight Pacific).
USER@DESKTOP-0K06777 ~
$ date --iso-8601=seconds
2025-04-03T07:03:28+00:00
USER@DESKTOP-0K06777 ~
$ curl https://assetdelivery.roblox.com/v1/asset/?id=4794911592 -L
Warning: Binary output can mess up your terminal. Use "--output -" to tell curl to output it to your terminal anyway, or consider "--output <FILE>" to save to
Warning: a file.
USER@DESKTOP-0K06777 ~
$ curl -s https://assetdelivery.roblox.com/v1/asset/?id=4794911592 -L --output - | wc --bytes
8929238
USER@DESKTOP-0K06777 ~
$ date --iso-8601=seconds
2025-04-03T09:04:01+00:00
USER@DESKTOP-0K06777 ~
$ curl -s https://assetdelivery.roblox.com/v1/asset/?id=4794911592 -L --output - | wc --bytes
8929238
USER@DESKTOP-0K06777 ~
$ date --iso-8601=seconds
2025-04-03T09:29:14+00:00
USER@DESKTOP-0K06777 ~
$ curl -s https://assetdelivery.roblox.com/v1/asset/?id=4794911592 -L --output - | wc --bytes
8929238
root@localhost:~# date --iso-8601=seconds
2025-04-03T19:10:29+00:00
root@localhost:~# curl assetdelivery.roblox.com/v1/asset/?id=1818 -L
Warning: Binary output can mess up your terminal. Use "--output -" to tell
Warning: curl to output it to your terminal anyway, or consider "--output
Warning: <FILE>" to save to a file.
Still as of 21:10Z.
USER@DESKTOP-0K06777 ~
$ date --iso-8601=seconds
2025-04-03T21:10:58+00:00
USER@DESKTOP-0K06777 ~
$ curl https://assetdelivery.roblox.com/v1/asset/?id=4794911592 -L
Warning: Binary output can mess up your terminal. Use "--output -" to tell curl to output it to your terminal anyway, or consider "--output <FILE>" to save to
Warning: a file.
USER@DESKTOP-0K06777 ~
$ date --iso-8601=seconds
2025-04-04T00:35:40+00:00
USER@DESKTOP-0K06777 ~
$ curl https://assetdelivery.roblox.com/v1/asset/?id=4794911592 -L
{"errors":[{"code":0,"message":"Authentication required to access Asset."}]}
Well now what do i do? i was using assetdelivery for getting the binary by http service and roproxy and then i get some data from it but now i cant access it
The legacy-asset:manage
permission scope doesn’t work with community API keys, preventing Asphalt from working properly.
Hi unmiss. Have you tried just making a “user” API key? It just wants to verify you are a valid user making the request. So far, it does not seem to care which user creates the key. The new assetdelivery returns a “location” URL to which you must send another http GET to retrieve the binary.
The new authenticated apis do not support the usecase of getting an image id from a decal id.
Previously, I used this:
Unfortunately, the new API does not contain the image id anywhere in the response, only the actual image binary location. I refuse to use a cookie to authenticate my requests, given how fickle they are.
Either add a dedicated “get image id from decal id” endpoint, or allow us to use user keys to access the legacy apis.
How about the InsertService method to get the ImageId from DecalId?
Please look at my screenshot and notice that this is not a Roblox environment, that’s a Python script; InsertService does not exist outside of Roblox
Yes I’m talking about ways to do it without needing to use outside code for what you want
My Python program needs the asset id without communicating with a Roblox server; this isn’t a proxy
Is there any problem with just downloading the location as well?
def get_image_id(asset_id):
Response = requests.get(
url = f"https://apis.roblox.com/asset-delivery-api/v1/assetId/{asset_id}",
headers = {
"x-api-key": ApiKey
}
)
Response.raise_for_status()
Data = requests.get(Response.json()["location"])
Data.raise_for_status()
Match = re.search(r"id=(\d+)", Data.text)
if Match:
return Match.group(1)
else:
raise ValueError("Image ID not found in the response")
I’m talking about using InsertService:LoadAsset on the ID given by the player, seeing if the returned asset has a Decal on it, if yes, the ID given is a Decal Id, grab the Image Id from it, if not, the Id is an Image one, use that one
I’ll admit, I probably should have tried this. I misinterpreted the “location” as solely being the image binary. Thank you, this works.
Would still like a more tact way of getting the image id though
This is how I’m currently doing it on my game:
local insertService = game:GetService("InsertService")
local id = 1234567890
local success, model = pcall(insertService.LoadAsset, insertService, id)
if success and model then
local decal = model:FindFirstChildOfClass("Decal")
if decal then
id = string.gsub(decal.Texture, "%D", "")
end
end
print(`rbxassetid://{id}`)
It seems to yield for about the same time it does when you use the ID on explorer and it auto-changes, you could probably cache it on the same server if anything to make it faster for same-ids
I assume this is what is causing my issue(s) mentioned in this post?
Why does this script that gets place visits and favorites error? “HttpError: InvalidRedirect” - Help and Feedback / Scripting Support - Developer Forum | Roblox
FAQS:
When did this change go live?
This change went live on April 2, 2025. Any request to an AssetDelivery endpoint without authentication now returns a 401 Unauthorized error.
> curl https://assetdelivery.roblox.com/v1/asset/?id=xxxxxxxxxx
{"errors":[{"code":0,"message":"Authentication required to access Asset."}]}
Does this affect experiences or Studio plug-ins using engine APIs such as InsertService?
No. Those APIs continue to work exactly as before.
Some asset requests still seem to work without authentication - why?
To ease the transition, we temporarily exempted some asset IDs to be fetched without authentication. We will shrink this exception list over time, so we strongly recommend moving to authenticated requests as soon as possible.
Does this change block access to public or free assets?
No. Logged-in users can still access public and free assets, and inserting assets in-game or in Studio behaves exactly the same.
I’m using a web proxy to get image IDs from Decals and it no longer works. What should I do?
Good news: you can now fetch Decals you do not own directly from in-game code by using InsertService. See the announcement here: link
If you need to read assets outside the engine - for example from a custom tool - see the next question.
My proxy or tool can’t fetch assets anymore. What should I do?
We have released two new OpenCloud endpoints for fetching assets. Documentation is available here : docs. These endpoints are on apis.roblox.com, not assetdelivery.roblox.com.
The quickest fix is to pass an api key with each request to these new endpoints. An api key created for any user is sufficient if you only need publicly-available assets. Be aware, however, that heavy use could throttle requests for that user.
Here’s an example curl command and output (with the api key removed).
> curl https://apis.roblox.com/asset-delivery-api/v1/assetId/1818 -H "x-api-key: $apikey"
{"location":"https://sc2.rbxcdn.com/3531bd1e0747fccbf5df1aea7e3fc903?__token__=exp=1746044686~acl=/3531bd1e0747fccbf5df1aea7e3fc903*~hmac=aff1f6ba8f5a8daae71eeee80899a82fe0b1afa1c1a123fc18bd6445546a0d8e&Expires=1746044686&Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cHM6Ly9zYzIucmJ4Y2RuLmNvbS8zNTMxYmQxZTA3NDdmY2NiZjVkZjFhZWE3ZTNmYzkwMyoiLCJDb25kaXRpb24iOnsiRGF0ZUxlc3NUaGFuIjp7IkFXUzpFcG9jaFRpbWUiOjE3NDYwNDQ2ODZ9fX1dfQ__&Signature=kUohXX01Gcn2RfY4jNp0aEAp09e8LX+/6wqHksvSE1ibkipVhJA6SwgxhUudAFfiuPLGFdpRb3E243R9zXpjNZWoekl6aW/0DTBnrVKTGBkfaMaB6PnraIX4Po7TeZnM3qZ+J3/Zy4wWJf266Lk9M1FUBpAuouwe67bPKEX+rIcxK0lBSeZXcvQGhmYbWQTZKaEEhis9EONkh8hLLhgM+X2wl9cd6ICIYqg+C40elgp3ke6BGiP4kMSFuvoIWTdOjTUG8E9Hokki4NFHxBqhV6CTAF0Cw6gDnJYXR2G9KDOF38+Hb0BSEFfSPTqeTRmqj7kQWcP3ZAmVnHx2Z+JXJg==&Key-Pair-Id=K1NHM9527CRDAW","requestId":"638814685640776121","IsHashDynamic":true,"IsCopyrightProtected":false,"isArchived":false,"assetTypeId":9}
Note that these endpoints return back a JSON payload with the URL for the asset content in the “location” field. Your application will need to make another http request to the “location” URL to download the asset content.
I want to use the new OpenCloud AssetDelivery endpoints to fetch my group’s private assets, but the legacy-asset API system is not selectable. What should I do?
The error message you see when trying to select the legacy-asset API system is “Legacy APIs with community API keys are currently not supported”.
At the moment, the new endpoints accept API keys created for individual users only, not a group. We are aware of this issue and we’re working towards a better experience for groups and legacy APIs. The current workaround is to create an API key for a user who is a member of the group and is in a role with permissions to download assets. The particular group permissions can be added on the website Group configure page:
- Configure avatar items - for avatar items, like body parts and clothing
- Create and edit community experiences - for places and game development assets
Sending up that user’s API key with your requests to the new OpenCloud endpoints will allow you to fetch the group’s assets.
Will there be a batch asset request endpoint?
We are happy to add this if creators want it! Please let us know you’re interested. Note that this would respect the same per-asset rate limits as single fetch requests though.