Roblox proximity prompt script (hold E to interact)

The “E Pick up” bubble you see in most Roblox games. One server script gives the player an item; the variations change the key, range and look.

ScriptUpdated November 2, 2026

Where to put it

Script — Inside the part (Workspace > Pickup > Script). It runs on the server, so players can't change what it does.

  1. Insert an anchored Part where the item should be, then insert a ProximityPrompt and a Script inside it.
  2. Put the Tool players should get (for example a tool named Sword) in ServerStorage, so it can't be grabbed directly.

The script

Inside the part (Workspace > Pickup > Script)
local ServerStorage = game:GetService("ServerStorage")

local part = script.Parent
local prompt = part:WaitForChild("ProximityPrompt")
local tool = ServerStorage:WaitForChild("Sword")

prompt.ActionText = "Pick up"
prompt.ObjectText = tool.Name
prompt.HoldDuration = 0.5 -- seconds to hold E; 0 = instant
prompt.MaxActivationDistance = 10

prompt.Triggered:Connect(function(player)
	local backpack = player:FindFirstChildOfClass("Backpack")
	if not backpack then
		return
	end
	local character = player.Character
	-- One copy per player: skip if it's in the backpack or in their hand.
	if backpack:FindFirstChild(tool.Name) or (character and character:FindFirstChild(tool.Name)) then
		return
	end
	tool:Clone().Parent = backpack
end)

How it works

  • The prompt appears when a player is within MaxActivationDistance studs. On a keyboard it shows E, on a gamepad a button, and on phones a tap button.
  • HoldDuration turns a tap into a hold with a progress ring — good for actions that shouldn't happen by accident.
  • Triggered fires on the server with the player who used it, so the server decides what they get. Clients can't give themselves items.

Variations

Cooldown per player

Lets each player use the prompt once every 30 seconds — useful for a free reward or a food stand.

local COOLDOWN = 30
local lastUsed = {}

prompt.Triggered:Connect(function(player)
	local now = os.clock()
	if lastUsed[player] and now - lastUsed[player] < COOLDOWN then
		return
	end
	lastUsed[player] = now
	-- give the reward here
end)

game:GetService("Players").PlayerRemoving:Connect(function(player)
	lastUsed[player] = nil
end)

Different key, range and visibility

Set these in Properties or in the script. RequiresLineOfSight hides the prompt when a wall is between the player and the part.

prompt.KeyboardKeyCode = Enum.KeyCode.F
prompt.GamepadKeyCode = Enum.KeyCode.ButtonY
prompt.MaxActivationDistance = 6
prompt.RequiresLineOfSight = false
prompt.Exclusivity = Enum.ProximityPromptExclusivity.OnePerButton

Your own prompt look

Set the prompt's Style to Custom and draw it yourself in a LocalScript in StarterPlayerScripts. The server script above stays the same.

local ProximityPromptService = game:GetService("ProximityPromptService")

ProximityPromptService.PromptShown:Connect(function(prompt)
	if prompt.Style ~= Enum.ProximityPromptStyle.Custom then
		return
	end
	local gui = Instance.new("BillboardGui")
	gui.Size = UDim2.fromOffset(160, 40)
	gui.StudsOffset = Vector3.new(0, 3, 0)
	gui.AlwaysOnTop = true
	gui.Adornee = prompt.Parent

	local label = Instance.new("TextLabel")
	label.Size = UDim2.fromScale(1, 1)
	label.BackgroundColor3 = Color3.fromRGB(20, 20, 30)
	label.TextColor3 = Color3.new(1, 1, 1)
	label.Font = Enum.Font.GothamBold
	label.TextScaled = true
	label.Text = "[" .. prompt.KeyboardKeyCode.Name .. "] " .. prompt.ActionText
	label.Parent = gui
	Instance.new("UICorner", label)

	gui.Parent = game:GetService("Players").LocalPlayer.PlayerGui
	prompt.PromptHidden:Wait()
	gui:Destroy()
end)

Common mistakes

  • Handling Triggered in a LocalScript to give items: the item exists only on that player's screen and exploiters can fire it at will. Give items on the server.
  • Putting the prompt somewhere it can't show: it needs a Part or an Attachment as its parent (a Model works only with a PrimaryPart).
  • The prompt never appears because the part is inside a wall or another part — move it, or turn off RequiresLineOfSight.
  • Many prompts close together all show at once. Lower MaxActivationDistance or set Exclusivity to OnePerButton.

FAQ

How do I make a proximity prompt in Roblox Studio?

Select a part, click + and insert a ProximityPrompt, then add a Script that listens to prompt.Triggered. The player who pressed it is passed to the function.

How do I change the proximity prompt key?

Set KeyboardKeyCode (for example Enum.KeyCode.F) and GamepadKeyCode. Phones always get a tap button.

Should a proximity prompt script be a Script or a LocalScript?

A Script, so the server decides what happens. Use a LocalScript only for looks, such as a custom prompt design.

Why is my proximity prompt not showing?

Check that Enabled is on, the player is within MaxActivationDistance, nothing blocks the line of sight, and the prompt sits in a Part or Attachment.

Keep reading