A Luau SDK for the AudioScape Developer API — search, browse, discover music, and track analytics for your Roblox experiences.
Note: This SDK uses
HttpService:RequestAsync()and must run on the server (Script, not LocalScript). You must enable Allow HTTP Requests in your experience's Game Settings → Security.
Add to your wally.toml:
[dependencies]
AudioScape = "this-fifo/audioscape-sdk@0.3.0"Then run:
wally installSince the SDK realm is server, Wally installs it to ServerScriptService.Packages (or your configured server packages location).
Download AudioScape.rbxm from the latest release and drop it into ServerStorage or ServerScriptService in Roblox Studio.
Copy src/init.luau into your project under ServerStorage or ServerScriptService. If using Rojo, add it to your server-side project tree.
- Enable HTTP Requests — In Roblox Studio, go to Game Settings → Security → Allow HTTP Requests and turn it on.
- API Key — Get your key at developer.audioscape.ai. Use the Roblox Secrets Store to securely store your key in production.
local ServerStorage = game:GetService("ServerStorage")
local HttpService = game:GetService("HttpService")
local RunService = game:GetService("RunService")
local AudioScape = require(ServerStorage.AudioScape)
-- Use a test key in Studio, Secrets Store in production
local apiKey = if RunService:IsStudio()
then "your-test-key"
else HttpService:GetSecret("AudioScapeKey")
local client = AudioScape.new(apiKey)
-- Search for music
local result, err = client:search({ query = "chill lo-fi beats", limit = 10 })
if result then
for _, track in result.tracks do
print(track.artist, "-", track.name)
end
endThe SDK automatically sends your game's Universe ID and Place ID with every request to help you track usage across your experiences. You can also pass an optional playerId to tie requests to specific players:
local result, err = client:search({
query = "epic battle music",
playerId = player.UserId,
})Creates a new client instance.
local client = AudioScape.new("your-api-key")Search the catalog using natural language.
local result, err = client:search({
query = "epic orchestral battle music", -- required
limit = 20, -- optional (default: 20, max: 100)
offset = 0, -- optional
playerId = player.UserId, -- optional
filters = { -- optional
genres = { "electronic", "pop" },
duration = { min = 60, max = 180 },
},
})
-- result = { tracks, artists, albums, meta }Find tracks that sound similar to a given track.
local result, err = client:similar({
asset_id = "123456789", -- required
limit = 10, -- optional
offset = 0, -- optional
playerId = player.UserId, -- optional
})
-- result = { tracks, meta }Browse by artist, album, genre, or mood.
-- List all genres
local result, err = client:browse({ type = "genre" })
-- result = { items, meta }
-- Get tracks for a specific genre
local result, err = client:browse({ type = "genre", name = "electronic", limit = 20 })
-- result = { tracks, meta }Browse types: artist, album, genre, mood
Configure analytics batching behavior. Call before tracking events.
client:configureAnalytics({
enabled = true, -- default: true
batchInterval = 30, -- seconds between flushes (min: 5)
maxBatchSize = 50, -- events per flush (1-500)
maxQueueSize = 500, -- max buffered events (min: 10)
})Track a song play event.
client:trackPlay("rbxassetid://123456789", player.UserId, 120)Track a song stop event (natural end or user action).
Track a song skip event. Duration is how long the player listened before skipping.
Track a vote. Value must be "up" or "down".
client:trackVote("rbxassetid://123456789", "up", player.UserId)Track a favorite event.
Track an unfavorite event.
Track when a player adds a song to a queue, setlist, or playlist.
Track when a player clicks a search result.
Track a custom event with any type name.
client:trackCustom("song_previewed", assetId, player.UserId, {
source = "browse_genre",
position = 3,
})Force flush all buffered events immediately. Called automatically on game close.
Analytics are collected automatically — events are buffered in memory and flushed every 30 seconds (configurable). On game close, remaining events are flushed via game:BindToClose. No player PII is stored; playerId is used only for unique player counts.
Roblox enforces a limit of 500 HTTP requests per minute per game server. Keep this in mind when designing your integration — consider caching results and debouncing player-triggered searches.
All methods return result, err. On failure, result is nil and err is a descriptive string:
local result, err = client:search({ query = "test" })
if not result then
warn("Search failed:", err)
return
endSee the examples/ folder for complete usage examples:
- SearchBox.luau — Wire search to a TextBox input
- BrowseGenres.luau — List genres and play a random track
- SimilarTrack.luau — Auto-playlist using similar tracks
MIT