Networking Examples
Real-world examples of integrating external APIs, webhooks, and services with your Roblox game using Raddish.
Discord Logging System
Send game events to Discord for monitoring and moderation.
lua
local Raddish = require(game.ReplicatedStorage.Raddish)
-- Configuration
local WEBHOOKS = {
logs = "https://discord.com/api/webhooks/YOUR_LOG_WEBHOOK_ID/TOKEN",
moderation = "https://discord.com/api/webhooks/YOUR_MOD_WEBHOOK_ID/TOKEN",
trading = "https://discord.com/api/webhooks/YOUR_TRADE_WEBHOOK_ID/TOKEN",
admin = "https://discord.com/api/webhooks/YOUR_ADMIN_WEBHOOK_ID/TOKEN"
}
-- Log levels with colors
local LOG_COLORS = {
INFO = 0x0099FF,
SUCCESS = 0x00FF00,
WARNING = 0xFFAA00,
ERROR = 0xFF0000,
CRITICAL = 0x800000
}
-- Generic logging function
function logToDiscord(webhook, level, title, description, fields)
Raddish.SendDiscordWebhook(webhook, {
title = "**[" .. level .. "]** " .. title,
description = description,
color = LOG_COLORS[level] or 0x808080,
fields = fields or {},
footer = {
text = "Server: " .. game.JobId .. " | " .. os.date("%Y-%m-%d %H:%M:%S")
},
username = "Game Logger",
avatar_url = "https://example.com/bot-avatar.png"
})
end
-- Player join logging
game.Players.PlayerAdded:Connect(function(player)
logToDiscord(WEBHOOKS.logs, "INFO", "Player Joined", player.Name .. " joined the game", {
{name = "User ID", value = tostring(player.UserId), inline = true},
{name = "Account Age", value = tostring(player.AccountAge) .. " days", inline = true},
{name = "Display Name", value = player.DisplayName, inline = true}
})
end)
-- Suspicious activity detection
function reportSuspiciousActivity(player, reason, details)
logToDiscord(WEBHOOKS.moderation, "WARNING", "Suspicious Activity Detected",
"Player: " .. player.Name,
{
{name = "User ID", value = tostring(player.UserId), inline = true},
{name = "Reason", value = reason, inline = true},
{name = "Details", value = details, inline = false},
{name = "Account Age", value = tostring(player.AccountAge) .. " days", inline = true}
}
)
end
-- Example: Speed hack detection
game.Players.PlayerAdded:Connect(function(player)
player.CharacterAdded:Connect(function(character)
local humanoid = character:WaitForChild("Humanoid")
humanoid:GetPropertyChangedSignal("WalkSpeed"):Connect(function()
if humanoid.WalkSpeed > 16 then
reportSuspiciousActivity(player, "Speed Hack",
"WalkSpeed set to " .. humanoid.WalkSpeed
)
end
end)
end)
end)
-- Trade logging
function logTrade(player1, player2, item, amount)
logToDiscord(WEBHOOKS.trading, "SUCCESS", "Trade Completed",
player1.Name .. " traded with " .. player2.Name,
{
{name = "Player 1", value = player1.Name, inline = true},
{name = "Player 2", value = player2.Name, inline = true},
{name = "Item", value = item, inline = true},
{name = "Amount", value = tostring(amount), inline = true}
}
)
end
-- Error logging
function logError(errorMessage, stackTrace)
logToDiscord(WEBHOOKS.admin, "ERROR", "Script Error",
"An error occurred in the game",
{
{name = "Error", value = errorMessage, inline = false},
{name = "Stack Trace", value = "```" .. stackTrace .. "```", inline = false}
}
)
end
-- Server crash logging
game:BindToClose(function()
logToDiscord(WEBHOOKS.admin, "CRITICAL", "Server Shutting Down",
"Server is shutting down",
{
{name = "Players Online", value = tostring(#game.Players:GetPlayers()), inline = true},
{name = "Uptime", value = tostring(math.floor(workspace.DistributedGameTime/60)) .. " minutes", inline = true}
}
)
task.wait(2) -- Give time for webhook to send
end)External API Integration
Connect to your backend API for game data and authentication.
lua
local Raddish = require(game.ReplicatedStorage.Raddish)
-- API Configuration
local API_BASE_URL = "https://api.yourgame.com"
local API_KEY = game:GetService("ServerStorage").Config.ApiKey.Value
-- Verify player owns game pass via external API
function verifyGamePass(player, gamePassId)
local response = Raddish.APIRequest(API_BASE_URL, "/player/gamepasses/verify", {
method = "POST",
apiKey = API_KEY,
data = {
userId = player.UserId,
gamePassId = gamePassId
},
cache = true,
cacheTTL = 300 -- Cache for 5 minutes
})
if response.Success and response.Body.verified then
return true
end
return false
end
-- Load player inventory from external database
function loadPlayerInventory(player)
local response = Raddish.APIRequest(API_BASE_URL, "/player/" .. player.UserId .. "/inventory", {
method = "GET",
apiKey = API_KEY,
cache = true,
cacheTTL = 180 -- Cache for 3 minutes
})
if response.Success then
local inventory = response.Body.inventory
-- Store in Raddish cache for quick access
for _, item in ipairs(inventory) do
Raddish.HSet("inventory:" .. player.UserId, item.id, item.quantity)
end
return inventory
else
warn("Failed to load inventory:", response.StatusMessage)
return {}
end
end
-- Save player data to external API
function savePlayerProgress(player, data)
local response = Raddish.APIRequest(API_BASE_URL, "/player/" .. player.UserId .. "/progress", {
method = "PUT",
apiKey = API_KEY,
data = {
level = data.level,
experience = data.experience,
coins = data.coins,
timestamp = os.time()
}
})
if response.Success then
print("Saved progress for", player.Name)
else
warn("Failed to save progress:", response.StatusMessage)
end
end
-- Auto-save every 5 minutes
game.Players.PlayerAdded:Connect(function(player)
task.spawn(function()
while player.Parent do
task.wait(300) -- 5 minutes
local data = {
level = player:GetAttribute("Level"),
experience = player:GetAttribute("Experience"),
coins = player:GetAttribute("Coins")
}
savePlayerProgress(player, data)
end
end)
end)
-- Fetch global leaderboard from API
function fetchGlobalLeaderboard()
local response = Raddish.HttpGet(API_BASE_URL .. "/leaderboard/global", {
cache = true,
cacheTTL = 60, -- Update every minute
headers = {
["Authorization"] = "Bearer " .. API_KEY
}
})
if response.Success then
local leaderboard = response.Body.players
-- Update local cache
for rank, entry in ipairs(leaderboard) do
Raddish.ZAdd("leaderboard:global", entry.score, entry.userId)
end
return leaderboard
end
return {}
end
-- Update leaderboard every minute
task.spawn(function()
while true do
fetchGlobalLeaderboard()
task.wait(60)
end
end)Payment Processing
Verify in-game purchases with your payment provider.
lua
local Raddish = require(game.ReplicatedStorage.Raddish)
local MarketplaceService = game:GetService("MarketplaceService")
local PAYMENT_API = "https://payments.yourgame.com"
local PAYMENT_KEY = game:GetService("ServerStorage").Config.PaymentKey.Value
-- Process developer product purchase
MarketplaceService.ProcessReceipt = function(receiptInfo)
local player = game.Players:GetPlayerByUserId(receiptInfo.PlayerId)
if not player then
return Enum.ProductPurchaseDecision.NotProcessedYet
end
-- Verify with external payment API
local response = Raddish.APIRequest(PAYMENT_API, "/verify-purchase", {
method = "POST",
apiKey = PAYMENT_KEY,
data = {
userId = receiptInfo.PlayerId,
productId = receiptInfo.ProductId,
purchaseId = receiptInfo.PurchaseId,
currencyType = receiptInfo.CurrencyType,
currencySpent = receiptInfo.CurrencySpent,
placeId = game.PlaceId,
timestamp = os.time()
}
})
if response.Success and response.Body.verified then
-- Grant product
local productId = receiptInfo.ProductId
if productId == 123456 then
-- 100 Coins
giveCoins(player, 100)
elseif productId == 123457 then
-- VIP Pass
giveVIP(player, 30) -- 30 days
end
-- Log to Discord
Raddish.SendDiscordWebhook("YOUR_WEBHOOK", {
title = "💰 Purchase Completed",
description = player.Name .. " purchased a product",
color = 0x00FF00,
fields = {
{name = "Product ID", value = tostring(productId), inline = true},
{name = "Price", value = tostring(receiptInfo.CurrencySpent), inline = true},
{name = "Purchase ID", value = receiptInfo.PurchaseId, inline = false}
}
})
return Enum.ProductPurchaseDecision.PurchaseGranted
else
warn("Payment verification failed:", response.StatusMessage)
return Enum.ProductPurchaseDecision.NotProcessedYet
end
end
function giveCoins(player, amount)
local newAmount = Raddish.IncrementWithCache(player, "Coins", amount, 0)
player:SetAttribute("Coins", newAmount)
-- Sync with external API
Raddish.APIRequest(PAYMENT_API, "/player/" .. player.UserId .. "/coins", {
method = "POST",
apiKey = PAYMENT_KEY,
data = {amount = newAmount}
})
endAnalytics Tracking
Send game analytics to external services.
lua
local Raddish = require(game.ReplicatedStorage.Raddish)
local ANALYTICS_URL = "https://analytics.yourgame.com"
local ANALYTICS_KEY = "your-analytics-api-key"
-- Track custom events
function trackEvent(eventName, properties)
Raddish.HttpPost(ANALYTICS_URL .. "/events", {
event = eventName,
properties = properties,
timestamp = os.time(),
serverId = game.JobId,
placeId = game.PlaceId
}, {
headers = {
["Authorization"] = "Bearer " .. ANALYTICS_KEY,
["Content-Type"] = "application/json"
}
})
-- Also cache locally for batch sending
Raddish.RPush("analytics:events", {
event = eventName,
properties = properties,
timestamp = os.time()
})
end
-- Player session tracking
game.Players.PlayerAdded:Connect(function(player)
trackEvent("player_joined", {
userId = player.UserId,
username = player.Name,
accountAge = player.AccountAge,
isPremium = player.MembershipType == Enum.MembershipType.Premium,
locale = player.LocaleId
})
player:SetAttribute("SessionStart", os.time())
end)
game.Players.PlayerRemoving:Connect(function(player)
local sessionDuration = os.time() - (player:GetAttribute("SessionStart") or os.time())
trackEvent("player_left", {
userId = player.UserId,
sessionDuration = sessionDuration,
level = player:GetAttribute("Level"),
coins = player:GetAttribute("Coins")
})
end)
-- Track level ups
function onLevelUp(player, newLevel)
trackEvent("level_up", {
userId = player.UserId,
username = player.Name,
newLevel = newLevel,
timePlayed = os.time() - (player:GetAttribute("SessionStart") or os.time())
})
end
-- Track purchases
function onPurchase(player, itemName, price)
trackEvent("item_purchased", {
userId = player.UserId,
itemName = itemName,
price = price,
currency = "Coins"
})
end
-- Batch send analytics every 60 seconds
task.spawn(function()
while true do
task.wait(60)
local events = Raddish.LRange("analytics:events", 1, -1)
if #events > 0 then
-- Send batch
Raddish.HttpPost(ANALYTICS_URL .. "/events/batch", {
events = events
}, {
headers = {
["Authorization"] = "Bearer " .. ANALYTICS_KEY
}
})
-- Clear local cache
Raddish.Delete("analytics:events")
print("Sent", #events, "analytics events")
end
end
end)Third-Party API Integration
Integrate with popular APIs like Twitter, YouTube, etc.
lua
local Raddish = require(game.ReplicatedStorage.Raddish)
-- YouTube API Integration
local YOUTUBE_API_KEY = "your-youtube-api-key"
function getChannelSubscribers(channelId)
local response = Raddish.HttpGet(
"https://www.googleapis.com/youtube/v3/channels?part=statistics&id=" .. channelId .. "&key=" .. YOUTUBE_API_KEY,
{
cache = true,
cacheTTL = 600 -- Cache for 10 minutes
}
)
if response.Success and response.Body.items then
return response.Body.items[1].statistics.subscriberCount
end
return 0
end
-- Display subscriber count in-game
local subscribers = getChannelSubscribers("YOUR_CHANNEL_ID")
print("Channel has", subscribers, "subscribers")
-- IP Geolocation API
function getPlayerCountry(ipAddress)
local response = Raddish.HttpGet(
"https://ipapi.co/" .. ipAddress .. "/json/",
{
cache = true,
cacheTTL = 86400 -- Cache for 24 hours
}
)
if response.Success then
return response.Body.country_name
end
return "Unknown"
end
-- Weather API (for in-game weather)
function getCurrentWeather(city)
local response = Raddish.HttpGet(
"https://api.openweathermap.org/data/2.5/weather?q=" .. city .. "&appid=YOUR_API_KEY",
{
cache = true,
cacheTTL = 1800 -- Update every 30 minutes
}
)
if response.Success then
return {
temperature = response.Body.main.temp,
condition = response.Body.weather[1].main,
description = response.Body.weather[1].description
}
end
return nil
end
-- Sync in-game weather with real weather
local weather = getCurrentWeather("London")
if weather then
if weather.condition == "Rain" then
startRain()
elseif weather.condition == "Clear" then
setSunny()
end
endServer Status Page
Create a status page with real-time server information.
lua
local Raddish = require(game.ReplicatedStorage.Raddish)
local STATUS_API = "https://status.yourgame.com"
local STATUS_KEY = "your-status-api-key"
-- Report server status every 30 seconds
task.spawn(function()
while true do
local status = {
serverId = game.JobId,
placeId = game.PlaceId,
status = "online",
players = {
current = #game.Players:GetPlayers(),
max = game.Players.MaxPlayers
},
performance = {
memory = game:GetService("Stats"):GetTotalMemoryUsageMb(),
heartbeat = game:GetService("RunService").Heartbeat:Wait(),
fps = 1 / game:GetService("RunService").Heartbeat:Wait()
},
uptime = workspace.DistributedGameTime,
timestamp = os.time()
}
Raddish.HttpPost(STATUS_API .. "/servers/" .. game.JobId, status, {
headers = {
["Authorization"] = "Bearer " .. STATUS_KEY
}
})
task.wait(30)
end
end)
-- Report server shutdown
game:BindToClose(function()
Raddish.HttpPost(STATUS_API .. "/servers/" .. game.JobId, {
status = "offline",
timestamp = os.time()
}, {
headers = {
["Authorization"] = "Bearer " .. STATUS_KEY
}
})
task.wait(2)
end)Caching Strategy
Always use caching for external APIs to:
- Reduce latency (instant responses)
- Save API costs (fewer requests)
- Handle rate limits automatically
- Improve reliability (serve cached data if API is down)
Security
Never expose API keys in client scripts! Always keep them in ServerStorage or ServerScriptService.
Rate Limits
Raddish automatically handles rate limiting with:
- Request queuing when limits are reached
- Exponential backoff for retries
- Automatic batching for high-volume requests