Reliable code that sorts people into servers based on age group

(Note: Player shave to chose what age group they are in as you can’t know someone’s age group)

what this system actually does

this setup lets players pick an age group manually, then it:

  • puts them into a queue for that group
  • finds or creates a private server just for that group
  • keeps servers from overfilling
  • rotates servers when they get old or full
  • avoids race conditions when multiple players click at once
  • retries teleports if roblox does a roblox moment

everything runs from one Script. no extra assets needed.


step 1: where to put the script

  1. open Roblox Studio
  2. go to ServerScriptService
  3. create a Script (not LocalScript)
  4. paste the entire code in there
  5. make sure the game is published (teleports wont work in unpublished games)

thats it. dont split it. dont rename anything inside it.


step 2: what happens when a player joins

when a player joins:

  • the script auto creates a ScreenGui
  • adds 3 buttons (Under13, Teen, Adult)
  • injects a LocalScript directly into the gui
  • the buttons lock after clicking so players cant spam

you do not need to make a gui yourself unless you want custom visuals.


step 3: how age groups actually work (important)

roblox does not let you read real age. this system does NOT try to.

these are just self selected groups, think of them like:

  • play style
  • maturity preference
  • community choice

do NOT say things like:

  • “verified age”
  • “real age servers”
  • “minors/adults only”

use neutral wording in your game description or UI if you change text later.


step 4: server logic (how it decides where to send players)

for each age group:

  • it stores server data in a DataStore
  • also keeps a live queue using MemoryStore
  • each server has:
    • a max player limit
    • a creation timestamp
  • if a server is full or too old → new one is created
  • players are teleported in small batches

this avoids:

  • 20 players being sent to a dead server
  • everyone racing to create servers at once
  • datastore corruption (mostly)

step 5: testing it (do this properly)

you cant test this with 1 player and expect magic.

best way:

  1. publish the game
  2. start Start Server + Start Player in studio
  3. open multiple test clients
  4. click different buttons
  5. watch servers split correctly

if teleports fail in studio, thats normal sometimes. live game is more reliable.


step 6: common mistakes people make

these will break it:

  • putting the script anywhere other than ServerScriptService
  • renaming the RemoteEvent
  • trying to move the LocalScript out of the gui
  • testing in an unpublished place
  • assuming roblox age is involved (its not)

also dont spam click in studio, teleport throttling is real.


step 7: customizing it (safe changes)

things you can change safely:

  • button text
  • age group names (just keep them consistent)
  • MAX_SERVER_SIZE
  • SERVER_TTL
  • teleport retry count
  • gui colors / sizes

if you add new groups, you MUST:

  • add a button
  • add it to the processing loop
  • use the same string everywhere

step 8: moderation & tos reality check

be smart about presentation.

this system is allowed only if:

  • players choose themselves
  • no claims about real age verification
  • no exclusionary language in rules

if you market it wrong, roblox moderation wont care how clean your code is.


step 9: when this system is actually worth using

use this if:

  • your game has social interaction
  • different maturity levels cause issues
  • you want softer separation without hard rules

dont use it if:

  • the game is solo
  • age doesnt matter at all
  • you expect it to enforce safety (it doesnt)

final dev advice (real talk)

this is already way more advanced than 95% of roblox games.
most devs stop at TeleportService:Teleport() and call it a day.

code:


local Players = game:GetService("Players")
local TeleportService = game:GetService("TeleportService")
local DataStoreService = game:GetService("DataStoreService")
local MemoryStoreService = game:GetService("MemoryStoreService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")

local PLACE_ID = game.PlaceId
local MAX_SERVER_SIZE = 20
local SERVER_TTL = 3600
local TELEPORT_RETRIES = 3

local ServerStore = DataStoreService:GetDataStore("AgeGroupServersV3")
local QueueMap = MemoryStoreService:GetSortedMap("AgeGroupQueuesV3")
local LockMap = MemoryStoreService:GetSortedMap("AgeGroupLocksV3")

local event = Instance.new("RemoteEvent")
event.Name = "AgeGroupSelected"
event.Parent = ReplicatedStorage

local function acquireLock(key)
	return pcall(function()
		LockMap:SetAsync(key, os.time(), 5)
	end)
end

local function releaseLock(key)
	pcall(function()
		LockMap:RemoveAsync(key)
	end)
end

local function getServerData(group)
	local data
	pcall(function()
		data = ServerStore:GetAsync(group)
	end)
	if type(data) ~= "table" then
		return nil
	end
	if os.time() - data.created > SERVER_TTL then
		return nil
	end
	return data
end

local function saveServerData(group, data)
	pcall(function()
		ServerStore:SetAsync(group, data)
	end)
end

local function createServer(group)
	local code = TeleportService:ReserveServer(PLACE_ID)
	local data = {
		code = code,
		count = 0,
		created = os.time()
	}
	saveServerData(group, data)
	return data
end

local function claimSlot(group)
	local data = getServerData(group)
	if not data or data.count >= MAX_SERVER_SIZE then
		data = createServer(group)
	end
	data.count += 1
	saveServerData(group, data)
	return data.code
end

local function teleport(player, code)
	for i = 1, TELEPORT_RETRIES do
		local ok = pcall(function()
			TeleportService:TeleportToPrivateServer(
				PLACE_ID,
				code,
				{ player }
			)
		end)
		if ok then
			return true
		end
		task.wait(i)
	end
	return false
end

local function processGroup(group)
	if not acquireLock(group) then
		return
	end

	local entries
	pcall(function()
		entries = QueueMap:GetRangeAsync(group, 1, 10)
	end)

	if not entries then
		releaseLock(group)
		return
	end

	for _, item in ipairs(entries) do
		local userId = tonumber(item.value)
		local player = Players:GetPlayerByUserId(userId)
		if player then
			local code = claimSlot(group)
			teleport(player, code)
		end
		pcall(function()
			QueueMap:RemoveAsync(group, item.id)
		end)
	end

	releaseLock(group)
end

event.OnServerEvent:Connect(function(player, group)
	pcall(function()
		QueueMap:SetAsync(group, player.UserId, os.time(), 60)
	end)
end)

task.spawn(function()
	while true do
		task.wait(2)
		processGroup("Under13")
		processGroup("Teen")
		processGroup("Adult")
	end
end)

Players.PlayerAdded:Connect(function(player)
	local gui = Instance.new("ScreenGui")
	gui.Name = "AgeSelectGui"
	gui.ResetOnSpawn = false
	gui.Parent = player:WaitForChild("PlayerGui")

	local function makeButton(text, y, name)
		local b = Instance.new("TextButton")
		b.Size = UDim2.fromScale(0.45, 0.12)
		b.Position = UDim2.fromScale(0.275, y)
		b.Text = text
		b.Name = name
		b.BackgroundColor3 = Color3.fromRGB(35, 35, 35)
		b.TextColor3 = Color3.new(1, 1, 1)
		b.Parent = gui
	end

	makeButton("Under 13", 0.25, "Under13")
	makeButton("Teen", 0.4, "Teen")
	makeButton("Adult", 0.55, "Adult")

	local ls = Instance.new("LocalScript")
	ls.Parent = gui
	ls.Source = [[
		local rs = game:GetService("ReplicatedStorage")
		local event = rs:WaitForChild("AgeGroupSelected")
		local gui = script.Parent
		local locked = false

		local function lock()
			if locked then return false end
			locked = true
			for _, v in ipairs(gui:GetChildren()) do
				if v:IsA("TextButton") then
					v.AutoButtonColor = false
					v.TextTransparency = 0.4
				end
			end
			return true
		end

		gui.Under13.MouseButton1Click:Connect(function()
			if lock() then
				event:FireServer("Under13")
			end
		end)

		gui.Teen.MouseButton1Click:Connect(function()
			if lock() then
				event:FireServer("Teen")
			end
		end)

		gui.Adult.MouseButton1Click:Connect(function()
			if lock() then
				event:FireServer("Adult")
			end
		end)
	]]
end)

RunService.Heartbeat:Connect(function()
	for _, group in ipairs({ "Under13", "Teen", "Adult" }) do
		local data = getServerData(group)
		if data and data.count <= 0 then
			pcall(function()
				ServerStore:RemoveAsync(group)
			end)
		end
	end
end)


hope yall have a good day :smiley:

5 Likes

so its a renamed server list with most features removed

honestly yeah lol. it’s basically a simplified server list, just automated and scoped per group instead of exposed to players. keeps things separated without overengineering it.

1 Like

might update and add more features to this one day but I have a lot of other projects tbh.

I feel like there are already better ways of doing this that are invisible, though. I remember somebody said that they were able to sort most players accurately into their age groups by signals (I don’t remember exactly). However they did say that they weren’t releasing it for fear of it being misused, so I guess this is the best alternative…

1 Like

yeah I get that, those “signal-based” methods probably do a lot behind the scenes, but honestly it’s kinda sketchy and risky. this self-select approach isn’t perfect but at least it’s safe and transparent, and you don’t get into the whole privacy/moderation mess.

1 Like

letting preds cherry pick the ones they want :wilted_flower:

how can they even chat if age checks are implemented Gng what :sob:?

I haven’t tried yet, but people can lie, so I’d try using alts for each age group, and use this code to verify their age, game:GetService("TextChatService"):CanUsersChatAsync()

then you’d have to make sure the AI sorts every single alt into the correct age groups, and if it fails, make a new alt

he makes no sense because they can’t chat with people in the age group either way. The whole purpose of the code is to sort people so they won’t have to worry about people being silent and the game experience can be better.

you can know which players are what age

no you can’t Gng how do I just hack into the code and steal their age group.

??? youre being put in a server with a specific age group, so the pred can know which players are what age group and target them later

and how can they communicate / do predatory acts with them if they can’t even talk to each other.

how do I hide the body in the factory map :sob:

literally you make no sense rn

1 Like

Thank you, useful script for my game that relies on player to player communication

1 Like