Advancements

The complete advancement JSON format — display, criteria, all 58 triggers, requirements logic and rewards — plus the single most important datapack pattern: using an invisible advancement as a silent, self-rearming event listener.

Overview & folder

An advancement is a single JSON file at data/<namespace>/advancement/<path>.json. Its resource id is <namespace>:<path>, with subfolders folding into the path — data/foo/advancement/story/root.json becomes foo:story/root. Advancements do three jobs:

Only criteria is strictly required for a functional advancement; everything else is optional. A root advancement (no parent) with a valid display creates a tab.

⚠ Version differences
  • since 1.21 (pack_format 48, snapshot 24w21a): the folder is singular advancement/.
  • before 1.21 (1.20.6 and earlier): the folder was plural advancements/.
  • since 1.20.5: the icon and item predicates use id + components — the old item + nbt string will fail to parse on 1.20.5+.

Root JSON schema

The top-level fields of an advancement file:

FieldTypeReq?DefaultNotes
parentstring (resource id)NoParent advancement. Omit → this is a root (its own tab). Circular parents fail to load.
displayobjectNoVisual presentation. Omit → invisible in the GUI but still functions (ideal for hidden detectors).
criteriaobjectYesMap of criterion name → trigger object. At least one required.
requirementsarray of arraysNoone sublist per criterion (AND)Boolean completion logic — see requirements semantics.
rewardsobjectNoRewards on completion.
sends_telemetry_eventbooleanNofalseIf true, completion sends an official Mojang telemetry event. Only honored for advancements in the minecraft namespace; custom-namespace advancements ignore it. Leave false/omit for datapacks.

A criterion is "<name>": { "trigger": "<id>", "conditions": { ... } }. The <name> is arbitrary and is what you reference in requirements[] and in advancement grant @s only <adv> <name>. conditions is trigger-specific and always optional — omit it and the trigger fires on any occurrence of that event.

data/example/advancement/detect/eat_apple.json — silent event-listener skeleton

{
  "criteria": {
    "ate": {
      "trigger": "minecraft:consume_item",
      "conditions": {
        "item": { "items": ["minecraft:apple"] }
      }
    }
  },
  "rewards": {
    "function": "example:on_eat_apple"
  }
}

No display → invisible in the GUI, no toast, no chat spam. A pure logic hook.

The display object

Present to make the advancement visible in the GUI. Omit it entirely for silent detectors.

FieldTypeReq? (if display)DefaultNotes
iconobjectYesSee the icon table below.
titletext component (string/object/array)YesShown in the toast + GUI.
descriptiontext componentYesShown in the GUI tooltip.
framestring enumNo"task"task (square), goal (rounded), challenge (spiky — plays a sound + purple toast).
backgroundstring (texture path)NoRoot-only. Tab background texture — see Tabs & backgrounds.
show_toastbooleanNotruePop-up toast on completion. Set false for silent detectors.
announce_to_chatbooleanNotrueBroadcasts "PlayerName has made the advancement [Title]" to chat. Set false for silent detectors. Also globally gated by the announceAdvancements gamerule.
hiddenbooleanNofalseHides this advancement and its children in the GUI until earned. Does not stop the toast/chat.

The icon object

FieldTypeReq?DefaultNotes
idstring (item id)Yese.g. "minecraft:diamond".
countintegerNo1Stack size (cosmetic).
componentsobjectNo1.20.5+ item components (e.g. minecraft:custom_model_data, minecraft:enchantments). Replaces the old nbt string.
⚠ Version differences
  • before 1.20.5: the icon used "item" + an "nbt" SNBT string.
  • since 1.20.5: the field is "id" and extra data goes in a structured "components" object. Using nbt on 1.20.5+ will fail to parse.

data/example/advancement/root.json — full displayed root advancement

{
  "display": {
    "icon": { "id": "minecraft:grass_block" },
    "title": { "text": "Example Pack", "color": "gold" },
    "description": "The start of a custom tree",
    "background": "minecraft:textures/gui/advancements/backgrounds/stone.png",
    "frame": "task",
    "show_toast": true,
    "announce_to_chat": false,
    "hidden": false
  },
  "criteria": {
    "tick": { "trigger": "minecraft:tick" }
  }
}

data/example/advancement/challenges/beat_ender_dragon.json — challenge with multiple rewards

{
  "parent": "example:root",
  "display": {
    "icon": { "id": "minecraft:dragon_egg" },
    "title": "Dragonslayer",
    "description": "Defeat the Ender Dragon",
    "frame": "challenge",
    "show_toast": true,
    "announce_to_chat": true
  },
  "criteria": {
    "killed_dragon": {
      "trigger": "minecraft:player_killed_entity",
      "conditions": { "entity": { "type": "minecraft:ender_dragon" } }
    }
  },
  "rewards": {
    "experience": 500,
    "loot": ["example:rewards/dragon_loot"],
    "function": "example:grant_dragon_title"
  }
}

The rewards object

All four fields are independent and optional; a completed advancement fires every one present, simultaneously.

FieldTypeNotes
experienceintegerRaw XP points (not levels). Default 0.
recipesarray of recipe idsUnlocks these recipes in the recipe book — see recipe-unlock advancements.
lootarray of loot-table idsGenerates loot from each table directly into the player's inventory.
functionstring (function id)Runs a single function as @s = the player who completed it. Function tags are NOT allowed — must be a concrete function. This is the datapack workhorse.

Complete trigger list (58)

All 58 vanilla trigger ids, pulled verbatim from the machine-readable registry (misode/mcmeta, trigger_type/data.json, tracking snapshot 26.3-snapshot-3). Prefix each with minecraft:. Because that branch is newer than the 1.21 baseline, triggers that did not exist in 1.21.0 are flagged below the table.

TriggerFires when…
allay_drop_item_on_block 1.19+an allay drops an item onto a block near the player
any_block_useplayer uses a block (any use path — default or item-specific)
avoid_vibration 1.19+player sneaks to avoid producing a vibration
bee_nest_destroyedplayer breaks a bee nest / beehive
bred_animalsplayer breeds two animals
brewed_potionplayer takes a potion out of a brewing stand
changed_dimensionplayer crosses between dimensions
channeled_lightningplayer triggers Channeling on a trident hit
construct_beaconplayer is near a beacon whose pyramid level changes
consume_itemplayer finishes eating/drinking (or otherwise consuming) an item
crafter_recipe_crafted 1.21+a Crafter block crafts a recipe near the player
cured_zombie_villagerplayer cures a zombie villager
default_block_useplayer triggers a block's default interaction
effects_changeda status effect is added/removed on the player
enchanted_itemplayer enchants an item at an enchanting table
enter_blockplayer's hitbox is inside a given block/state
entity_hurt_playerplayer takes damage from an entity
entity_killed_playeran entity kills the player
fall_after_explosionplayer lands after being launched by an explosion/wind
fall_from_heightplayer lands having fallen a distance / between elevations
filled_bucketplayer fills a bucket
fishing_rod_hookedplayer reels in a fishing rod with something hooked
hero_of_the_villagea raid the player helped win ends
impossiblenever — command/reward-only marker
inventory_changedplayer's inventory contents change
item_durability_changedan item's durability changes
item_used_on_blockplayer right-clicks a block with an item (item action)
kill_mob_near_sculk_catalyst 1.19+player kills a mob near a sculk catalyst
killed_by_arrowplayer kills entities with an arrow/projectile
levitationplayer has levitation for some ticks/distance
lightning_strikelightning strikes near the player
locationpolled — player is at a matching location
nether_travelplayer travels then exits the Nether (measures overworld distance)
placed_blockplayer places a block
player_generates_container_loota loot table generates for a container the player opens
player_hurt_entityplayer deals damage to an entity
player_interacted_with_entityplayer right-clicks/interacts with an entity (with an item)
player_killed_entityplayer kills an entity
player_sheared_equipment 1.21.xplayer shears equipment off a mob
recipe_crafted 1.20+player crafts a specific recipe (crafting-table result)
recipe_unlockedplayer unlocks a recipe
ride_entity_in_lava 1.21+player rides an entity across lava
shot_crossbowplayer fires a crossbow
slept_in_bedplayer enters/sleeps in a bed
slide_down_blockplayer slides down a block (honey/etc.)
spear_mobs post-1.21player hits multiple mobs with a charged spear
started_ridingplayer starts riding an entity
summoned_entityplayer summons an entity (golem, wither, etc.)
tame_animalplayer tames an animal
target_hitplayer hits a target block with a projectile
thrown_item_picked_up_by_entityan entity picks up an item the player threw
thrown_item_picked_up_by_playerplayer picks up a thrown item
tickevery tick, per online player
used_ender_eyeplayer uses an eye of ender
used_totema totem of undying saves the player
using_itempolled while the player is holding-use on an item
villager_tradeplayer completes a trade with a villager
voluntary_exileplayer causes a raid by getting Bad Omen at a village
📌 Note

The table is the 26.3-snapshot registry (58 triggers); not all existed in 1.21.0. spear_mobs is a post-1.21 (26.x era) addition tied to the spear item — do not use it in a 1.21 pack. crafter_recipe_crafted arrived with the Crafter block in 1.21. ride_entity_in_lava and fall_after_explosion are Tricky-Trials-era, present by 1.21. any_block_use/default_block_use are part of the interaction-trigger refactor — if targeting exactly 1.21.0/48, verify against the wiki before relying on them; item_used_on_block is the long-stable equivalent for item-on-block.

⚠ Gotcha

Before shipping a version-sensitive trigger, confirm it exists in your exact pack_format by checking the registry for that version (an mcmeta version branch) or the wiki trigger's own History section. Do not assume the 26.3 list applies to 1.21.

Condition schemas

Every trigger's conditions also accepts "player": [ <predicate conditions...> ] — a list of predicate objects tested against the triggering player — except minecraft:impossible. It is omitted from the schemas below for brevity.

Most-used trigger conditions

minecraft:impossible — no conditions. Never fires on its own. Used purely as a reward/flag holder.

minecraft:tick — no conditions (beyond player). Fires every tick. Combine with a player predicate to test state continuously.

minecraft:inventory_changed

{
  "items": [ { /* item predicate: matches an added item */ } ],
  "slots": {
    "empty":    <int or {"min":_,"max":_}>,
    "full":     <int or range>,
    "occupied": <int or range>
  }
}

Each entry in items[] must match at least one item currently in the inventory.

minecraft:consume_item

{ "item": { /* item predicate for the consumed item */ } }

minecraft:location

{ "location": [ { /* location predicate: position/biome/structure/dimension/block/fluid/light/smokey */ } ] }

Polled roughly every 20 ticks. Use for "player is in biome / structure / dimension".

minecraft:player_killed_entity (also entity_killed_player, kill_mob_near_sculk_catalyst)

{
  "entity":       { /* entity predicate for the victim, or a list of predicate conditions */ },
  "killing_blow": { /* damage-type predicate: how it died */ }
}

minecraft:item_used_on_block (right-click an item onto a block)

{
  "location": [
    {
      "condition": "minecraft:location_check",
      "predicate": { "block": { "blocks": ["minecraft:..."], "state": { } } }
    }
    /* plus a location predicate whose `tool` sub-field matches the item used */
  ],
  "item": { /* item predicate for the used item (version-dependent placement) */ }
}

The block is tested via a location predicate; the held item is tested via that predicate's tool item sub-predicate (or the item field, depending on version). minecraft:placed_block uses the same location array shape, describing the placed block's state, position and the tool/item used.

minecraft:recipe_crafted

{
  "recipe_id":   "minecraft:...",              /* required: which recipe */
  "ingredients": [ { /* item predicate */ } ]  /* optional: which items went in */
}

This is what powers "craft with a specific item" detection — it exposes recipe_id and per-slot ingredients.

minecraft:using_item (polled while holding right-click on an item)

{ "item": { /* item predicate; use predicates:{minecraft:custom_data:...} for custom items */ } }

minecraft:slide_down_block

{ "block": "minecraft:honey_block", "state": { "<property>": "<value>" } }

minecraft:allay_drop_item_on_block

{
  "location": [ { /* location/block predicate for the drop target */ } ],
  "item":     { /* item predicate for the dropped item */ }
}

Sub-predicate quick reference

PredicateTop-level keys
Entityentity_type (type in older names), nbt, team, location, stepping_on, movement_affected_by, distance, flags (is_baby/is_on_fire/is_sneaking/is_sprinting/is_swimming/is_flying/is_on_ground), equipment (mainhand/offhand/head/chest/legs/feet/body), slots, effects, vehicle, passenger, targeted_entity, movement, periodic_tick, predicates (data-component predicates), type_specific (variants: player, fishing_hook, lightning, raider, sheep, …).
Itemitems (id list or #tag), count (range), components (exact component match), predicates (partial/sub-predicate match — e.g. minecraft:custom_data, minecraft:enchantments, minecraft:damage). custom_data is the standard way to tag a custom item for detection.
Locationposition (x/y/z ranges), biomes, structures, dimension, block (blocks + state + nbt), fluid, light, can_see_sky, smokey, tool (item predicate for the held item — used by block-interaction triggers).
⚠ Version differences
  • since 1.20.5: item predicates match with id-style component data — use components for exact matches and predicates (e.g. minecraft:custom_data) for partial matches.
  • before 1.20.5: item predicates used item + an nbt SNBT string.
  • in 1.15 and earlier: the field names for entity/item predicates and the criteria/requirements format differed; everything here assumes the modern (1.16+) predicate format.

requirements AND/OR logic

requirements is an array of arrays of criterion names. The completion rule:

📌 Note

The advancement is granted when every sublist has at least one completed criterion. The outer array is joined by AND (all sublists must be satisfied); each inner array is joined by OR (any one criterion in it satisfies that sublist).

If requirements is omitted, the default is one sublist per criterion → all criteria must be met (pure AND).

Pure AND (default, written explicitly)

"criteria": { "a": {...}, "b": {...}, "c": {...} },
"requirements": [ ["a"], ["b"], ["c"] ]

Pure OR — "any one of N"

"criteria": { "a": {...}, "b": {...}, "c": {...} },
"requirements": [ ["a", "b", "c"] ]

Completing a or b or c grants it — the canonical "detect one of several items/events" form.

Mixed — (a OR b) AND c

"requirements": [ ["a", "b"], ["c"] ]
⚠ Gotcha
  • Every criterion listed in criteria should appear somewhere in requirements; a criterion omitted from requirements can never contribute to completion.
  • An empty inner list [] can never be satisfied → the advancement becomes command-only.
  • Criterion names in requirements must exactly match keys in criteria, or the pack fails validation.

Event-listener detection pattern

Advancements are the cleanest event listeners in vanilla datapacks. The loop:

  1. Write an advancement whose criterion is the event you want (consume_item, player_killed_entity, using_item, item_used_on_block, …), with no display so it is invisible/silent.
  2. Give it a rewards.function that runs your logic as @s (the player).
  3. Inside that function, revoke the advancement from that player so it can fire again: advancement revoke @s only <namespace>:<path>.

Because the reward function runs with @s = the completing player and revocation re-arms the listener, this yields reliable, per-player, single-execution event handling with no per-tick scanning — far cheaper and more precise than polling scoreboards for most discrete events.

⚠ Version differences
  • since 1.20.5: making a custom item "consumable"/"usable" so consume_item or using_item fires is done via item components (minecraft:consumable, minecraft:food).
  • before 1.20.5: the same was done through NBT.

Detect eating a custom golden apple

data/mypack/advancement/detect/ate_special.json

{
  "criteria": {
    "ate": {
      "trigger": "minecraft:consume_item",
      "conditions": {
        "item": {
          "items": ["minecraft:golden_apple"],
          "predicates": { "minecraft:custom_data": "{special:true}" }
        }
      }
    }
  },
  "rewards": { "function": "mypack:on_ate_special" }
}

data/mypack/function/on_ate_special.mcfunction

# @s is the player who just ate the item
effect give @s minecraft:regeneration 10 2
playsound minecraft:entity.player.levelup player @s
# re-arm the listener so it can fire again next time
advancement revoke @s only mypack:detect/ate_special

Right-click detection via item_used_on_block

Detect right-clicking a custom wand on any block:

data/mypack/advancement/detect/wand_use.json

{
  "criteria": {
    "used": {
      "trigger": "minecraft:item_used_on_block",
      "conditions": {
        "item": { "predicates": { "minecraft:custom_data": "{wand:true}" } }
      }
    }
  },
  "rewards": { "function": "mypack:on_wand_use" }
}

data/mypack/function/on_wand_use.mcfunction

execute at @s anchored eyes run particle minecraft:end_rod ^ ^ ^2 0 0 0 0 1
advancement revoke @s only mypack:detect/wand_use
📌 Note

item_used_on_block only fires when clicking a block. To detect a right-click in air or on entities, use using_item (needs a consumable/usable component) or the classic carrot-on-a-stick statistic method below.

Mob-kill counter

data/mypack/advancement/detect/killed_zombie.json

{
  "criteria": {
    "kill": {
      "trigger": "minecraft:player_killed_entity",
      "conditions": { "entity": { "type": "minecraft:zombie" } }
    }
  },
  "rewards": { "function": "mypack:count_zombie_kill" }
}

data/mypack/function/count_zombie_kill.mcfunction

scoreboard players add @s zombie_kills 1
advancement revoke @s only mypack:detect/killed_zombie
execute if score @s zombie_kills matches 100.. run function mypack:reward_100_kills

Detection cookbook

GoalApproach
Consume detection (food/potions)consume_item + custom_data item predicate + revoke. Best for anything with a use-consume animation.
Right-click a blockitem_used_on_block.
Right-click anywhere (air/entity)(a) give the item a minecraft:consumable component and use using_item; or (b) the carrot-on-a-stick / warped-fungus-on-a-stick trick — a scoreboard with criterion minecraft.used:minecraft.carrot_on_a_stick, a per-tick check, then reset the score. COAS registers a use every ~4 ticks while held; use custom_data to distinguish your item.
Kill counters / boss logicplayer_killed_entity + revoke.
Continuous statea displayless tick advancement with a player predicate fires every tick while the condition holds; pair its function with revoke for edge-detection, or gate inside the function.
🎩 Trick

An advancement whose only criterion is minecraft:impossible can only be granted by command (advancement grant), making it a clean, persistent per-player boolean flag readable via advancement / execute if against entity data.

💡 Best practice

Silence is mandatory for detectors: omit display entirely (no toast, no chat, no GUI clutter). If you do need a display on a detector, set show_toast: false and announce_to_chat: false.

Recipe-unlock advancements

Recipes appear in the player's recipe book only once unlocked. Two mechanisms:

  1. Automatic discovery — obtaining any item that is an ingredient (or the result) of a recipe auto-unlocks it. This is driven by auto-generated advancements under the minecraft:recipes/... id space.
  2. rewards.recipes on an advancement — completing an advancement unlocks the listed recipes. This is exactly how vanilla's minecraft:recipes/<category>/<name> advancements work: each is a hidden advancement whose criteria (inventory_changed, recipe_unlocked, …) detect "player has an ingredient", and whose reward is "recipes": ["minecraft:<recipe>"].

data/minecraft/advancement/recipes/misc/example.json — auto-generated recipe advancement shape

{
  "parent": "minecraft:recipes/root",
  "criteria": {
    "has_ingredient": {
      "trigger": "minecraft:inventory_changed",
      "conditions": { "items": [ { "items": ["minecraft:paper"] } ] }
    },
    "has_the_recipe": {
      "trigger": "minecraft:recipe_unlocked",
      "conditions": { "recipe": "minecraft:example" }
    }
  },
  "requirements": [ ["has_ingredient", "has_the_recipe"] ],
  "rewards": { "recipes": ["minecraft:example"] }
}

Note the no display (recipe advancements are invisible) and the OR requirement — it grants the moment either the ingredient is obtained or the recipe is otherwise unlocked.

To unlock recipes from any advancement, add to its rewards:

"rewards": { "recipes": ["mypack:secret_sword", "mypack:secret_shield"] }

Suppressing the recipe-unlock toast

The "recipe unlocked!" pop-up is controlled on the recipe side, not the advancement side: set "show_notification": false in the recipe JSON.

data/mypack/recipe/secret_sword.json

{
  "type": "minecraft:crafting_shaped",
  "group": "swords",
  "show_notification": false,
  "pattern": ["#", "#", "/"],
  "key": { "#": "minecraft:netherite_ingot", "/": "minecraft:stick" },
  "result": { "id": "minecraft:netherite_sword" }
}
⚠ Version differences
  • since 1.20 (snapshot 23w07a): show_notification exists and defaults to true. Setting it false unlocks the recipe silently — the standard way to add recipes to the book without a toast.
  • the group field merges related recipes in the book display.
💡 Best practice
  • To grant a recipe immediately at world join with no toast, pair "show_notification": false on the recipe with a hidden advancement that has an inventory_changed/tick criterion and rewards.recipes.
  • Give recipes with related outputs the same group to collapse them in the recipe book.
  • Recipe advancements are the one legitimate large-volume use of rewards.recipes; don't hand-roll discovery logic with functions unless you need conditional gating.

Tabs, roots & backgrounds

Any advancement without a parent and with a valid display becomes a tab in the Advancements GUI. Child advancements (those with parent) render inside their root's tab. The game auto-arranges children into columns, drawing connector arrows to the nearest visible ancestor. A custom tree therefore needs exactly one root per tab.

data/mypack/advancement/root.json — the tab

{
  "display": {
    "icon": { "id": "minecraft:nether_star" },
    "title": "My Pack",
    "description": "Custom challenges",
    "background": "minecraft:textures/gui/advancements/backgrounds/adventure.png",
    "show_toast": false,
    "announce_to_chat": false
  },
  "criteria": { "auto": { "trigger": "minecraft:tick" } }
}

data/mypack/advancement/step_one.json — a child

{
  "parent": "mypack:root",
  "display": {
    "icon": { "id": "minecraft:iron_pickaxe" },
    "title": "Getting Started",
    "description": "Mine some iron",
    "frame": "task"
  },
  "criteria": {
    "iron": {
      "trigger": "minecraft:inventory_changed",
      "conditions": { "items": [ { "items": ["minecraft:iron_ingot"] } ] }
    }
  }
}

Background textures

background is a texture resource path (relative to assets, including the .png). Vanilla tab backgrounds live at minecraft:textures/gui/advancements/backgrounds/:

ValueLook
minecraft:textures/gui/advancements/backgrounds/stone.pngStone
minecraft:textures/gui/advancements/backgrounds/gravel.pngGravel
.../backgrounds/dirt.pngDirt
.../backgrounds/end.pngEnd stone
.../backgrounds/nether.pngNetherrack
.../backgrounds/adventure.pngStone bricks
.../backgrounds/husbandry.pngHay/farmland

To use a custom background, ship it in a resource pack at assets/mypack/textures/gui/advancements/backgrounds/mytab.png and reference "background": "mypack:textures/gui/advancements/backgrounds/mytab.png". The texture tiles across the tab; use a seamless 16×16 (or larger) tileable image.

📌 Note

background is honored on root advancements only; setting it on a child is ignored. The path format (namespaced, full textures/...png) has been stable across 1.16 → 1.21 — only the folder rename to singular advancement/ affects path layout.

⚠ Version differences
  • since 1.21 (pack_format 48, snapshot 24w21a): datapack directories were renamed to singularadvancements→advancement, recipes→recipe, loot_tables→loot_table, predicates→predicate, functions→function, item_modifiers→item_modifier, structures→structure, tags/functions→tags/function.
  • before 1.21 (1.20.6 and earlier): use the plural advancements/. A pack targeting both must ship overlays or duplicate trees per pack_format.
💡 Best practice
  • One root per logical tab; keep tab count small — many roots make a cluttered tab bar.
  • For pure-logic packs, never give detectors a display — keep the GUI clean and reserve visible advancements for actual player-facing goals.
  • Titles/descriptions are full text components — use translate keys for localization.
  • Test the tree with /advancement grant @s everything and /advancement revoke @s everything during development.

Sources