In short
Insert a ClickDetector into a Part, and in a server Script connect clickDetector.MouseClick. It passes the Player who clicked, so you can reward or check them. MaxActivationDistance (32 studs by default) sets how close they must be, MouseHoverEnter and MouseHoverLeave fire when the cursor moves on and off, and RightMouseClick handles right clicks.
- Handle
MouseClickon the server, so the result is shared by everyone. - Add a cooldown and a distance check on the server: a cheater can fire clicks from anywhere, much faster than anyone can click.
- For phones and controllers, a ProximityPrompt is usually easier to use than a tap on a small part.
Get the script
ClickDetector button script with a cooldown
A server Script that makes a part a clickable button: it lights up, says who pressed it, checks they are close and can only be pressed again after a cooldown.
-- Script inside the Button part, named ClickButton.
-- Lights up when clicked, then can be pressed again after a cooldown.
local button = script.Parent :: BasePart
local clickDetector = button:WaitForChild("ClickDetector") :: ClickDetector
local COOLDOWN_SECONDS = 2
local OFF_COLOR = Color3.fromRGB(200, 40, 40)
local ON_COLOR = Color3.fromRGB(40, 200, 80)
local pressedAt = -math.huge
button.Color = OFF_COLOR
clickDetector.MouseClick:Connect(function(player: Player)
local now = os.clock()
if now - pressedAt < COOLDOWN_SECONDS then
return
end
-- cheats can fire clicks from any distance, so check it here
local root = player.Character and player.Character:FindFirstChild("HumanoidRootPart")
if not (root and root:IsA("BasePart")) or (root.Position - button.Position).Magnitude > clickDetector.MaxActivationDistance + 5 then
return
end
pressedAt = now
print(player.Name, "pressed the button")
button.Color = ON_COLOR
task.delay(COOLDOWN_SECONDS, function()
button.Color = OFF_COLOR
end)
end)
RoCode builds it in the place you have open in Roblox Studio, on Windows or macOS with a desktop browser; on a phone the button sends the prompt and the link to your computer. Free to start, with free credits every day. More Roblox Studio scripts
Where to put it
Workspace
Button Part new
ClickDetector ClickDetector new
ClickButton Script new
Settings you can change
COOLDOWN_SECONDSIn the script- Seconds before the button can be pressed again. Default:
2.
What a cheater can and cannot doThe cooldown and the distance check run on the server, so clicking faster, or firing clicks from across the map with a cheat, does not press the button.
Type-checked with luau-lsp strict against Roblox's API definitions on 5 November 2026. Not playtested in Studio yet: press Play and watch the Output window before you publish.
Prompt for RoCode
Make the part named Button clickable with a ClickDetector: when a player clicks it, it turns green for 2 seconds, prints who pressed it and opens the gate model, with a 2 second server cooldown.
On this page
How a ClickDetector works
A ClickDetector works on the part it is inside (or on every part of a Model it is inside). When a player's cursor is over that part and within MaxActivationDistance of their character, the cursor changes to a hand, and a click fires MouseClick on the server with that player. On touch screens a tap on the part counts as a click.
| Name | What it does |
|---|---|
MouseClick | Left click (or tap). Passes the player. |
RightMouseClick | Right click. Passes the player. |
MouseHoverEnter / MouseHoverLeave | The cursor moved onto or off the part. Passes the player. |
MaxActivationDistance | How close, in studs, the player's character must be. 32 by default. |
CursorIcon | A custom cursor image while hovering. |
Step 2: Hover effects
A highlight when the cursor is over the part shows players it is clickable. Do this on the client, so only the player hovering sees it. Add a LocalScript in StarterPlayerScripts:
-- LocalScript in StarterPlayerScripts named ButtonHover.
-- Outlines the Button part while this player's cursor is over it.
local button = workspace:WaitForChild("Button") :: BasePart
local clickDetector = button:WaitForChild("ClickDetector") :: ClickDetector
local highlight = Instance.new("Highlight")
highlight.FillTransparency = 1
highlight.OutlineColor = Color3.new(1, 1, 1)
highlight.Enabled = false
highlight.Adornee = button
highlight.Parent = button
clickDetector.MouseHoverEnter:Connect(function()
highlight.Enabled = true
end)
clickDetector.MouseHoverLeave:Connect(function()
highlight.Enabled = false
end)
ClickDetector events fire on the client too, for the local player only, which is what makes this work. The Highlight is created by the LocalScript, so other players never see it.
Step 3: One script for many clickable parts
For a wall of buttons or a dozen item boxes, tag them instead of copying the script. Give each part the tag Clickable and a string attribute Message; this Script adds the ClickDetector itself.
-- Script in ServerScriptService named Clickables.
local CollectionService = game:GetService("CollectionService")
local TAG = "Clickable"
local COOLDOWN_SECONDS = 1
local function setUp(part: Instance)
if not part:IsA("BasePart") or part:FindFirstChildOfClass("ClickDetector") then
return
end
local detector = Instance.new("ClickDetector")
detector.MaxActivationDistance = 20
detector.Parent = part
local lastClick: { [Player]: number } = {}
detector.MouseClick:Connect(function(player: Player)
local now = os.clock()
if now - (lastClick[player] or 0) < COOLDOWN_SECONDS then
return
end
local root = player.Character and player.Character:FindFirstChild("HumanoidRootPart")
if not (root and root:IsA("BasePart")) or (root.Position - part.Position).Magnitude > detector.MaxActivationDistance + 5 then
return -- too far away to have clicked honestly
end
lastClick[player] = now
local message = part:GetAttribute("Message")
print(player.Name, "clicked", part.Name, if typeof(message) == "string" then message else "")
end)
end
for _, part in CollectionService:GetTagged(TAG) do
setUp(part)
end
CollectionService:GetInstanceAddedSignal(TAG):Connect(setUp)
Each part gets its own cooldown per player here, so one player clicking does not block another. The CollectionService guide covers tags and cleaning up when parts are removed.
ClickDetector or ProximityPrompt?
| ClickDetector | ProximityPrompt | |
|---|---|---|
| How players use it | Click or tap the part itself | Press E, a gamepad button or tap the prompt |
| Shows a hint | Only a cursor change on hover | A labelled bubble with the key |
| Gamepads | Awkward: needs a virtual cursor | Built in |
| Hold to use | No | Yes, with HoldDuration |
| Good for | Desktop-first games, small buttons in reach of the mouse, many items close together | Doors, NPCs, chests, anything in most games |
Roblox's security guide says both must be secured as carefully as RemoteEvents, because a cheater can trigger them from any distance, so keep cooldowns and distance checks on the server either way. The ProximityPrompt guide builds the prompt version.
Common errors and fixes
Open the Output window (Window menu, then Output) before you press Play.
The cursor does not change over the part
You are further than MaxActivationDistance (32 studs) from it, the ClickDetector is not inside the part (or its Model), or another part in front of it is blocking the cursor.
Clicking does nothing
Check the Script is a Script inside the part or in ServerScriptService, that it found the right ClickDetector, and add print(player.Name) at the top of the handler.
It works for me but not on my phone
Taps count as clicks, but small parts are hard to hit with a finger. Make the part bigger or use a ProximityPrompt.
Build it with RoCode
If you would rather not set 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 change in a web chat, and its Studio plugin creates the scripts and instances in your Explorer, so there is no code to paste.
Make the three red buttons on the wall clickable: each one, when clicked, lights up green for 2 seconds and opens its matching gate, with a server cooldown per button and an outline when hovered.
- Can find the buttons and gates you mean with Search Game before it writes anything
- Adds the ClickDetectors with Create Instance and writes the scripts with Create Script
- Is told to compile-check each script it writes with Check Script
- Sets an undo point before and after each batch of changes, so Ctrl+Z steps back one batch at a time
Click each button yourself in a playtest, and try it in Studio's Device emulator at phone size. How RoCode connects to Studio.
Questions
How do I make a part clickable in Roblox?
Insert a ClickDetector into the part and connect its MouseClick event in a server Script. The event passes the player who clicked.
How do I know who clicked a ClickDetector?
MouseClick gives you the Player as its first value: clickDetector.MouseClick:Connect(function(player) ... end).
Does ClickDetector work on mobile?
Yes, a tap on the part counts as a click. For small parts, a ProximityPrompt is easier to use on touch screens and gamepads.
How do I change how far away players can click?
Set the ClickDetector's MaxActivationDistance. The default is 32 studs.
Sources and further reading
- Roblox Creator Docs: ClickDetector. MouseClick, hover events and MaxActivationDistance
- Roblox Creator Docs: Proximity prompts
- Roblox Creator Docs: Highlight
- Roblox Creator Docs: Securing the client-server boundary. ClickDetectors and prompts as inputs to check
How the code was checked: every script on this page passes Luau's strict type checker against Roblox's API definitions (luau-lsp, 5 November 2026). A type check catches misspelt APIs and wrong types, not game logic, so playtest in Studio before you publish.