PSA: Stop using Roblox proxies! (roproxy, rprxy.xyz, rprxy)

Also, you can add checks for if they are in the Group and if they are a specific Rank in the group to prevent random requests getting sent to your webhooks.

That’s not related to the issue here - it’s that you’re leaving your webhooks open to attack by the people running the proxy itself

Hi everyone, I’m a PM from Roblox and want to learn more about your needs about accessing Roblox domain directly from your game.
Could you share the features you’re trying to build?

9 Likes

For getting precise and extensive details on badges, groups, games, people, and items. You can’t do this with methods of MarketplaceService, players, etc. This is why I use roproxy, anyways.

Some documentation on roblox even says developers use proxies to send requests to roblox.com, so why can’t we just send it directly?

2 Likes

How do you use such details in your game? can you give some examples?

1 Like

As a way to show how many people earned a badge:

A way to get lots of details on games:

Trade hangout get’s users items: (most likely though rolimons API, but it could be through roblox in some games like this)


It would be more efficient to go directly to roblox rather than through a proxy. But, if it’s for security reasons (or some similar excu- reason), then I understand.

3 Likes

I think we just need more methods to services directly. I feel making web requests to itself is just sort of hacky.

4 Likes

Yes of course, but if we had to send a request I’d prefer it directly to roblox for information on roblox stuff. Maybe then it could detect I’m asking for roblox.com, and would ask it’s own servers instead of making a request?

1 Like
  • Getting all the gamepasses a player made.
  • Getting all the badges a player has.
  • How many people purchased a gamepass
  • How many people earned a specific badge (as @bluebxrrybot said)

There are alot of more needs I can’t just explain here!

2 Likes

I have to use a simple proxy I host on Google Apps to provide an Audio search function for players in our Poop Simulator game. This allows them to create their own custom audio/radio playlist in game.

It’s the only way to query the catalog for audio assets that I am aware of by effectively going off-platform and back in via the API.

It’s not an expected norm. It’s a recommendation, for your account’s security, and your users’ security.
Like the post says, lots of functions that these API proxies are being used for are usable in Roblox’s Luau environment, without any user-requested HTTP requests.

If you’re making a system that REQUIRES a proxy, you should not be using a public proxy. A private one is much more secure, as you can define your token and such on the proxy’s end, instead of the game’s end (this eliminates the possibility of someone logging into the holder account via the token, unless you expose it another way).
You can also only expose very specific functions, and if you know what you’re doing, you can do additional checks to see if the incoming proxy request is coming from one of your game’s servers.

If you don’t have the money to do PAID cloud hosting or self-hosting, don’t host your own at all. Completely free services (Heroku, Google Scripts / Apps) are not going to be reliable, compared to a paid service (Google Cloud Services, so on.)

Also, I’d totally recommend GCS (but self-hosting is the most reliable, depending on other factors). It’s confusing, but you can get $300 of free credit for three months without having to pay a cent.

6 Likes

Recently, Roblox has been planning to let us request roblox.com at certain endpoints so a proxy is still necessary but is not at certain cases

4 Likes

Not sure if you are still asking but for my use-case I am trying to use Roblox Open Cloud & HttpService to access the a DataStore from experience A and transfer it over to experience B on a Players.PlayerAdded basis.

  • Player joins experience A
  • I query for any existing data in experience B (a privated game) using HttpService & Roblox Open Cloud API endpoints
  • I assign them that existing data to their data in experience A

Mock example;

... --// Player joins experience A

local ExperienceB_EndPoint = "https://apis.Roblox.com/datastores/v1/universes/{" .. ExperienceB_UniverseID .. "}"
local Response = HttpService:GetAsync(ExperienceB_EndPoint )

warn(HttpService:JSONEncode(Response))

Is accessing Roblox API’s directly with Lua still going to be considered?

I’d imagine these would be accessed directly with HttpService, or with a special service to interact with any of the APIs that do not require a token to use. If they did use a token, it would have to be called from the client. I can understand if that may be unsafe.

I still have use cases for the Roblox API, and it would be great if we didn’t have to use any hacky methods like with using proxies. They’ll go down for good eventually, but a service won’t.

2 Likes

I don’t know if this question is still being considered, but in my case it goes as this:
I want to fetch how many sales a limited item has, so I can classify them based on the number of copies sold. But for some reason, MarketplaceService:GetProductInfo( ) or AvatarEditorService:GetItemDetails( ) only returns this info if the item is a LimitedUnique, although you can see this information in the catalog for both of the limited types.
Also, the sales data always returns 0 independent of the type of the item.
I think that a solution for this would be making these methods return more details about the item, or simply letting specific endpoints available to the general use, without the need of using proxies to send requests.
This would make things easier, while protecting developers that don’t know about these risks or don’t have the resources / knowledge to use it safely.

One of the reasons I’m currently looking into it is because there is no way of getting either a list of/a check for players with developer access when running the game. I do not have access to hosting own web servers or such things, nor do I have the know-how on how to set one up. I have been informed (via this post), that there’s an API that I can check if a player has manage perms "develop.roblox.com/v1/user/UserId/canmanage/PlaceId". If there is a Service function to check this, that would make my life a whole lot easier.

For example:

--Theoretical code, functions do not exist.
local PlayersService = game:GetService("Players")

local PlayerAdded = function(player:Player)
	local isDeveloper:boolean = PlayersService:isDeveloperOfPlace(player.UserId, game.PlaceId)
	
	if isDeveloper == true then
		print(tostring(player.Name.." Is a Developer of this game, Granting Developer Access"))
		--Grant Developer Access
	else
		print(tostring(player.Name.." Is NOT a Developer of this game, Granting Player Access"))
		--Grant Player Access
	end
	
end


PlayersService.PlayerAdded:Connect(PlayerAdded)

This API was unfortunately deprecated (and removed) a while back with the new alternative API requiring that you have the cookie of the account you wish to request from.

so… it’s impossible to get this info?

Not entirely, I did some digging around few days ago in API Documentation and wrote a Typescript function to check if they have studio permissions.

It cannot check for collaborators of a experience atm though. Requires 2 NPM Packages and a Roblox Open Cloud API Key. Weirdly Roblox requires the API key to be owned by an Regular account not an Group otherwise you’ll get authentication bugs.

import axios from "axios";
import noblox from "noblox.js";

// Base API URL
const baseUrl: string = 'https://apis.roblox.com';

// Interfaces for Roblox API responses
export interface RobloxOCRole {
    id: number;
    name: string;
    rank: number;
    memberCount: number;
    permissions: {
        viewWallPosts: boolean,
        createWallPosts: boolean,
        deleteWallPosts: boolean,
        viewGroupShout: boolean,
        createGroupShout: boolean,
        changeRank: boolean,
        acceptRequests: boolean,
        exileMembers: boolean,
        manageRelationships: boolean,
        viewAuditLog: boolean,
        spendGroupFunds: boolean,
        advertiseGroup: boolean,
        createAvatarItems: boolean,
        manageAvatarItems: boolean,
        manageGroupUniverses: boolean,
        viewUniverseAnalytics: boolean,
        createApiKeys: boolean,
        manageApiKeys: boolean
    };
}

export interface GroupRolesResponse {
    groupRoles: RobloxOCRole[];
    nextPageToken?: string;
}

export interface AssetDetails {
    creationContext: {
        creator: {
            userId?: number;
            groupId?: number;
        };
    };
}

// Function to get asset details from the Roblox Open Cloud API
async function getAssetDetails(assetId: number): Promise<AssetDetails> {
    try {
        const response = await axios.get(`${baseUrl}/assets/v1/assets/${assetId}`, {
            headers: {
                "x-api-key": process.env.RBLX_OC_API_KEY as string,
                "Accept": "*/*",
                "User-Agent": "axios"
            }
        });
        return response.data;
    } catch (error) {
        console.log("Error fetching asset details:", error);
        return null;
    }
}

// Function to get group roles and their permissions from the Roblox Open Cloud API
async function getGroupRoles(groupId: number, maxPageSize: number = 10, pageToken: string | null = null): Promise<GroupRolesResponse> {
    try {
        const params: Record<string, any> = { maxPageSize };
        if (pageToken) params.pageToken = pageToken;

        const response = await axios.get(`${baseUrl}/cloud/v2/groups/${groupId}/roles`, {
            headers: {
                "x-api-key": process.env.RBLX_OC_API_KEY as string,
                "Accept": "*/*",
                "User-Agent": "axios"
            },
            params: params
        });

        return response.data;
    } catch (error) {
        console.log("Error fetching asset details:", error);
        return null;
    }
}

// Function to check if a user can edit an experience based on their group role
async function canUserEditInGroup(groupId: number, userId: number): Promise<boolean> {
    try {
        const rank: number = await noblox.getRankInGroup(groupId, userId);
        if (rank === 255) return true;

        const group: GroupRolesResponse = await getGroupRoles(groupId);
        if (!group) return false; 

        const userRole = group.groupRoles.find(role => role.rank === rank);
        if (!userRole) return false;

        return userRole.permissions.manageGroupUniverses;
    } catch (error) {
        console.log("Error fetching asset details:", error);
        return false;
    }
}

// Main function to check if the user can edit the experience
export default async function canUserEditExperience(assetId: number, userId: number): Promise<boolean> {
    if (assetId <= 0) return false;

    try {
        const assetDetails = await getAssetDetails(assetId);
        if (!assetDetails) return false; 
        
        const creator = assetDetails.creationContext.creator;

        // Check if the place is owned by a user
        if (creator.userId && creator.userId === userId) return true;

        // Check if the place is owned by a group
        if (creator.groupId) return await canUserEditInGroup(creator.groupId, userId);

        return false;
    } catch (error) {
        console.error("Error checking user permissions:", error);
        return false;
    }
}

I appreciate the time you’ve taken to make this, but I need something that can be used in-roblox that can detect anyone including collaborators and it to work in both group games and user game. Looks like there’s nothing for that.

1 Like