Skip to content

Commit 6e877f4

Browse files
update Open Source Docs from Roblox internal teams
1 parent f3cdecf commit 6e877f4

File tree

3 files changed

+202
-23
lines changed

3 files changed

+202
-23
lines changed

content/en-us/production/monetization/regional-pricing.md

Lines changed: 190 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,45 @@ description: Regional pricing adjusts the price of your items based on a user's
55

66
With Regional Pricing, you can offer region-specific prices for your items and build a more inclusive and accessible global economy. After you determine a default global price for an item, Roblox uses a variety of signals like the region's purchasing power, currency exchange rates, and local spending behavior to set the most appropriate price for that item region by region.
77

8-
You can choose which of your items you want to price regionally. When you enable Regional Pricing for an item in your experience, Roblox automatically adjusts the price of that item for users based on their economic location. Economic location is not always the same as account location. To determine a user's economic location, Roblox looks at signals, including VPN usage, billing history, and account history. If their economic location can't be determined, users see the default global price for the item instead.
8+
You can choose which of your items you want to price regionally. When you enable Regional Pricing for an item in your experience, Roblox automatically adjusts the price of that item for users based on their economic location.
99

10-
## Enable Regional Pricing
10+
Economic location is not always the same as account location. To determine a user's economic location, Roblox looks at signals, including VPN usage, billing history, and account history. If their economic location can't be determined, users see the default global price for the item instead.
11+
12+
To prevent price arbitrage when users gift or trade items with different regional prices, you can [manage in-experience transfers with the `GetUsersPriceLevelsAsync` API](#protect-your-trades-and-gifts).
1113

1214
<Alert severity="warning">
13-
Regional prices will never be below 30% of the default price of your pass or developer product.
15+
Regional prices will never be discounted by more than 70% of your default price, and they will never exceed the default price you set for your item.
16+
17+
For example, if your item has a default price of 100 Robux, the lowest the item can be priced at is 30 Robux and the highest is 100 Robux, regardless of a user's region.
18+
</Alert>
19+
20+
## Enable Regional Pricing
1421

15-
For example, if your item has a default price of 100 Robux, the lowest the item can be priced at is 30 Robux, regardless of a user's region.
22+
<Alert severity="info">
23+
Regional prices update periodically to reflect changes in global economy trends.
1624
</Alert>
1725

1826
### For passes
1927

20-
To enable Regional Pricing for a pass:
28+
To enable Regional Pricing for passes:
2129

2230
1. Go to [Creations](https://create.roblox.com/dashboard/creations) and select an experience.
2331
2. Go to **Monetization** > **Passes**.
24-
3. Select an existing pass or create a new pass.
25-
4. Click **Sales**.
26-
5. Turn on **Enable Regional Pricing**. The **Top Countries/Regions** list updates to show the adjusted regional price per country or region based on the default price of the pass. To view regional prices for all countries and regions, click **View all**.
27-
6. Click **Save Changes**.
32+
3. Select an existing pass or multiple passes, or create a new pass.
33+
4. Click **Enable Regional Pricing**.
34+
5. (Optional) To view regional prices by country or region, select a pass and go to its **Sales** page. The **Top Countries/Regions** list updates to show the adjusted regional prices based on the default price of the pass. To view regional prices for all countries and regions, click **View all countries**.
35+
36+
### For developer products
2837

29-
Regional prices update periodically to reflect changes in global economy trends.
38+
To enable Regional Pricing for developer products:
39+
40+
1. Check that your developer products have [dynamically-scripted prices](#check-for-dynamic-pricing).
41+
2. [Implement the `GetUsersPriceLevelsAsync` method](#protect-your-trades-and-gifts) to regulate item transfers based on users' price levels.
42+
3. Go to [Creations](https://create.roblox.com/dashboard/creations) and select an experience.
43+
4. Go to **Monetization** > **Developer Products**.
44+
5. Select an existing product or multiple products, or create a new product.
45+
6. Click **Enable Regional Pricing**.
46+
7. (Optional) To view regional prices by country or region, select a product and go to its **Basic Settings** page. The **Top Countries/Regions** list updates to show the adjusted regional prices based on the default price of the product. To view regional prices for all countries and regions, click **View all countries**.
3047

3148
### For Avatar items
3249

@@ -35,23 +52,180 @@ To enable Regional Pricing for an Avatar item, see [Pricing](../../marketplace/p
3552
## Check for dynamic pricing
3653

3754
<Alert severity="info">
38-
You don't need to check for hard-coded prices if you only have passes for sale on your experience details page.
55+
If you're only applying Regional Pricing to passes for sale on your experience details page, you don't need to check for hard-coded prices.
3956
</Alert>
4057

41-
When you enable Regional Pricing for a pass, the price of the pass adjusts for users in different regions whether it's for sale inside or outside of your experience. However, if you have hard-coded the price into your experience's UI, that number does not update as it's not dynamic or accessible by Roblox. As a result, users are charged the correct region-specific price but the UI still shows them the hard-coded value.
58+
When you enable Regional Pricing, the price of the item adjusts for users in different regions whether it's for sale inside or outside of your experience. However, if you have hard-coded the price into your experience's UI, that number does not update as it's not dynamic or accessible by Roblox. As a result, users are charged the correct region-specific price but the UI still shows them the hard-coded value.
4259

43-
The **dynamic price check** tool updates all products for sale inside your experience with a fake Robux price or a fake economic location to help you identify which prices are hard-coded in your experience's UI and which are dynamically-scripted with `Class.MarketplaceService|MarketplaceService` and called from a client script. After you have identified the hard-coded passes, you can update them to use `MarketplaceService` functions.
60+
The **dynamic price check tool** updates all items for sale inside your experience with a fake Robux price or a fake economic location to help you identify which prices are hard-coded in your experience's UI and which are dynamically-scripted with `Class.MarketplaceService|MarketplaceService` and called from a client script. After you have identified the hard-coded passes, you can update them to use `MarketplaceService` functions.
4461

4562
To use the dynamic price check tool:
4663

47-
1. Go to **Monetization** > **Passes**.
64+
1. Go to **Monetization**.
65+
- For passes, go to **Passes**.
66+
- For develper products, go to **Developer Products**.
4867
2. Click **&hellip;** and select **Dynamic Price Check**.
4968
3. Under **Add test accounts**, enter up to five Roblox users to check for hard-coded prices.
5069
4. Select a testing type.
5170
- **Price pinned** updates all dynamically-scripted prices with a set fake Robux amount.
5271
- **Location pinned** updates all dynamically-scripted prices with a region-specific price for a fake economic location.
53-
5. Click **Enable**. After a few minutes, you can enter your experience to identify the hard-coded prices.
72+
5. Click **Enable**. After a few minutes, enter your experience to identify the hard-coded prices.
5473

5574
To disable the dynamic price check tool, go to the **Dynamic Price Check** page and click **Disable**.
5675

57-
For more information about hard-coded versus dynamically-scripted product prices, see [Check for dynamic pricing](./price-optimization.md#check-for-dynamic-pricing) in the Price optimization page. For more information about selling passes with `MarketplaceService` functions, see [Sell a pass inside your experience](./game-passes.md#inside-your-experience).
76+
For more information about hard-coded versus dynamically-scripted product prices, see [Check for dynamic pricing](./price-optimization.md#check-for-dynamic-pricing) in the Price optimization page. For more information about selling passes and developer products with `MarketplaceService` functions, see [Sell a pass inside your experience](./game-passes.md#inside-your-experience) and [Sell a developer product inside your experience](./developer-products.md#inside-your-experience).
77+
78+
## Protect your trades and gifts
79+
80+
Regional pricing can affect in-experience transfers like trading and gifting. Because of price differences across regions, price arbitrage (exploiting price discrepancies between the same products to generate a profit) can take place. To manage the potential for price arbitrage, you can use the `Class.MarketplaceService.GetUsersPriceLevelsAsync|GetUsersPriceLevelsAsync` API, which lets you determine the relative price levels of users so that you can implement logic to regulate item transfers based on these levels.
81+
82+
`GetUsersPriceLevelsAsync` provides a numerical value between 1 and 1000 that indicates a user's pricing level. This value is designed to represent the percentage of the full price a user is expected to pay. The price level 1000 represents the full global price, while lower price levels indicate that the user typically pays a lower price because of their economic location.
83+
84+
A lower price level difference means that there's a smaller price difference between the full global price and the user's regional price. A higher price level difference means that there's a larger price difference between the two. For example:
85+
86+
- User A has the price level 1000, which represents the full global price. This user pays 100% of the base price for an item.
87+
- User B has the price level 500, which represents 50% of the full global price. This user pays 50% of the base price for an item.
88+
- Once you know each user's price level, you can choose to approve or block gifting or trading between User A and User B based on their price level difference of 500.
89+
90+
### Implement GetUsersPriceLevelsAsync
91+
92+
<Alert severity="warning">
93+
We recommend that you **do not** cache the results of your `GetUsersPriceLevelsAsync` API calls after a user session. User price levels can change. Relying on cached data can lead to inaccurate transfer logic and potential abuse or exploitation of the system.
94+
95+
To make sure that you have the most up-to-date price information for each user, always make calls to `GetUsersPriceLevelsAsync` at game join.
96+
</Alert>
97+
98+
To get the price levels of users involved in an item transfer, call the `GetUsersPriceLevelsAsync` function in the `MarketplaceService`. This function takes an array of user IDs as its argument, and returns an array of `PriceLevelInfo` objects with the following fields:
99+
100+
```lua
101+
type PriceLevelInfo = {
102+
UserId: number,
103+
PriceLevel: number
104+
}
105+
```
106+
107+
After implementing the function, use the returned price levels to choose whether you want to allow an item transfer to take place. For example, you can let users with a higher price level gift items to users with a lower price level, but only allow trading between users that have the same price level as each other. See the [available examples](#examples) for more information.
108+
109+
For more information about the `GetUsersPriceLevelsAsync` API, see `Class.MarketplaceService.GetUsersPriceLevelsAsync|MarketplaceService`.
110+
111+
### Examples
112+
113+
Examples of how you can use `GetUsersPriceLevelsAsync` with Regional Pricing.
114+
115+
<h5 style={{marginTop: '36px'}}>Example 1: Check the price levels for a list of users</h5>
116+
117+
This example shows you how to retrieve price levels for a list of users, which can help you choose whether you want to allow an item transfer to take place.
118+
119+
```lua
120+
-- Get the MarketplaceService
121+
local MarketplaceService = game:GetService("MarketplaceService")
122+
123+
-- Define a function to retrieve price levels for a list of users
124+
local function getPriceLevels(userIds)
125+
local success, result = pcall(function()
126+
return MarketplaceService:GetUsersPriceLevelsAsync(userIds)
127+
end)
128+
129+
if success then
130+
-- Map each PriceLevelInfo to a UserId -> PriceLevel lookup table
131+
local lookup = {}
132+
for _, info in ipairs(result) do
133+
lookup[info.UserId] = info.PriceLevel
134+
end
135+
return lookup
136+
else
137+
warn("Error getting price levels:", result)
138+
return nil
139+
end
140+
end
141+
142+
-- Example using placeholder IDs
143+
local user1Id = 123456789
144+
local user2Id = 987654321
145+
146+
-- Call the function and store the result
147+
local priceLevels = getPriceLevels({user1Id, user2Id})
148+
-- If successful, print each user's level
149+
if priceLevels then
150+
print("Price level for User 1:", priceLevels[user1Id])
151+
print("Price level for User 2:", priceLevels[user2Id])
152+
else
153+
print("Failed to retrieve price levels.")
154+
end
155+
```
156+
157+
<h5 style={{marginTop: '36px'}}>Example 2: Return a dictionary mapping each user ID to their corresponding price level</h5>
158+
159+
This example shows you how to use a helper function to transform the array returned by `GetUsersPriceLevelsAsync` into a user ID to price level mapping, which makes the results easier to read.
160+
161+
```lua
162+
-- Get the MarketplaceService
163+
local MarketplaceService = game:GetService("MarketplaceService")
164+
165+
-- Define a helper function to map users to their price levels
166+
-- The parameter priceLevelData is the array returned by MarketplaceService:GetUsersPriceLevelsAsync(), where each object contains a user ID and a price level
167+
-- The function returns a dictionary mapping each user ID to their corresponding price level
168+
local function mapUserIdsToPriceLevels(priceLevelData)
169+
local userIdToPriceLevelMap = {}
170+
for _, userData in ipairs(priceLevelData) do
171+
userIdToPriceLevelMap[userData.UserId] = userData.PriceLevel
172+
end
173+
return userIdToPriceLevelMap
174+
end
175+
```
176+
177+
<h5 style={{marginTop: '36px'}}>Example 3: Compare a sender's price level to a recipient's price level</h5>
178+
179+
This example shows you a **sample implementation** of how to check a sender's price level against the recipient's price level. This can help you manage gifting from users in higher-priced regions to users in lower-priced regions.
180+
181+
```lua
182+
-- Get the MarketplaceService
183+
local MarketplaceService = game:GetService("MarketplaceService")
184+
185+
-- Define a function that checks if the sender has a higher or equal price level to the recipient
186+
-- The parameters are the Player sending the item and the Player receiving the item
187+
-- The function returns true if the sender’s price level is greater than or equal to the recipient’s price level
188+
function isSenderPriceLevelHigherOrEqualforGifting(sender, recipient)
189+
local success, priceLevelData = pcall(function()
190+
return MarketplaceService:GetUsersPriceLevelsAsync({ sender.UserId, recipient.UserId })
191+
end)
192+
193+
if not success then
194+
error("MarketplaceService:GetUsersPriceLevelsAsync failed. Unable to retrieve user price levels.")
195+
end
196+
197+
local priceLevelMap = mapUserIdsToPriceLevels(priceLevelData)
198+
local senderPriceLevel = priceLevelMap[sender.UserId]
199+
local recipientPriceLevel = priceLevelMap[recipient.UserId]
200+
201+
return senderPriceLevel >= recipientPriceLevel
202+
end
203+
```
204+
205+
<h5 style={{marginTop: '36px'}}>Example 4: Check if two users have the same price level</h5>
206+
207+
This example shows you a **sample implementation** of how to check if two users have the same price level. This can help you manage trading and ensure a fair exchange between users from different regions
208+
209+
```lua
210+
-- Get the MarketplaceService
211+
local MarketplaceService = game:GetService("MarketplaceService")
212+
213+
-- Define a function that checks if two users have the same price level
214+
-- The parameters are the two users whose price levels you want to compare
215+
-- The function returns true if both users have the same price level
216+
function haveSamePriceLevelForTrading(userA, userB)
217+
local success, priceLevelData = pcall(function()
218+
return MarketplaceService:GetUsersPriceLevelsAsync({ userA.UserId, userB.UserId })
219+
end)
220+
221+
if not success then
222+
error("MarketplaceService:GetUsersPriceLevelsAsync failed. Unable to retrieve user price levels.")
223+
end
224+
225+
local priceLevelMap = mapUserIdsToPriceLevels(priceLevelData)
226+
local userAPriceLevel = priceLevelMap[userA.UserId]
227+
local userBPriceLevel = priceLevelMap[userB.UserId]
228+
229+
return userAPriceLevel == userBPriceLevel
230+
end
231+
```

content/en-us/production/promotion/content-maturity.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Content maturity consists of two components:
1010
- **Content maturity label** - Indicates the level of maturity suitable for the experience according to child development research and industry standards.
1111
- **Content descriptors** - Indicates what type of content is within an experience, such as realistic depictions of blood or paid item trading.
1212

13-
If an experience does not have accurate or all content maturity information, Roblox restricts the playability of the experience on the platform for players younger than 13. In addition, experiences without content maturity information cannot contain any [Restricted content](https://en.help.roblox.com/hc/en-us/articles/15869919570708-Roblox-17-Policy-Standards) without risk of moderation. For this reason, Roblox strongly recommends that you fill out the questionnaire for each of your experiences so that they're available to the largest appropriate audience as possible.
13+
If an experience does not have accurate or all content maturity information, Roblox restricts the playability of the experience on the platform for all players. In addition, experiences without content maturity information cannot contain any [Restricted content](https://en.help.roblox.com/hc/en-us/articles/15869919570708-Roblox-17-Policy-Standards) without risk of moderation. For this reason, Roblox strongly recommends that you fill out the questionnaire for each of your experiences so that they're available to the largest appropriate audience as possible.
1414

1515
<Alert severity="warning">
1616
Content descriptors that generate content maturity labels are separate from [genres](../publishing/experience-genres.md) that classify experiences according to their core gameplay. In cases where there is overlap between genres and in-experience content or behavior, answer the Maturity & Compliance questionnaire as accurately as you can regardless of your genre selection or assignment from Roblox.
@@ -491,7 +491,7 @@ Roblox relies on the information you provide in the Maturity & Compliance Questi
491491
- Roblox provides a moderation action.
492492
- If your experience contains restricted content without a Restricted maturity label, your experience is subject to moderation consequences.
493493
- If your experience contains content that is prohibited by Roblox's [Community Standards](https://en.help.roblox.com/hc/en-us/articles/203313410), [Terms of Use](https://en.help.roblox.com/hc/articles/115004647846), or [Restricted Content Policy](https://en.help.roblox.com/hc/articles/15869919570708), your experience is subject to moderation consequences.
494-
- If your experience otherwise has inaccurate content maturity information according to its content, Roblox may remove the maturity label (or only some or all descriptors if the maturity label is Restricted) from your experience. If an experience does not have content maturity information, Roblox restricts the playability of the experience on the platform for players younger than 13.
494+
- If your experience otherwise has inaccurate content maturity information according to its content, Roblox may remove the maturity label (or only some or all descriptors if the maturity label is Restricted) from your experience. If an experience does not have content maturity information, Roblox restricts the playability of the experience on the platform for all players.
495495
- If you repeatedly include inaccurate content maturity information, **your experience and/or account is subject to moderation consequences**.
496496

497497
If receive a moderation action and believe Roblox made a mistake, you can appeal the decision:

0 commit comments

Comments
 (0)