Skip to content

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}
    })
end

Analytics 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
end

Server 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

"Beyond Boundaries. Beyond Imagination."