How Bedrock Selectors Handle Dead Players
The foundation of a command-only respawn detector is a deliberate difference between two target selectors: @a and @e[type=player]. In Minecraft Bedrock, @a is the only selector capable of targeting players who are currently dead and looking at the 'You Died!' screen. By contrast, @e[type=player] treats the player as a standard entity and completely ignores anyone whose health has dropped to zero and has not yet clicked Respawn.
By combining these two selectors with the RM (minimum radius) or R (maximum radius) arguments, or more reliably by negating a live-entity check, you can isolate players who are currently dead. However, you cannot execute nested selector checks directly inside a single target bracket. Instead, you use a two-step tag system that marks all players as potentially dead, and then immediately clears that mark from anyone who is still alive.
Once a player is confirmed dead, they hold onto a persistent marker tag while they sit on the death screen. The exact tick they click the Respawn button, their entity becomes valid again in the world, allowing @e[type=player] to find them, run your respawn commands, and strip the marker tag so the commands only fire once.
| Selector | Targets Alive Players | Targets Dead Players | Typical Use in Respawn Detection |
|---|---|---|---|
| @a | Yes | Yes | Applying initial check tags and maintaining state while on the death screen. |
| @e[type=player] | Yes | No | Clearing check tags from living players and triggering the final respawn reward. |
| @p | Yes | No | Finding the closest living player; ignored during the death screen state. |
| @s | Yes | Depends on caller | Executing the actual reward sequence once the player is confirmed alive again. |
Registering the Tick Function
For this detection loop to feel instant, it must run every game tick (20 times per second). In a behavior pack, you accomplish this by registering an mcfunction file inside BP/functions/tick.json. Every function listed in the values array of this file will execute automatically from the server context on every tick, without needing repeating command blocks placed in the world.
Keep your tick function dedicated to orchestration or lightweight checks. If you already have a main tick file in your pack, you can either paste the detection lines directly into that file or call the respawn handler as a sub-function using the function command.
{
"values": [
"respawn_check"
]
}The Tag-Based Respawn Loop
Create the function file referenced in your tick configuration. The order of commands in this file is critical. If you swap the death detection and the respawn execution blocks, a player could theoretically be flagged as dead and immediately flagged as respawned within the same tick, or fail to trigger at all depending on the execution order.
In the first half of the function, we check if any player who was previously marked with the is_dead tag has returned to life. We do this by targeting @e[type=player,tag=is_dead]. Because @e[type=player] only sees living players, this selector will completely ignore the player while they are on the death screen. The moment they click Respawn, they match the selector. We then run a separate reward function as that player and immediately remove the is_dead tag.
In the second half of the function, we detect new deaths. Every tick, we give every connected player (@a) a temporary tag called check_alive. On the very next line, we remove check_alive from every living player (@e[type=player]). Anyone who still possesses the check_alive tag on the third line must be dead, so we grant them the persistent is_dead tag and clean up the temporary tag.
# 1. Detect players who were dead and are now alive again
execute as @e[type=player,tag=is_dead] at @s run function on_player_respawn
tag @e[type=player,tag=is_dead] remove is_dead
# 2. Detect players who are currently on the death screen
tag @a add check_alive
tag @e[type=player] remove check_alive
tag @a[tag=check_alive] add is_dead
tag @a[tag=check_alive] remove check_aliveWriting the Respawn Action Function
Because we called the sub-function using execute as @e[type=player,tag=is_dead] at @s, the entire on_player_respawn.mcfunction file runs with the newly respawned player as the @s executor and their exact spawn location (bed, respawn anchor, or world spawn) as the execution position. You do not need to repeat tag checks inside this file.
This separation makes your pack much easier to maintain. Whenever you want to change what happens on respawn—such as giving a Wooden Sword, applying temporary spawn protection via Resistance, or playing a sound—you only edit this reward file without touching the sensitive tag-swapping logic in the tick loop.
Keep in mind that if the game rule keepInventory is false, the player's inventory is already empty by the time they click Respawn and this function fires. It is completely safe to use give or replaceitem here without worrying about items dropping on the old death location.
# Grant 5 seconds of spawn protection
effect @s resistance 5 4 true
effect @s weakness 5 4 true
# Provide a basic starter tool
give @s wooden_pickaxe 1 0
# Visual and audio feedback at the respawn point
playsound random.orb @s ~~~ 1.0 1.2
particle minecraft:totem_particle ~~~
title @s actionbar You have respawned!Handling Edge Cases: Combat Logging and Dimension Changes
A common edge case in multiplayer worlds is a player dying, closing the game while still on the death screen, and rejoining later. Because entity tags are saved directly to the player's NBT data on disk, a player who disconnects while holding the is_dead tag will still have that tag when they log back in. When they rejoin and click Respawn, the @e[type=player,tag=is_dead] selector will catch them normally and run your function.
Another scenario to consider is the doImmediateRespawn gamerule. When doImmediateRespawn is set to true, the death screen is skipped entirely. However, in Bedrock's tick execution order, there is usually still a single tick where the player's health is zero before the game forces the respawn, or conversely, the death and respawn happen between server ticks so fast that the tag check misses them. If your map requires immediate respawning, test the tag loop thoroughly; if it drops detections under heavy server lag, you should switch to the Script API method below.
Dimension transitions (such as dying in the Nether and respawning at a bed in the Overworld) are handled cleanly by the at @s modifier in our execute command. By the time @e[type=player] is able to target the player again, the game has already moved them to their destination dimension and coordinates.
Alternative: The Script API Event Listener
If your add-on already uses a script module with @minecraft/server, you do not need to run a tick function or manage tags at all. The Script API exposes a dedicated world.afterEvents.playerSpawn event that fires whenever a player spawns into the world. This event passes a property called initialSpawn, which is a boolean.
When a player joins the server for the session, initialSpawn is true. When a player dies and clicks the Respawn button (or walks through the End exit portal), initialSpawn is false. Checking that single boolean gives you an event-driven respawn hook with zero per-tick performance overhead, and it works reliably even when doImmediateRespawn is enabled.
Note that returning from the End dimension via the exit portal also triggers playerSpawn with initialSpawn set to false. If your players have access to the End and you use the script method, you may still want to combine it with an entityDie after-event or a dynamic property flag if you need to distinguish an End return from an actual death.
import { world } from "@minecraft/server";
world.afterEvents.playerSpawn.subscribe((eventData) => {
const { player, initialSpawn } = eventData;
// Ignore players who are just logging into the world
if (initialSpawn) return;
// Run our mcfunction as the respawned player
player.runCommandAsync("function on_player_respawn");
});Which versions this applies to
The mcfunction and tag recipe works in Bedrock Edition 1.19.50 and newer (using the modern execute syntax). No experimental toggles are required for functions or the @minecraft/server playerSpawn event in current stable releases.
When it does not work
| What you see | Why | The fix |
|---|---|---|
| Function 'on_player_respawn' fires 20 times a second forever after the player dies once. | The command removing the 'is_dead' tag is missing, misspelled, or placed inside a conditional check that fails, leaving the tag permanently attached to the living player. | Ensure 'tag @e[type=player,tag=is_dead] remove is_dead' is in 'respawn_check.mcfunction' immediately after the execute line, not inside a conditional command block. |
| Content Log shows: 'Syntax error: Unexpected "as": at "execute >>as<< @e[type=player..."' | Your behavior pack's 'manifest.json' has a 'min_engine_version' set lower than [1, 19, 50], forcing the game to parse functions using the legacy execute syntax. | Update 'min_engine_version' in the header of 'BP/manifest.json' to at least [1, 19, 50] or [1, 20, 0] so the modern 'execute as ... at ... run' syntax is enabled. |
| Particles and sounds play at world spawn (0, 0, 0) instead of at the player's bed when they respawn. | The function was called with 'execute as @e[type=player,tag=is_dead] run...', which changes the executor (@s) to the player, but leaves the execution position at the server's tick origin. | Add 'at @s' before 'run' in the execute command ('execute as @e[type=player,tag=is_dead] at @s run function on_player_respawn') to shift the coordinate context to the player. |
Reference, straight from the game files
Read out of the game itself, so the ids match the version you are building for.
