Tutorial · Game systems

How to make a teleporter in Roblox Studio

A teleporter in Roblox is one of two things: moving a character somewhere else in the same server, or sending the player to another place in your game. This guide builds both from one server script: pads that send you to a partner pad, a Teleport menu whose locked spots open with Wins, and portals to another place that retry when Roblox's teleport fails.

Updated 15 October 202623 min readBeginnerLuau

In short

For a teleport pad, put a Script in ServerScriptService that listens to the pad's Touched event, finds the player with Players:GetPlayerFromCharacter, and moves the whole character with character:PivotTo() to a spot just in front of the destination pad, facing away from it, with a cooldown of a couple of seconds per player so the destination pad does not send them straight back. To send players to another place in your game, call TeleportService:TeleportAsync(placeId, { player }) from a server Script inside pcall; it only works in the published game, not in Studio.

  • Move the whole character with PivotTo. Setting HumanoidRootPart.Position moves the root part away from the rest of the body, because Roblox updates the joints when Position is set.
  • A teleport menu should send the server a destination name, never a position. The server checks the name, the cooldown and any unlock rule before it moves anyone.
  • TeleportService:Teleport() is deprecated and client-side. Use TeleportAsync on the server, wrap it in pcall, retry, and handle TeleportInitFailed.
On this page
  1. How it works
  2. 1. Teleport pads
  3. 2. Teleport script
  4. 3. Teleport menu
  5. 4. Other places
  6. Older tutorials
  7. Exploit limits
  8. 5. Test it
  9. Extending it
  10. Common errors
  11. With RoCode
  12. Questions
  13. Sources

Two kinds of teleport

IllustrationTouching PadA puts you just in front of PadB, so PadB does not send you straight back, and the server refuses the locked Castle but moves you to Lake.

A teleporter can mean three things in a Roblox game: a pad that sends you across the map, a menu of spots to jump to, or a portal into another level. The first two move a character inside the server the player is already in. The third sends the player to a different place in your game, which runs on its own servers. They use different APIs, so it helps to know which one you need.

The two kinds of teleport
Inside the same serverTo another place in your game
The callcharacter:PivotTo(cframe)TeleportService:TeleportAsync(placeId, players)
Used forTeleport pads, a teleport menu, moving players from the lobby to an arenaPortals to another level, a lobby that sends players into a separate dungeon or match place
Runs inA server ScriptA server Script only. The client-side Teleport() is deprecated.
Works in a Studio playtestYesNo. Roblox's TeleportService does not support playtesting in Studio, so you test it in the published game.
What the player seesA jump across the map, which can take up to 2 seconds if that area has to load firstRoblox's loading screen, then the other place
Coins, items and other dataStay as they areRoblox discards the player's local data, so anything that matters has to come from a data store in the other place

This guide builds all three kinds in one server Script, so one set of rules covers every teleport in your game: the server decides, each player has their own cooldown, and the player's device only ever says which spot it would like.

The pieces of the teleporter
PieceWhere it livesWhat it does
TeleportPads Folder with PadA and PadBWorkspaceTwo pads. Each pad's Destination attribute names the pad it sends players to.
TeleportSpots FolderWorkspaceOne part for each spot the menu lists. A WinsNeeded attribute locks a spot.
PlacePortals FolderWorkspacePortal parts. Each portal's PlaceId attribute is the place it sends players to.
Teleporters ScriptServerScriptServiceRuns all three kinds of teleport and creates the two remotes. The only place a teleport can happen.
TeleportMenu LocalScriptStarterPlayer > StarterPlayerScriptsDraws the Teleport button and the list of spots, and sends the name of the spot the player picks.
GetTeleportSpots RemoteFunction and TeleportRequest RemoteEventReplicatedStorage (Teleporters creates them)The first returns the list of spots to the menu. The second carries the picked name to the server.
Explorer when the teleporter is finished. Teleporters adds GetTeleportSpots and TeleportRequest to ReplicatedStorage when the game runs.
Workspace
  TeleportPads Folder new
    PadA Part new
    PadB Part new
  TeleportSpots Folder new
    Spawn Part new
    Lake Part new
    Castle Part new
  PlacePortals Folder new
    DungeonPortal Part new
ServerScriptService
  Teleporters Script new
StarterPlayer
  StarterPlayerScripts
    TeleportMenu LocalScript new

Step 1: Build two teleport pads

  1. In the Explorer, hover over Workspace, click the + button and insert a Folder. Name it TeleportPads. The script looks for this exact name.
  2. Insert two Parts into the folder and name them PadA and PadB. Make each one a flat slab, for example 6 by 1 by 6 studs, and place them on the floor some distance apart. In the Properties window, tick Anchored, leave CanCollide and CanTouch on, and give them a bright colour and the Neon material so players can spot them.
  3. Select PadA, scroll to the Attributes section of the Properties window and click +. Enter the name Destination, choose the type String and click Save, then set its value to PadB. Do the same on PadB with the value PadA.
  4. Turn each pad so its front face points at open floor. Players arrive 3 studs in front of the destination pad's front face, facing away from it, so leave a few studs of open floor there. To see which face is the front, right-click the pad and choose Show Orientation Indicator: a blue line marks the front face. Turn the pad with the Rotate tool until that line points where players should walk off.

Players land beside the pad, not on it, on purpose. Roblox's debounce page notes that Touched fires many times in quick succession for one contact, so a player who arrived on top of the other pad would set it off again as soon as their cooldown ran out, and bounce back across the map.

You are not limited to two pads. A pad's Destination can name any part in TeleportPads, so three pads can send players round in a loop. For a one-way pad, point it at a part in TeleportPads that has no Destination of its own: that part receives players and sends nobody anywhere.

Step 2: Add the teleport script

Hover over ServerScriptService, insert a Script, name it Teleporters and paste the code below. It handles the pads now, and the menu and the portals from the next steps, so you add it once. The settings at the top are the lines you are meant to change.

Script in ServerScriptService named Teleporters
-- Script in ServerScriptService named Teleporters.
-- Every teleport is decided here, on the server:
--   1. Pads: touching a part in Workspace.TeleportPads takes you to the part named
--      in its Destination attribute.
--   2. A menu: the TeleportMenu LocalScript asks for a spot in Workspace.TeleportSpots
--      by name. The server checks the name, the cooldown and the Wins the spot needs.
--   3. Portals: touching a part in Workspace.PlacePortals sends you to the place
--      in its PlaceId attribute (another place in this game).

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

local PAD_COOLDOWN_SECONDS = 2 -- pads ignore a player this long after any teleport
local MENU_COOLDOWN_SECONDS = 3
local PAD_ARRIVAL_GAP = 3 -- studs in front of a destination pad, so players land beside it
local PLACE_ATTEMPTS = 3

local padFolder = workspace:FindFirstChild("TeleportPads")
local spotFolder = workspace:FindFirstChild("TeleportSpots")
local portalFolder = workspace:FindFirstChild("PlacePortals")

-- This script makes both remotes itself, so do not add them by hand
local getSpots = Instance.new("RemoteFunction")
getSpots.Name = "GetTeleportSpots"
getSpots.Parent = ReplicatedStorage
local teleportRequest = Instance.new("RemoteEvent")
teleportRequest.Name = "TeleportRequest"
teleportRequest.Parent = ReplicatedStorage

local lastTeleport: { [Player]: number } = {}
local warnedPads: { [Instance]: boolean } = {}
local leavingForPlace: { [Player]: boolean } = {}

local function playerFromHit(otherPart: BasePart): Player?
	local character = otherPart:FindFirstAncestorOfClass("Model")
	return if character then Players:GetPlayerFromCharacter(character) else nil
end

local function onCooldown(player: Player, seconds: number): boolean
	return os.clock() - (lastTeleport[player] or -math.huge) < seconds
end

-- How high a standing character's root part sits above the floor.
-- The formula is from Roblox's Humanoid.HipHeight reference (R6 rigs add the leg height).
local function rootHeight(character: Model, humanoid: Humanoid, rootPart: BasePart): number
	local height = rootPart.Size.Y / 2 + humanoid.HipHeight
	if humanoid.RigType == Enum.HumanoidRigType.R6 then
		local leg = character:FindFirstChild("Left Leg")
		if leg and leg:IsA("BasePart") then
			height += leg.Size.Y
		end
	end
	return height
end

local function teleportTo(player: Player, destination: BasePart, besidePad: boolean)
	local character = player.Character
	local humanoid = character and character:FindFirstChildOfClass("Humanoid")
	local rootPart = humanoid and humanoid.RootPart
	if not (character and humanoid and rootPart) or humanoid.Health <= 0 then
		return
	end
	lastTeleport[player] = os.clock() -- set before waiting, so a second touch cannot start a second teleport

	-- Face the way the destination's front face points (level, never tilted)
	local facing = destination.CFrame.LookVector * Vector3.new(1, 0, 1)
	if facing.Magnitude < 0.01 then
		facing = Vector3.new(0, 0, -1)
	end
	facing = facing.Unit
	-- Stand on its top face: a character's pivot is its root part, so lift it to standing height.
	-- A pad puts players a few studs in front of itself instead, because a player standing
	-- on a pad would set it off again with the next step.
	local lift = destination.Size.Y / 2 + rootHeight(character, humanoid, rootPart)
	local top = destination.Position + destination.CFrame.UpVector * lift
	if besidePad then
		top += facing * (destination.Size.Z / 2 + PAD_ARRIVAL_GAP)
	end
	local target = CFrame.lookAlong(top, facing)

	-- With instance streaming on, load the area around the destination first (up to 2 seconds)
	pcall(function()
		player:RequestStreamAroundAsync(target.Position, 2)
	end)
	if player.Parent == nil or player.Character ~= character or humanoid.Health <= 0 then
		return -- left, respawned or died while the area loaded
	end
	-- A seated character is welded to its seat, and moving it would bring the seat along.
	-- Destroying the SeatWeld gets the character out of the seat first.
	local seat = humanoid.SeatPart
	if seat then
		local seatWeld = seat:FindFirstChild("SeatWeld")
		if seatWeld then
			seatWeld:Destroy()
		end
	end
	character:PivotTo(target)
	-- Start the cooldown again on arrival: the pre-fetch above can take up to 2 seconds,
	-- and the pad they land on must not send them straight back
	lastTeleport[player] = os.clock()
	player:SetAttribute("MovementCheckSkip", true) -- for a speed check script, if you have one
end

-- 1. Pads
if padFolder then
	for _, pad in padFolder:GetChildren() do
		if pad:IsA("BasePart") then
			pad.Touched:Connect(function(otherPart: BasePart)
				local player = playerFromHit(otherPart)
				local destinationName = pad:GetAttribute("Destination")
				if not player or typeof(destinationName) ~= "string" or onCooldown(player, PAD_COOLDOWN_SECONDS) then
					return
				end
				local destination = padFolder:FindFirstChild(destinationName)
				if destination and destination:IsA("BasePart") then
					teleportTo(player, destination, true)
				elseif not warnedPads[pad] then
					warnedPads[pad] = true -- warn once, not on every touch
					warn(`Teleporters: {pad.Name} points to {destinationName}, which is not a part in TeleportPads`)
				end
			end)
		end
	end
end

-- 2. The menu: the list of spots, then a request by name
local function winsOf(player: Player): number
	local leaderstats = player:FindFirstChild("leaderstats")
	local wins = leaderstats and leaderstats:FindFirstChild("Wins")
	return if wins and wins:IsA("IntValue") then wins.Value else 0
end

local function winsNeeded(spot: Instance): number
	local value = spot:GetAttribute("WinsNeeded")
	return if typeof(value) == "number" then value else 0
end

getSpots.OnServerInvoke = function(_player: Player)
	local list = {}
	if spotFolder then
		for _, spot in spotFolder:GetChildren() do
			if spot:IsA("BasePart") then
				table.insert(list, { name = spot.Name, winsNeeded = winsNeeded(spot) })
			end
		end
	end
	table.sort(list, function(a, b)
		if a.winsNeeded ~= b.winsNeeded then
			return a.winsNeeded < b.winsNeeded
		end
		return a.name < b.name -- same Wins: alphabetical, so the order never changes
	end)
	return list
end

teleportRequest.OnServerEvent:Connect(function(player: Player, spotName: unknown)
	-- The client sends only a name. Never accept a position or a CFrame from a client.
	if typeof(spotName) ~= "string" or #spotName > 50 or not spotFolder then
		return
	end
	if onCooldown(player, MENU_COOLDOWN_SECONDS) then
		return
	end
	local spot = spotFolder:FindFirstChild(spotName)
	if not (spot and spot:IsA("BasePart")) then
		return
	end
	if winsOf(player) < winsNeeded(spot) then
		return -- locked for this player
	end
	teleportTo(player, spot, false)
end)

-- 3. Portals to another place in this game
local function sendToPlace(player: Player, placeId: number)
	if leavingForPlace[player] or onCooldown(player, PAD_COOLDOWN_SECONDS) then
		return -- already on the way, or touched a teleporter a moment ago
	end
	lastTeleport[player] = os.clock()
	if RunService:IsStudio() then
		print(`Teleporters: would send {player.Name} to place {placeId}. Place teleports only work in the published game.`)
		return
	end
	leavingForPlace[player] = true
	for attempt = 1, PLACE_ATTEMPTS do
		local ok, err = pcall(function()
			TeleportService:TeleportAsync(placeId, { player })
		end)
		if ok then
			return
		end
		warn(`Teleporters: teleport attempt {attempt} for {player.Name} failed: {err}`)
		task.wait(2)
	end
	leavingForPlace[player] = nil -- give up; touching the portal again tries again
end

-- A teleport can also fail after it starts. The player stays here and may try again.
TeleportService.TeleportInitFailed:Connect(function(player: Player, result: Enum.TeleportResult, message: string)
	warn(`Teleporters: {player.Name} could not leave ({result.Name}): {message}`)
	leavingForPlace[player] = nil
end)

if portalFolder then
	for _, portal in portalFolder:GetChildren() do
		if portal:IsA("BasePart") then
			portal.Touched:Connect(function(otherPart: BasePart)
				local player = playerFromHit(otherPart)
				local placeId = portal:GetAttribute("PlaceId")
				if player and typeof(placeId) == "number" and placeId > 0 then
					sendToPlace(player, placeId)
				end
			end)
		end
	end
end

Players.PlayerRemoving:Connect(function(player: Player)
	lastTeleport[player] = nil
	leavingForPlace[player] = nil
end)

Teleporters creates the GetTeleportSpots RemoteFunction and the TeleportRequest RemoteEvent itself, so there is nothing to insert in ReplicatedStorage by hand. It connects the pads in TeleportPads and the portals in PlacePortals once, when the server starts, so pads and portals added while the game is running do nothing. A folder that is missing simply switches that kind of teleport off.

What each part of Teleporters does
PartWhat it doesWhy
playerFromHitFinds the character model the touching part belongs to and asks Players:GetPlayerFromCharacter whose it is.A pad is touched by feet, hats and loose parts. Anything that is not part of a player's character gives nil and is ignored.
onCooldownCompares os.clock() with the time of the player's last teleport.One cooldown per player, so a player standing near a pad never blocks anyone else. Nothing waits or sleeps.
rootHeightWorks out how high a standing character's root part sits above the floor: half the root part's height plus the Humanoid's HipHeight, plus the leg length on R6 rigs.This is the formula from Roblox's Humanoid.HipHeight reference. A character's pivot is its root part, so lifting the pivot by this much puts the feet on the surface for small, large and R6 avatars alike.
The checks at the top of teleportToReturns unless the player has a living character with a root part, then records the time at once.The streaming request below can make the script wait. Recording the time first means the many Touched events in that moment cannot start a second teleport.
The arrival pointThe destination's top face, raised by rootHeight, facing the way its front face points with any tilt removed. For a pad, it also moves 3 studs past the pad's front face.The character arrives upright, not inside the destination part. Beside a pad its feet start level with the pad's top face, so it drops the pad's thickness to the floor. CFrame.lookAlong builds a CFrame at a position, facing a direction.
RequestStreamAroundAsyncAsks Roblox to send the area around the arrival point to that player first, waiting at most 2 seconds.Instance streaming is on by default for new places, so a far part of the map may not be loaded on the player's device yet. Roblox recommends this server call before moving a character somewhere far, though it does not guarantee what arrives.
The second checkIf the player left, or the character respawned or died during the wait, nothing moves.The player may have reset or left the game while the area loaded. Roblox's own pre-fetch example also checks the character is still in the game before moving it.
The SeatWeld linesIf the character is sitting, destroys the weld that holds it to the seat.Roblox welds a sitting character to its seat. PivotTo moves parts by changing their CFrame, and Roblox's reference says setting a part's CFrame also moves the parts joined to it, so without this the seat, and anything welded to it, would arrive with the player. Destroying SeatWeld is how Roblox's Seat reference gets a character out of a seat from a script.
character:PivotTo(target)Moves the whole character, every limb and accessory together, to the arrival point.Roblox calls PivotTo the primary function for moving models from scripts.
The second lastTeleport lineStarts the cooldown again on arrival.The streaming request can take up to 2 seconds, as long as the pad cooldown itself, so without this line a player could arrive with no cooldown left.
MovementCheckSkipSets an attribute on the Player after each move.A server-side speed check would see the jump as a cheat. The sprint guide's MovementCheck reads this attribute and starts measuring again from the new position. Without such a script, the attribute does nothing.
The settings at the top of Teleporters
SettingValue hereWhat it changes
PAD_COOLDOWN_SECONDS2How long pads and portals ignore a player after any teleport.
MENU_COOLDOWN_SECONDS3The shortest gap between two menu teleports for one player. Pads and the menu share one clock per player, so a menu request within 3 seconds of a pad teleport is ignored too.
PAD_ARRIVAL_GAP3How many studs past a destination pad's front face players arrive, so they land beside the pad, not on it.
PLACE_ATTEMPTS3How many times a portal tries TeleportAsync, 2 seconds apart, before it gives up.

Press Play now and step on PadA: you appear in front of PadB. The menu and the portals need the next two steps, but the script already runs without them.

Step 4: Teleport to another place

A place is a separate world inside your game, with its own servers: a lobby and a dungeon, or a hub and a set of levels. Players move between places with TeleportService, and Roblox runs it only in the published game, so this step ends in the Roblox app rather than in Studio.

  1. If the game is not published yet, choose File > Publish. New games are open only to you, people you give Edit access and group members with the right roles until you release them, which is all you need to test teleports yourself.
  2. Make the second place: open a new place from any Studio template, build your dungeon, then choose File > Publish As, click your game's tile, select Add as a new place and click Create.
  3. Copy the new place's ID. Open the Asset Manager from the Window menu or the Home tab, go to Places In Experience, right-click the place and choose Copy Asset ID, which copies its place ID.
  4. Back in your first place, insert a Folder named PlacePortals into Workspace, and inside it an anchored Part named DungeonPortal. Add a Number attribute named PlaceId and paste the ID as its value.
  5. Press Play and touch the portal. Output prints a line starting Teleporters: would send: that is all a portal does in Studio.
  6. Publish again with File > Publish, so the published game has the portal, and test it from the Roblox app as in Step 5.

Teleporters calls TeleportAsync inside pcall, up to 3 times with 2 seconds between attempts, because Roblox's teleport page says teleports can fail and throw an error, and recommends retrying. A teleport can also start and then fail at the last moment without an error, leaving the player where they were. Roblox fires TeleportInitFailed for that, and the script clears the player's "leaving" flag, so touching the portal again tries again.

To bring players back, do the same in the other place: put a copy of Teleporters in its ServerScriptService and add a portal whose PlaceId is your first place's ID, copied from the Asset Manager the same way.

Who can join your other places

Roblox's security docs warn that once a client is inside one place of your game, it can teleport to any other place in it, whatever route you intended, and that turning off a place's Direct Access only removes the Join button on the website. The setting that changes this is Access Control for Places, under Audience > Access Settings in the Creator Dashboard:

The three Access Control for Places settings
SettingWho can join a place that is not the start place
Fully openAnyone, through teleports from any game, deep links, game invites and joining a friend.
Limited to same universeOnly players teleporting from within your games. Both client and server teleports are allowed.
Secure within universe onlyOnly players your server scripts teleport from within this game.

If players should only reach a place through your portal, a dungeon for example, choose Secure within universe only. Every teleport in this guide starts on the server, so it keeps working. Roblox also says many games do not need secure teleports, so a game whose places are all open to everyone can leave it as it is.

What older teleporter tutorials get wrong

If you are comparing this guide with a video or a forum post, these are the differences that matter, with the reason each pattern is a problem.

Common patterns in teleporter tutorials, and what this guide does instead
The tutorialThe problemThis guide
Sets hit.Parent.HumanoidRootPart.Position = target.PositionRoblox's reference says setting Position updates the part's joints so it moves relative to the parts it is joined to: the root part moves without the body.Moves the whole character with PivotTo.
Sets HumanoidRootPart.CFrame = target.CFrameThe middle of the character lands at the middle of the target part, partly inside it, and takes on the part's tilt.Arrives at standing height above the top face, beside a pad, kept level.
Uses one debounce variable for the whole padWhile one player teleports, the pad ignores everyone else. With no debounce at all, a player who lands on the other pad is sent straight back.One cooldown per player, recorded before anything waits, and players land beside the pad.
Calls TeleportService:Teleport(placeId, player) from a LocalScriptRoblox marks Teleport() deprecated, says not to use it for new work, and allows TeleportAsync only from server scripts.Calls TeleportAsync in the server script.
No pcall, no retryRoblox's teleport page says teleports can fail and throw an error, and can also fail after they start.Up to 3 attempts in pcall, and TeleportInitFailed lets the player try again.
Gives up because "it does not work" in StudioTeleportService does not support playtesting in Studio.RunService:IsStudio() prints what the portal would have done instead.
A teleport GUI whose buttons send a positionA cheater can fire the same remote with any position.The buttons send a spot name, and the server looks it up.
Coins passed along in teleport dataRoblox says teleport data is visible to the client and unencrypted.Tells you to keep coins and Wins in a data store and load them in the other place (see Carry data to the other place).

What players can and cannot fake

Assume a cheater controls everything on their own device: they can edit TeleportMenu, fire both remotes as often as they like with any arguments, and move their own character. Here is what that gets them with this teleporter.

What a cheater can try, and what Teleporters does about it
A cheater tries toResultWhy
Send a position or a CFrame through the menu remoteIgnoredTeleportRequest reads one string, a spot name of up to 50 characters. Anything else is dropped.
Ask for Castle without 3 WinsRefusedThe server reads the Wins from its own copy of leaderstats. The grey button is only a hint.
Ask for a spot that does not existIgnoredThe server looks the name up in TeleportSpots and does nothing if no part has that name.
Fire the menu remote over and overAt most one menu teleport every 3 secondsThe cooldown is kept on the server, per player.
Set off a pad without walking to itThey reach the partner pad, which they could walk to anywayRoblox lists teleporting to any position and manipulating Touched events among the things a client can do with its own character.
Join another place of your game directlyPossible unless Access Control for Places is Secure within universe onlySee Who can join your other places.
Move their own character anywhere, a locked spot includedPossibleEach device controls its own character's movement. A locked spot is a convenience, not a vault, so check on the server before giving out anything valuable there.

The last row is the honest limit of any teleporter. For a competitive game, add a server-side movement check like the one in the sprint guide. Teleporters already sets the MovementCheckSkip attribute that check reads, so its own teleports are not flagged: Roblox's security docs say games with legitimate teleports need exactly this kind of exemption in their movement checks.

Step 5: Test it

  1. Press Play. Step on PadA: you appear just in front of PadB, facing away from it. Turn round and step straight back onto PadB: nothing happens, because pads ignore you for 2 seconds after you arrive. Step off, wait 2 seconds and walk onto PadB again: you appear in front of PadA.
  2. Wait a few seconds, then click Teleport at the left of the screen. The list shows Lake, Spawn and "Castle (needs 3 wins)" in grey. Pick Lake: you appear on it. Open the menu again and pick Castle: nothing happens, and Output stays quiet.
  3. Give yourself 3 Wins (this needs a leaderstats script with a Wins IntValue, such as the leaderboard guide's). Click the Client/Server toggle to switch to Server, find Players, your name, leaderstats, Wins in the Explorer and set its Value to 3 in the Properties window. Switch back to Client and open the menu again: Castle is purple and takes you there.
  4. Touch DungeonPortal. Output prints a line starting Teleporters: would send with your name and the place ID. That is expected in Studio, and it prints at most once every 2 seconds however long you stand on the portal.
  5. Choose Server & Clients in the test mode dropdown, set 2 clients and press Play. Both players can use the pads at the same time, and one player's cooldown never blocks the other.
  6. Stop the test, publish, and play the game from the Roblox app. Touch the portal: Roblox's loading screen appears and you arrive in the other place. If you stay where you are, open the Developer Console with F9, switch its log to the Server view, which only the game's owner and group members with edit permission can see, and look for the Teleporters: warnings, which include the reason Roblox gave.

Keep the Output window open (Window menu, then Output) during the Studio steps. Teleporters prints nothing when it works, apart from the portal line in step 4, so any warning or red error is worth reading. See Common errors.

Extending it

Teleport a team or a party together

TeleportAsync takes a list of players, so one portal can send a whole group to the same place. Roblox's teleport page suggests starting from the player who touched the portal: player.Team and Team:GetPlayers() for a team, or SocialService:GetPlayersByPartyId() with player.PartyId for a party. Pass that list instead of { player }, and set the leavingForPlace flag for each player in it.

Send a group to its own server

By default, teleported players join a public server of the other place. To send a group to a new reserved server instead, for example for a match, create a TeleportOptions, set its ShouldReserveServer to true and pass it as the third argument: TeleportService:TeleportAsync(placeId, players, options). Roblox notes that failures involving reserved servers in particular benefit from retries, which the script already does.

Carry data to the other place

Teleporting discards any local data for that player. Roblox's teleport data, set with TeleportOptions:SetTeleportData() and read in the other place with player:GetJoinData(), is visible to the client and unencrypted, so use it only for harmless choices such as which map to load. Keep coins, Wins and items in a data store, as in the DataStore tutorial, and load them again when the player arrives in the other place.

A custom loading screen

While a place teleport loads, players see Roblox's standard loading screen. To show your own, call TeleportService:SetTeleportGui() on the client with a ScreenGui, for example one kept in ReplicatedStorage. The teleports in this guide start on the server, so the client has to call it ahead of time, for example as soon as the player joins. Roblox says the screen has to be set again before each teleport and is not used for a place in a different game. It also notes that scripts inside that ScreenGui do not run, so design it as a still screen.

Round teleports and checkpoints

The round system moves every player into the arena with the same kind of PivotTo call at the start of each round, and PivotTo or SpawnLocations in the obby guide compares this approach with Roblox's spawn points. If a spot should only open after a round, the round system already awards the Wins that WinsNeeded reads.

Common errors and fixes

Open the Output window (Window menu, then Output) before you press Play. Teleporters names the pad when a Destination points nowhere, so most problems show up there.

Infinite yield possible on 'ReplicatedStorage:WaitForChild("GetTeleportSpots")'

TeleportMenu is waiting for the remote that Teleporters creates, so Teleporters is not running. Check that it is a Script, not a LocalScript, directly inside ServerScriptService, that it is not disabled, and that Output shows no red error from it. The script errors guide explains this warning in detail.

Teleporters: PadA points to PadC, which is not a part in TeleportPads

The pad's Destination attribute names something that is not a part directly inside the TeleportPads folder. Check the spelling and capitals of the attribute value and of the destination pad's name. The warning appears once per pad, the first time a player touches it.

Stepping on a pad does nothing

Check that the folder is named exactly TeleportPads and sits directly in Workspace when the game starts, that the pad's Destination attribute is a String (a Number attribute is ignored), and that you waited 2 seconds since your last teleport. Also check the pad's CanTouch is on: Roblox says connecting Touched to a part with CanTouch off throws an error, which stops the script.

I land inside a wall or fall off the edge

Players arrive 3 studs in front of the destination pad's front face. Right-click the pad, choose Show Orientation Indicator, and turn the pad until the blue line points at open floor. Menu spots put players on top of the part, so keep each spot on a floor.

The Castle button stays grey after I earned 3 Wins

The list is drawn when the menu opens, so close the menu and open it again. If it is still grey, check that leaderstats has an IntValue named exactly Wins, and that the Wins changed on the server, not only in Client mode.

The portal does nothing in the published game

Open the Developer Console with F9, switch its log to the Server view (only the game's owner and group members with edit permission see it, because Teleporters is a server Script) and read the Teleporters: warnings, which include the reason Roblox gave. Check that the portal's PlaceId attribute is a Number holding the ID from the Asset Manager, and that you published the place again after adding the portal.

Build it with RoCode

If you would rather not wire this up by hand, RoCode can build it in the place you have open. RoCode is an independent AI agent for Roblox Studio, not made by Roblox: you describe the feature in its web chat, and its Studio plugin creates the parts and the scripts in your Explorer, so you are not copying code out of a chat window.

You type

Add teleporters: pads in Workspace.TeleportPads that send players to the pad named in their Destination attribute with a 2 second cooldown, a Teleport menu for the spots in Workspace.TeleportSpots where Castle needs 3 Wins, checked on the server, and portals in Workspace.PlacePortals that send players to the place ID in their PlaceId attribute with retries.

RoCode does
  • Can look through your place when a step needs it, with Search Game and Search Scripts, so it can build on items, remotes or save code you already have instead of adding a second system
  • Creates the folders and the pad parts with Create Instance and sets their properties with Set Property, and writes Teleporters and TeleportMenu with Create Script
  • Is told to compile-check each script it writes with Check Script, which compiles it in Studio without running it
  • Sends its changes in batches, and each batch is an undo point in Studio's history

Place teleports only run in the published game, so test those in the Roblox app yourself. With plugin 3.9 or newer RoCode can run a short playtest and read the errors, but it does not move a character or click, so step on the pads and open the menu yourself. A teleporter is one system among many in a game; building a whole game with RoCode works one system per prompt like this. How RoCode connects to Studio.

Questions

How do I make a teleport pad in Roblox Studio?

Give two parts a Destination attribute naming each other, then let one server script move whoever touches a pad with character:PivotTo to a spot just in front of the other pad, with a short per-player cooldown. Step 1 and Step 2 build exactly that.

Why does my teleporter not work in Studio?

Pads and menus work in Studio. Teleports to another place do not: Roblox's TeleportService does not support playtesting in Studio, so publish the game and test in the Roblox app. The script in this guide prints what a portal would have done instead, so you can still check that it fires.

How do I teleport players to another place in my game?

Add the place with File > Publish As (Add as a new place), copy its place ID from the Asset Manager, and call TeleportService:TeleportAsync(placeId, { player }) from a server Script inside pcall, retrying if it fails. Step 4 walks through it.

How do I make a teleport GUI?

Build the buttons in a LocalScript and send the server only the name of the spot the player picked. The server looks the name up in a folder, checks the cooldown and any unlock rule, then moves the character. Never send a position from the client: a cheater can send any position they like.

Why does my character get stuck or fall apart after teleporting?

Setting the root part's Position moves only that part, not the body joined to it, and copying a pad's CFrame puts the middle of the character inside the pad. Use character:PivotTo with a point at standing height above the floor, worked out from the Humanoid's HipHeight.

Can I send coins or items with a teleport?

Not safely. Roblox says teleport data is visible to the client and unencrypted, so it is fine for something like a chosen map, not for coins. Save coins and items in a data store and load them in the other place.

Sources and further reading

How the code was checked: every script on this page passes Luau's strict type checker against Roblox's API definitions (luau-lsp, 15 October 2026). A type check catches misspelt APIs and wrong types, not game logic, so playtest in Studio before you publish.

Try RoCode on your own place.

Free every day, no card required. Install the plugin, describe the feature, and review what lands in Studio.