Roblox ProximityPrompt Script: Triggered, Hold & Cooldown

Last updated:

Quick answer: Insert a ProximityPrompt into a part, then connect `prompt.Triggered` in a server Script. The callback receives the player who pressed the key, so you can give items, open doors or start events. Set `HoldDuration` for hold-to-use and flip `Enabled` to build cooldowns.

A ProximityPrompt is the built-in "press E to interact" button in Roblox. You parent one to a part, set its text and distance, and connect a function to its Triggered event. When a player gets close and presses the key, Roblox fires that event and hands you the Player who did it. It replaces the old ClickDetector for most interaction, and it works on keyboard, gamepad and touch without any extra code from you.

How do you create a ProximityPrompt?

You can add one in Studio (Part, then the plus icon, then ProximityPrompt) or create it from code. Doing it from code is useful when you spawn items at runtime:

local part = workspace.Door

local prompt = Instance.new("ProximityPrompt")
prompt.ActionText = "Open"
prompt.ObjectText = "Wooden Door"
prompt.KeyboardKeyCode = Enum.KeyCode.E
prompt.MaxActivationDistance = 8
prompt.HoldDuration = 0
prompt.RequiresLineOfSight = true
prompt.Parent = part

The properties you will touch most often:

How do you detect when someone uses it?

Connect to Triggered. Put this in a Script (not a LocalScript) so the logic runs on the server:

local prompt = script.Parent.ProximityPrompt

prompt.Triggered:Connect(function(player: Player)
	print(player.Name .. " used the prompt")
end)

Unlike the Touched event, you do not need to dig a player out of a body part. The argument already is the Player, so there is no GetPlayerFromCharacter step. If you want to compare it with how that works, the Touched event guide shows the extra work a physical trigger needs.

Can you make a hold-to-use prompt?

Set HoldDuration to a number of seconds. Roblox draws the progress ring and only fires Triggered once the hold completes. Two companion events let you react earlier:

prompt.HoldDuration = 2
prompt.ActionText = "Open chest"

prompt.PromptButtonHoldBegan:Connect(function(player)
	print(player.Name .. " started holding")
end)

prompt.PromptButtonHoldEnded:Connect(function(player)
	print(player.Name .. " let go early (or finished)")
end)

prompt.Triggered:Connect(function(player)
	print(player.Name .. " finished the hold")
end)

Remember that PromptButtonHoldEnded fires whether the hold finished or was cancelled, so use Triggered for the real action.

How do you add a cooldown?

The easiest approach is to disable the prompt while the cooldown runs. Players see it vanish, so you also get free feedback:

local COOLDOWN = 5
local prompt = script.Parent.ProximityPrompt

prompt.Triggered:Connect(function(player)
	prompt.Enabled = false

	-- give the reward here
	local leaderstats = player:FindFirstChild("leaderstats")
	if leaderstats and leaderstats:FindFirstChild("Coins") then
		leaderstats.Coins.Value += 10
	end

	task.wait(COOLDOWN)
	prompt.Enabled = true
end)

If each player should have their own cooldown (for example a daily chest), disabling the prompt for everyone is the wrong tool. Track a timestamp per player in a table keyed by UserId and compare it with os.time() inside the callback instead.

How do you handle lots of prompts at once?

Copying the same script into forty doors does not scale. Tag the parts with CollectionService and use one script. ProximityPromptService also exposes a global PromptTriggered event that fires for any prompt, which is convenient for a central interaction system:

local ProximityPromptService = game:GetService("ProximityPromptService")
local CollectionService = game:GetService("CollectionService")

local handlers = {
	Door = function(player, prompt)
		print(player.Name .. " opened " .. prompt.Parent.Name)
	end,
	Chest = function(player, prompt)
		print(player.Name .. " looted " .. prompt.Parent.Name)
	end,
}

ProximityPromptService.PromptTriggered:Connect(function(prompt, player)
	for tag, handler in handlers do
		if CollectionService:HasTag(prompt.Parent, tag) then
			handler(player, prompt)
			return
		end
	end
end)

Put the handlers in a ModuleScript once the table grows; the ModuleScript guide shows how.

Can you customise how the prompt looks?

Set Style to Enum.ProximityPromptStyle.Custom and build your own UI listening to ProximityPromptService.PromptShown and PromptHidden in a LocalScript. That is a larger topic, and the GUI scripting basics cover the building blocks. For most games the default look is fine and a small tweak of UIOffset or ObjectText is enough.

Common mistakes

Practice it

Interaction systems are a good first project because the loop is short: build the part, add the prompt, see the result. Try it in the Luablox lessons, follow with the theory lessons, and test yourself on the practice problems.

Related guides: Touched events, tool scripts, and server-side validation for keeping interactions honest.

Frequently asked questions

Should I handle ProximityPrompt.Triggered on the server or the client?

Handle anything that changes game state on the server, because the server version of Triggered cannot be faked by editing a LocalScript. Use a LocalScript with the same event only for visual effects such as sounds or camera moves that only that player needs to see.

Why does my ProximityPrompt not show up?

Check that the prompt is Enabled, that the player is within MaxActivationDistance, and that RequiresLineOfSight is not blocking it behind a wall. Also make sure the parent is a BasePart or Attachment that is actually in the workspace and not anchored far from where you are standing.

How do I change the key a ProximityPrompt uses?

Set KeyboardKeyCode, for example Enum.KeyCode.F, and GamepadKeyCode for controllers. Touch players always get an on-screen button, so you do not need to handle that separately.

How do I stop players spamming a prompt?

Set prompt.Enabled to false inside the Triggered callback, wait for your cooldown with task.wait, then set it back to true. Because Enabled is a property, the prompt disappears for everyone during the cooldown, which doubles as visual feedback.

Learn core Roblox scripting and Luau programming concepts, including: roblox proximityprompt script, proximityprompt triggered, roblox hold e to interact, proximityprompt holdduration, proximitypromptservice.

Related pages