[Beta] Content Sharing APIs: Use Upload API and Recommendations API to Drive Discovery and Engagement

Hi Creators,

At RDC, we shared our vision for Roblox Moments, a complete ecosystem for user content that transforms how players create, share, and discover experiences. We’re committed to giving you the same tools we used to build the Moments experience itself.

Today, we’re taking the next major step forward by introducing the Upload API (part of CaptureService), the Recommendations API, and the Moments Experience Source Code. This suite of tools is designed to help you build your own in-experience creation and discovery features, driving engagement, retention, and new player growth.

You’ve already started using our foundational APIs (Video Captures API and Share Link API) to capture those epic moments. Now, these new additions close the loop, turning captures into a dynamic, social content reel inside your game. Here’s a breakdown of our full Moments toolkit:

Creator Tool What It Does for Your Game How You Can Use It
Video Captures API Programmatically trigger and capture peak gameplay moments. Automatically record a player’s game-winning goal or a perfect speedrun finish.
Share Link API Create custom deep links to drive targeted re-engagement. Send players directly back to the specific obby level they saw in a shared Moment.
[NEW] Upload API (Beta) Allow users to publish user captured content directly within your experience. After a great fashion show, prompt the user to publish their runway content to your in-game gallery.
[NEW] Recommendations API (Beta) Configure your own recommendation algorithm to highlight relevant content for players right inside your experience. Track its performance in Creator Hub under Recommendation Service. Power your own in-game billboard with a “Highlight Reel” showing the most engaging content from the players in your experience.
[NEW] Moments Source Code Provides a reference for how you can integrate custom, content-based player experiences inside your game. Get a concrete example to inform how you can build and customize your own in-experience content publishing and consumption flow.

New Creator Tools: Closing the Content Sharing Loop

Upload API (Beta)

This API enables users to publish and share their captured content within your experience. No more relying on players leaving the platform to share, the entire creation-to-sharing loop stays in your game, driving more traffic and focus back to your experience.

During Beta, this API will only let players upload captures recorded in your experience. In the future, we will expand the API to support uploads of captures recorded in other experiences.

Click here to view the code snippet
--[[
	Upload API Overview

	The Upload API describes a set of functions added to CaptureService that allow the retrieval and upload of a user's captures.

	Key Features:
	- Request permissions to view and upload a user's captures
	- Fetch captures from gallery
	- Upload capture to the asset system

	At the moment, only captures taken in the current experience can be retrieved and uploaded.
]]

local CaptureService = game:GetService("CaptureService")

-- ============================================================================
-- STEP 1: Request permission
-- ============================================================================

local accepted = CaptureService:PromptCaptureGalleryPermissionAsync(Enum.CaptureGalleryPermission.ReadAndUpload)

-- ============================================================================
-- STEP 2: Fetch captures from gallery
-- ============================================================================

local allCaptures = {}
if accepted then
	local capturesPages
	local success, result = pcall(function()
		local readResult, pages = CaptureService:ReadCapturesFromGalleryAsync()
		if readResult == Enum.ReadCapturesFromGalleryResult.Success then
			capturesPages = pages
		end
		return readResult
	end)

	if not success or result ~= Enum.ReadCapturesFromGalleryResult.Success then
		warn("Failed to fetch initial captures: " .. result)
		return
	end

	-- Iterate through current page
	local currentPage = capturesPages:GetCurrentPage()

	for _, capture in currentPage do
		table.insert(allCaptures, capture)
	end

	-- Advance to next page until finished
	while not capturesPages.IsFinished do
		local advanceToNextPageSuccess, _ = pcall(function()
			capturesPages:AdvanceToNextPageAsync()
		end)

		if not advanceToNextPageSuccess then
			return
		end

		currentPage = capturesPages:GetCurrentPage()
		for _, capture in currentPage do
			table.insert(allCaptures, capture)
		end
	end
end

-- ============================================================================
-- STEP 3: Upload a capture
-- ============================================================================

-- Here, we'd likely want to show the user's captures to them and prompt them to upload one, but for the example, we can take the first capture in the list.

if #allCaptures > 0 then
	local capture = allCaptures[1]
	local success, result = pcall(function()
		-- This step may take a few minutes
		local uploadCaptureResult, assetId = CaptureService:UploadCaptureAsync(capture)

		if uploadCaptureResult ~= Enum.UploadCaptureResult.Success then
			-- Handle failure
			return nil
		end

		return assetId
	end)

	if not success then
		-- Handle error
	end

	-- Now we can use the returned asset in-experience
end

Example Use Case: A competitive game uses the Upload API to allow players to instantly submit their “Play of the Game” video to an in-game leaderboard or community feed after a match ends.


Recommendations API (Beta)

This is the engine for in-experience discovery. Built from similar tech behind Roblox’s Home Discovery, integrate your own content recommendations right into your experience. Use this API to rank any content within your experience, giving you full control over how it’s displayed to maximize player engagement and retention. Once set up, track and optimize performance within Creator Hub under Recommendation Service!

Click here to view the code snippet
--[[
	RecommendationService API Overview

	RecommendationService is a content-agnostic service that helps you create personalized recommendation
	systems for your Roblox experience. It handles the complex logic of ranking and ordering content
	based on user behavior, while you focus on defining what content to recommend.

	Key Features:
	- Register items to be recommended (games, assets, experiences, etc.)
	- Generate personalized recommendation lists for users
	- Log user interactions to improve recommendation quality over time

	Typical Workflow:
	1. Register items that you want to recommend to users
	2. Generate recommendation lists when users need them
	3. Log user interactions (views, clicks, reactions) as they happen
	4. Repeat steps 2-3 to continuously improve recommendations

	This service is flexible and can be used for various recommendation scenarios.
]]

local RecommendationService = game:GetService("RecommendationService")
local replicatedStorage = game:GetService("ReplicatedStorage")

-- ============================================================================
-- STEP 1: REGISTER ITEMS
-- ============================================================================
-- Before you can recommend items, you need to register them with the service.
-- You'll need a RemoteFunction to allow clients to request item registration.

-- Assume a RemoteFunction named 'RegisterItemRemote' exists in ReplicatedStorage
local registerItemRemote = replicatedStorage.RegisterItemRemote

registerItemRemote.OnServerInvoke = function(player, refId)
	-- Create a registration request with item details
	local request: RegisterRecommendationItemRequest = {
		-- ContentType gives a hint on the content:
		-- - Dynamic: Videos
		-- - Static: Images
		-- - Interactive: Games, 3D models, etc.
		ContentType = Enum.RecommendationItemContentType.Dynamic,

		-- ReferenceId is your unique identifier for this item.
		-- This links the recommendation system to your own data storage.
		-- Store additional metadata in your DataStore; RecommendationService only
		-- stores recommendation-related data.
		ReferenceId = refId,

		-- Duration in seconds. How long is this content.
		Duration = 60,

		-- Visibility controls who can see this item:
		-- - Public: Visible to all users
		-- - Private: Only visible to the creator.
		Visibility = Enum.RecommendationItemVisibility.Public,

		-- CustomTags help categorize and filter items (e.g., language, season, genre)
		-- These can be used to boost certain items in recommendations
		CustomTags = {"locale:en-us", "seasonal:summer"},
	}

	-- Register the item with error handling
	local success, response = pcall(function()
		return RecommendationService:RegisterItemAsync(player, request)
	end)

	if success and response then
		print("Successfully registered item. ItemId: " .. response.ItemId)
		-- The service returns an ItemId that you'll use for future operations
		return response.ItemId
	else
		warn("Failed to register item. Error: " .. tostring(response))
		return nil
	end
end

-- ============================================================================
-- STEP 2: GENERATE RECOMMENDATION LISTS
-- ============================================================================
-- Once items are registered, you can generate personalized recommendation lists.
-- This can be called from either client or server scripts, depending on your needs.

-- Define the request parameters for generating recommendations
local request: GenerateRecommendationItemListRequest = {
	-- ConfigName: The recommendation strategy/algorithm to use
	ConfigName = "MaximizeEngagement",

	-- LocationId: Where in your experience these recommendations will be shown.
	-- It will not affect the recommendation results, but their performance metrics will be shown separately in the Creator Hub.
	LocationId = "Lobby",

	-- PageSize: Number of items to return per page.
	PageSize = 10
}

-- Generate the recommendation list (returns a paginated result)
local success, recommendationPages = pcall(function()
	return RecommendationService:GenerateItemListAsync(request)
end)

if success then
	-- Get the first page of recommended items
	local currentPage = recommendationPages:GetCurrentPage()

	-- Iterate through the recommended items
	for _, item in ipairs(currentPage) do
		print("ItemId: " .. item.ItemId)           -- Service-generated unique ID
		print("  ReferenceId: " .. item.ReferenceId)  -- Your original identifier
		print("  TracingId: " .. item.TracingId)     -- Use this when logging interactions

		-- Use the ReferenceId to look up full item details from your DataStore
		-- Use the TracingId when logging user interactions (see Step 3)
	end

	-- To get more items, you can call:
	-- recommendationPages:AdvanceToNextPageAsync()
	-- local nextPage = recommendationPages:GetCurrentPage()
else
	warn("Failed to generate recommendations: " .. tostring(recommendationPages))
end

-- ============================================================================
-- STEP 3: LOG USER INTERACTIONS
-- ============================================================================
-- Logging user interactions helps the recommendation system learn what users like
-- and improves future recommendations. This should be done from a client script
-- when users interact with recommended items.

-- Log when a user views a recommended item (impression event)
local impressionDetail: RecommendationImpressionEventDetails = {
	-- Duration: How long the user viewed the item (in seconds)
	Duration = 5,

	-- ItemPosition: Where the item appeared in the list (1 = first item, 2 = second, etc.)
	-- Helps the system understand which positions get more attention
	ItemPosition = 1,

	-- DepartureIntent: How the user left the item
	-- - Positive: User engaged positively (e.g., clicked, liked)
	-- - Neutral: User scrolled past
	-- - Negative: User dismissed or skipped
	DepartureIntent = Enum.RecommendationDepartureIntent.Neutral
}

-- Log the view event
-- Parameters: event type, itemId from recommendation, tracingId from recommendation, details
RecommendationService:LogImpressionEvent(
	Enum.RecommendationImpressionType.View,
	"itemId",      -- Use item.ItemId from the recommendation list
	"tracingId",   -- Use item.TracingId from the recommendation list
	impressionDetail
)

-- Log when a user takes an action on a recommended item (action event)
local actionDetail: RecommendationActionEventDetails = {
	-- ReactionType: Type of action taken (e.g., "Like", "Thumb up")
	-- This is a string you define based on your experience's actions
	ReactionType = "Like"
}

-- Log the action event
-- Parameters: action type, itemId, tracingId, details
RecommendationService:LogActionEvent(
	Enum.RecommendationActionType.AddReaction,
	"itemId",      -- Use item.ItemId from the recommendation list
	"tracingId",   -- Use item.TracingId from the recommendation list
	actionDetail
)

-- The more data you log, the better your recommendations will become over time

Example Use Case: A car racing experience uses the Recommendations API to display the fastest laps and coolest overtakes as a dynamic highlight reel on jumbotrons around the track, inspiring others to try and beat the record.


Moments Experience Source Code

We’re giving you the full Moments source code. To access the source code, go to the Roblox Moments experience and click the three dot menu > “Edit in Studio”. This provides a reference for the entire Moments workflow – capture, editing, and publishing. This gives you a concrete example on how to create a content sharing feature that matches your own experience’s style and needs.

Example Use Case: For a fashion experience, you can reference how the Moments experience empowers players to creatively edit their captures, and integrate relevant editing functionality into your own experience, making self-expression a core part of how your players publish their unique looks.

Technical Details & Get Started

All of these APIs and the Source Code are available now!

Foundation APIs:

Here is comprehensive documentation and availability updates for the Upload API, Recommendations API, and the Moments Source Code.

Amplify Your Experience and Drive Discovery

We’ve given you the tools; now we invite you to push the boundaries of creativity. We are already actively exploring how user-generated content can further enrich the platform, and you can expect future updates that will expand what’s possible with the Moments ecosystem.

We can’t wait to see the creative ways you innovate with these tools. Share your feedback and ideas below!

Thank you,

@corepcgamer, Moments Product Lead, Roblox User Team


FAQs

Will voice ever be available to record in Moments?

  • Currently, shared Moments videos include some in-experience audio (sound effects, music) but do not record voice communication for safety and privacy reasons. We continuously evaluate our platform capabilities and will share updates here if any changes to audio recording policies are planned for the future.

As a creator, can I control what content is recommended through the Recommendations API?

  • Yes. The power of the Recommendations API is in the control it gives you. You can select how content is ranked, fully customize its display, and eventually personalize for your individual players within your experience. For more details on how to implement this, check out our documentation.

As a creator, will I be penalized/moderated for content surfaced through the Recommendations API?

  • No, you will not be penalized for content that is surfaced through a reel you build using the Recommendations API. All captured and published content, whether shared in the main Moments experience or through your custom in-experience systems, is subject to proactive moderation before publication to ensure it complies with Community Standards.

Will my experience be restricted to 13+ when implementing Upload API?

  • At this time, your experience’s content maturity label will not be impacted. In the future, we’ll add cross-experience upload support. If you call the Upload API for users to upload media from other experiences, then you must answer “yes” to “Cross-Experience Content”, and the experience will receive a ‘Moderate’ content maturity label and be age-gated to 13+.
44 Likes

This topic was automatically opened after 11 minutes.

this is amazing! i love it and im gonna use it

4 Likes

This is a very good update I looked through the upload api and its useful
But when I click Roblox moments game page to edit it , it says page not found

1 Like

(It’s too early.)

Too early for what the Roblox moments isn’t available ?

Yay, more doom scrolling. :smiley:

1 Like

Why is RecommendationService kind of cool? Can’t wait to prototype a lot of stupid ideas with it!

Do you only answer yes when both conditions are true? For example, if we use the recommendations API for a list of purchasable items, the answer would be no?

This is great and what I’ve been waiting for but we still need IsMutedForCapture of sound instances to not be Roblox script only

Could these “Clips” Be utilized by the game itself as resources to make “Video Tutorials” for the players? Instead of needing to pay a constant 2000 Robux per individual Videos before?

1 Like

Custom algorithms in Roblox is amazing but for full applications you would probably still need an external database

Good point. Moments, for example, uses the creator datastore and memory stores as the data storage.

2 Likes

what happen if i try to do background music ads video

Apologies for the confusion! Please answer “yes” if either conditions are true. We’ve updated the copy to reflect this.


I can’t even view the game page for Moments without using a VPN.
I’m age-verified as 18+, so there shouldn’t be anything I’m blocked from.

1 Like

There are certain countries for which Moments is not available, which might explain why connecting to vpn solves it.

I know this is my 3rd post, BUT will this matury label be enforced if the client uploading is the ONLY client that is going to view the video (e.g., server size is 1, the game is a Video Capture editor)?

Hi there, the question is if other users can see what someone is uploading. If that’s true, this label will be enforced. In your case, it sounds like other users would not be able to view what a user is uploading, right?

ok that’s actually cool