I have a script I made a while back that prints them in the Studio output with CSV format. It might be a little wonky but it worked for me.
Unfortunately for these scripts I made you do need to verify with your Roblox cookie through a public proxy, hence why I made a throwaway account with analytics permissions, so in the event it’s used maliciously, little harm would be done. I highly recommend you do the same as well as public proxies aren’t guaranteed to be safe.
Both scripts require this ‘Proxy’ module, so as long as you have some knowledge to tweak values and paths you should be able to figure it out hopefully!
Proxy
--> Services
local HttpService = game:GetService("HttpService")
--> Configuration
local Cookie = "PASTE-COOKIE-HERE-JUST-THE-LETTERS"
--> Variables
local Headers = {
Cookie = `.ROBLOSECURITY={Cookie}`
}
--------------------------------------------------------------------------------
-- 401 = Invalid Cookie
-- 403 = Token Validation Failure
local function Reauthenticate()
while true do
local Success, Response = xpcall(function()
return HttpService:RequestAsync({
Method = "POST",
Url = `https://auth.roproxy.com`,
Headers = Headers
})
end, warn)
if Success and Response.StatusCode == 403 then
print("Authenticated!")
Headers["x-csrf-token"] = Response.Headers["x-csrf-token"]
break
else
warn("Unknown error occurred. Retrying in 3 seconds.")
warn(Response)
task.wait(3)
end
end
end
---- EXPOSED API ---------------------------------------------------------------
local Proxy = {}
function Proxy:MakeRequest(Method: string?, Url: string)
while true do
local Success, Response = xpcall(function()
return HttpService:RequestAsync({
Method = Method,
Url = Url,
Headers = Headers
})
end, warn)
if not Success or not Response.Success then
if Response.StatusCode == 403 then
print("Request doesn't have a valid token! Authenticating...")
Reauthenticate()
task.wait(1)
else
warn("Unknown error occurred. Retrying in 3 seconds.")
print(Response.Body)
task.wait(3)
end
else
return Response.Body
end
end
end
return Proxy
Get Legacy Developer Stats (Division: Age)
Summary
--> Services
local ServerStorage = game:GetService("ServerStorage")
local HttpService = game:GetService("HttpService")
--> Dependencies
local Proxy = require(game:GetService("ServerStorage").Proxy)
--> Configuration
local placeId = 380305410
--------------------------------------------------------------------------------
local Months = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}
local function GetMonthFromIsoDate(IsoDate: string): number
return DateTime.fromIsoDate(IsoDate):ToUniversalTime().Month
end
local function GetPage(Start: DateTime, End: DateTime)
local Response = Proxy:MakeRequest("GET", `https://develop.roproxy.com/v1/places/{placeId}/stats/Visits?granularity=Daily&divisionType=Age&startTime={Start:ToIsoDate()}&endTime={End:ToIsoDate()}`)
return HttpService:JSONDecode(Response)
end
local function GetValue(t, isoDate: string): number|string
if t then
for _, Value in t do
if Value[1] == isoDate then
return Value[2]
end
end
end
return ""
end
local LastDay = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
for _, Year in {2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023} do
for Month = 1, 12 do
local isLeapMonth = (Month == 2) and (Year % 4 == 0)
local Start = DateTime.fromUniversalTime(Year, Month)
local End = DateTime.fromUniversalTime(Year, Month, LastDay[Month] + (isLeapMonth and 1 or 0))
local Page = GetPage(Start, End)
warn(`{Start:ToIsoDate()} ::: {End:ToIsoDate()}`)
-- Sort data into arrays
local arrays = {}
for _, Category in Page.data do
local t = {}
for date, value in Category.data do
table.insert(t, {DateTime.fromUnixTimestampMillis(tonumber(date)):ToIsoDate(), value})
end
table.sort(t, function(A, B)
return A[1] < B[1]
end)
arrays[Category.type] = t
end
-- Log
for n, totalData in arrays.Total do
local IsoDate = totalData[1]
local placeId = Page.placeId
local Total = arrays.Total[n][2]
local SixOrUnder = GetValue(arrays.SixOrUnder, IsoDate)
local SevenAndEight = GetValue(arrays.SevenAndEight, IsoDate)
local NineAndTen = GetValue(arrays.NineAndTen, IsoDate)
local ElevenAndTwelve = GetValue(arrays.ElevenAndTwelve, IsoDate)
local ThirteenToFifteen = GetValue(arrays.ThirteenToFifteen, IsoDate)
local SixteenAndSeventeen = GetValue(arrays.SixteenAndSeventeen, IsoDate)
local EighteenOrOver = GetValue(arrays.EighteenOrOver, IsoDate)
print(`{IsoDate},{placeId},{Total},{SixOrUnder},{SevenAndEight},{NineAndTen},{ElevenAndTwelve},{ThirteenToFifteen},{SixteenAndSeventeen},{EighteenOrOver}`)
end
task.wait(2)
end
end
Get Legacy Developer Stats (Division: Device)
Summary
--> Services
local ServerStorage = game:GetService("ServerStorage")
local HttpService = game:GetService("HttpService")
--> Dependencies
local Proxy = require(game:GetService("ServerStorage").Proxy)
--> Configuration
local placeId = 380305410
--------------------------------------------------------------------------------
local Months = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}
local function GetMonthFromIsoDate(IsoDate: string): number
return DateTime.fromIsoDate(IsoDate):ToUniversalTime().Month
end
local function GetPage(Start: DateTime, End: DateTime)
local Response = Proxy:MakeRequest("GET", `https://develop.roproxy.com/v1/places/{placeId}/stats/Visits?granularity=Daily&divisionType=Device&startTime={Start:ToIsoDate()}&endTime={End:ToIsoDate()}`)
return HttpService:JSONDecode(Response)
end
local function GetValue(t, isoDate: string): number|string
if t then
for _, Value in t do
if Value[1] == isoDate then
return Value[2]
end
end
end
return ""
end
local LastDay = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
for _, Year in {2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023} do
for Month = 1, 12 do
local isLeapMonth = (Month == 2) and (Year % 4 == 0)
local Start = DateTime.fromUniversalTime(Year, Month)
local End = DateTime.fromUniversalTime(Year, Month, LastDay[Month] + (isLeapMonth and 1 or 0))
local Page = GetPage(Start, End)
warn(`{Start:ToIsoDate()} ::: {End:ToIsoDate()}`)
-- Sort data into arrays
local arrays = {}
for _, Category in Page.data do
local t = {}
for date, value in Category.data do
table.insert(t, {DateTime.fromUnixTimestampMillis(tonumber(date)):ToIsoDate(), value})
end
table.sort(t, function(A, B)
return A[1] < B[1]
end)
arrays[Category.type] = t
end
-- Log
for n, totalData in arrays.Total do
local IsoDate = totalData[1]
local placeId = Page.placeId
local Total = arrays.Total[n][2]
local Computer = GetValue(arrays.Computer, IsoDate)
local Tablet = GetValue(arrays.Tablet, IsoDate)
local Phone = GetValue(arrays.Phone, IsoDate)
local Console = GetValue(arrays.Console, IsoDate)
print(`{IsoDate},{placeId},{Total},{Computer},{Tablet},{Phone},{Console}`)
end
task.wait(2)
end
end
Both scripts print out a CSV format like the one shown below. By importing it into excel (just save it into a notepad as .csv, but you may be able to paste this format into a .csv file itself), it’ll have each column represent the values that print at the bottom, and each row the day. Make sure to hide the warnings too if you wish.
Make sure to disable the timestamp/sources in the output settings to make this easier to copy & paste! For example, the format shown below is:
Date,PlaceId,Total,SixOrUnder,SevenAndEight,NineAndTen,ElevenAndTwelve,ThirteenToFifteen,SixteenAndSeventeen,EighteenOrOver
If your game is old enough, some columns/values may be empty due to Roblox not implementing sources like breakdown by age yet. This is normal.
Finally, both scripts are printing out Visits at a granularity of Daily. You can change the source to any available, but I didn’t make these to support other granularities - so unfortunately getting Hourly may be a hassle, even though you don’t really need it. Monthly can be calculated pretty easily. Also, Revenue is gross revenue - unlike the new dashboard which shows net revenue (after marketplace/commission fees).