Install in Roblox Studio
Add the RoChart module to your game, record purchases, send your own events — and send data from websites, bots and backends too.
Let your coding agent do it. It sets up the module in your server code, wraps ProcessReceipt, adds your key events and tells you how to check they arrive.
The RoChart module runs on the game server only. It sends events with HttpService, batched, so nothing runs on players' devices except a tiny script that reports their platform. You need your project token (rc_…) from Project settings → Data collection. The token can only send events and read flags. Never put a secret API key (rc_sk_…) in your game.
Set up the module
Allow HTTP requests
Game Settings → Security → Allow HTTP Requests, then publish. Without it, every request fails and nothing arrives.
Put RoChart in ServerScriptService
Get the RoChart ModuleScript from Project settings → Data collection and insert it into ServerScriptService. Keep it on the server: ModuleScripts in ReplicatedStorage are visible to clients.
Start it
In a Script in ServerScriptService, require the module and call init once, as early as possible:
local RoChart = require(game.ServerScriptService.RoChart)
RoChart.init({
token = "rc_your_project_token",
host = "https://app.rochart.co",
})What it sends on its own
| Event | When |
|---|---|
$session_start | A player joins. Carries the join source, campaign, account age, Premium, server type and place version. |
$session_end | A player leaves, or the server shuts down. Carries $duration in seconds. |
$server_heartbeat | Every 60 seconds per running server, with the player count and server health: FPS, memory, heartbeat time and the players' average ping. Concurrent players are built from it, and a server whose heartbeats stop without a shutdown counts as a crash. |
$server_shutdown | The server closes (BindToClose). |
$error | A script error, on the server or on a player's device. Identical errors are grouped for up to a minute and sent once with a $count. At most 30 per server per minute. |
$purchase | A developer product is granted through processReceipt, or a game pass is bought in-game. |
$feature_flag_called | A flag was read for a player. |
Every player event carries the session, server, place, platform (Computer, Phone, Tablet, Console, VR), country and locale. Each player is a person in RoChart, keyed by their UserId, with their name, display name, account age, Premium, country and platform as properties. See Players and properties.
Roblox doesn't give games age or gender, so RoChart doesn't have them either. The full contract is in Game analytics.
Record purchases
Roblox lets a game set MarketplaceService.ProcessReceipt only once. Hand your callback to RoChart instead, and it records a $purchase with the Robux amount whenever you return PurchaseGranted:
RoChart.processReceipt(function(receiptInfo)
local player = game.Players:GetPlayerByUserId(receiptInfo.PlayerId)
if not player then
return Enum.ProductPurchaseDecision.NotProcessedYet
end
grantProduct(player, receiptInfo.ProductId) -- your code
return Enum.ProductPurchaseDecision.PurchaseGranted
end)Game passes bought in-game are recorded without any extra code.
Send your own events
RoChart.track(player, "match_ended", { mode = "duos", placement = 2, kills = 4, duration = 312 })
RoChart.track(player, "tutorial_step", { step = 3, name = "equip_sword" })
RoChart.trackServer("round_started", { map = "Volcano", players = #game.Players:GetPlayers() })track(player, …)is for something a player did. It's attached to that player and their session.trackServer(…)is for something the server did, such as a round starting or a boss spawning. It doesn't belong to any player.
Name events after what happened, in snake_case and past tense: quest_completed, pet_hatched, round_won. Put variants in properties, so one quest_completed with quest = "dragon" instead of dragon_quest_completed. Send numbers as numbers (kills = 4, not "4") so you can sum and average them.
Set your own player properties, such as level or the team they picked:
RoChart.setUserProperties(player, { level = 12, class = "mage" })Economy, funnels and live config
Record in-game currency the way Roblox's AnalyticsService:LogEconomyEvent does, so you can see where it comes from and where it goes:
RoChart.economy(player, { flow = "source", currency = "Gold", amount = 50, balance = gold, transactionType = "Gameplay", itemSku = "match_reward" })
RoChart.economy(player, { flow = "sink", currency = "Gold", amount = 300, balance = gold, transactionType = "Shop", itemSku = "artillery" })Mark the steps of a funnel. A funnel the player can go through again, such as a shop visit, takes an id per visit:
RoChart.funnelStep(player, "onboarding", 2, "Picked country")
local visit = HttpService:GenerateGUID(false)
RoChart.funnelStep(player, "shop", 1, "Opened shop", visit)
RoChart.funnelStep(player, "shop", 2, "Viewed item", visit)Tune the game without publishing: give a flag a JSON payload per variant and read it with getConfig:
local prices = RoChart.getConfig(player, "shop-prices") or { artillery = 300 }Player feedback
Send what players tell you to Feedback:
RoChart.feedback(player, message, { rating = 4, category = "bug", board = "bugs" })Or turn on the built-in button with feedbackButton = true in init. It shows a small Feedback tab on the right edge of the screen with a 1–5 rating and a text box.
All functions are in the SDK reference.
Check that it works
Start a server and join. Open Live: you should see $server_heartbeat right away and your own $session_start within five seconds. If nothing arrives, check the server output (Developer Console → Server in a live game) for errors, that Allow HTTP Requests is on for the published place, and that the token is your project's.
Websites, Discord bots and backends
The same project can take events from outside the game, such as your game's website, a Discord bot or a backend that grants rewards. Use the same distinct_id as the game, the player's UserId as a string, so it lands on the same player.
<script src="https://app.rochart.co/sdk/rochart.min.js"></script>
<script>
rochart.init('rc_your_project_token', { host: 'https://app.rochart.co' })
</script>This captures pageviews, sessions, referrers and UTM campaigns. See the SDK reference.