Hi all!
Just got a working example of telemetry for a Playdate game. I literally just got it working and it's not yet in production, but given the lack of examples I reckon it wouldn't hurt to put it out there. ![]()
It's using a single-file module, called TelemetryHandler. Here's the code:
TelemetryHandler.lua
local http <const> = playdate.network.http
TelemetryHandler = {
isAccessGranted = false,
url = nil,
path = nil,
httpTelemetry = nil,
permissionReasonMessage = nil
}
local calls <const> = {}
function TelemetryHandler.create(url, path, permissionReasonMessage)
TelemetryHandler.url = url
TelemetryHandler.path = path
TelemetryHandler.permissionReasonMessage = permissionReasonMessage
end
function TelemetryHandler.update()
if #calls > 0 then
-- Pop latest "call" on stack
local call = table.remove(calls)
call()
end
end
local function _requestPermissionsAccess()
local accessGranted = http.requestAccess(TelemetryHandler.url, nil, true, TelemetryHandler.permissionReasonMessage)
TelemetryHandler.isAccessGranted = accessGranted
end
function TelemetryHandler.requestAccess()
table.insert(calls, _requestPermissionsAccess)
end
local function _sendTelemetryData(data)
if not TelemetryHandler.isAccessGranted then
return
end
if not TelemetryHandler.httpTelemetry then
TelemetryHandler.httpTelemetry = http.new(TelemetryHandler.url, 443, true,
TelemetryHandler.permissionReasonMessage)
end
local request, error = TelemetryHandler.httpTelemetry:post(TelemetryHandler.path,
{
["Authorization"] = "Bearer " .. SUPABASE_ANON_KEY,
["Content-Type"] = "application/json"
},
json.encode(data))
if error then
print("Error occurred making Telemetry call: " .. error)
else
print("Telemetry call in progress...")
end
TelemetryHandler.httpTelemetry:setHeadersReadCallback(function()
print("Telemetry call finished with status code: " .. TelemetryHandler.httpTelemetry:getResponseStatus())
end)
TelemetryHandler.httpTelemetry:setRequestCallback(function()
print("Request complete")
local bytes = TelemetryHandler.httpTelemetry:getBytesAvailable()
if bytes > 0 then
print("Response: " .. TelemetryHandler.httpTelemetry:read(bytes))
end
end)
TelemetryHandler.httpTelemetry:setRequestCompleteCallback(function()
local error = TelemetryHandler.httpTelemetry:getError()
if error then
print("Error returned from Telemetry call: " .. error)
else
local bytes = TelemetryHandler.httpTelemetry:getBytesAvailable()
print("Response: " .. TelemetryHandler.httpTelemetry:read(bytes))
end
end)
end
---comment
---@param data table
function TelemetryHandler.send(data)
table.insert(calls, function()
playdate.network.setEnabled(true, function(error)
if error then
print("Error occurred enabling network: " .. error)
else
print("Network connection status: " .. playdate.network.getStatus())
table.insert(calls, function() _sendTelemetryData(data) end)
end
end)
end)
end
On top of adding this file to your project, you'll need a back-end to handle your requests. I'll post my setup on Supabase (an open-source, highly advanced Backend-as-a-service/firebase alternative) which you can use as well. Setup steps will be in the next comment in the thread.
The usage is as follows:
_First, make sure the file is imported into your project, in main.lua or other.
import "path/to/TelemetryHandler"
Setup:
TelemetryHandler.create(
"your.backend.com", -- Your back-end domain
"/telemetry", -- Request path
-- "Reason" message when Playdate prompts for network permission access.
"This game is still in early-access. We would like to monitor the difficulty of puzzles to ensure a smooth difficulty curve."
)
Sending telemetry:
if not TelemetryHandler.isAccessGranted then
TelemetryHandler.requestAccess()
end
TelemetryHandler.send(
-- Whatever payload you want in here! :)
{
game_id = "Test123",
world_name = worldCurrent.filepath,
level_name = currentLevelName,
rescue_bot = botNumber,
key_config = "LRR",
playtime_seconds = 1000
})
Edit: I forgot to mention - the TelemetryHandler doesn't directly call the HTTP or Networking methods, instead it places them on a stack (call) which should execute in playdate.update!
So don't forget to add this to your playdate.update / main.lua:
function playdate.update()
...
TelemetryHandler.update()
end


