Overview
The item_shop_device is a Creative device that presents players with a purchasable item interface — think an in-game store kiosk where players can spend Gold Bars or other currency on weapons, consumables, or upgrades. You configure the items, prices, and appearance entirely in the UEFN editor; Verse gives you runtime control over whether the shop is open (Enable) or closed (Disable).
When should you reach for it?
- You want the shop to open only after a wave clears or a boss dies.
- You want to close the shop during a PvP combat phase and reopen it in a safe zone.
- You want different players or teams to have shop access at different times.
- You want to toggle the shop on a timer (e.g., a 30-second shopping window between rounds).
Because the device has no events of its own, you pair it with other devices — trigger_device, class_selector_device, a timer, or your own game-state logic — to decide when to call Enable or Disable.
API Reference
item_shop_device
Allows the item shop to be opened when activated
Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse).
item_shop_device<public> := class<concrete><final>(creative_device_base):
Methods (call these to make the device act):
| Method | Signature | Description |
|---|---|---|
Enable |
Enable<public>():void |
Enables this device. |
Disable |
Disable<public>():void |
Disables this device. |
Walkthrough
Scenario: A survival game with shopping windows. At the start of each round a trigger fires, opening the shop for 20 seconds. When the timer expires the shop closes automatically. A second trigger (a "skip shopping" button) lets players close the shop early.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
# Place this Verse device in your level, then wire up the three @editable fields
# in the UEFN Details panel.
item_shop_controller := class(creative_device):
# The item_shop_device placed on your island.
@editable
Shop : item_shop_device = item_shop_device{}
# A trigger_device players step on (or you fire via another device)
# to open the shopping window at the start of each round.
@editable
RoundStartTrigger : trigger_device = trigger_device{}
# A second trigger players can activate to close the shop early
# (e.g., an "I'm ready, skip shopping" button).
@editable
SkipShoppingTrigger : trigger_device = trigger_device{}
# How many seconds the shopping window stays open.
ShoppingWindowSeconds : float = 20.0
# Called once when the game starts. Wire up events here.
OnBegin<override>()<suspends> : void =
# Shop starts closed — players cannot access it yet.
Shop.Disable()
# Subscribe to both triggers.
RoundStartTrigger.TriggeredEvent.Subscribe(OnRoundStart)
SkipShoppingTrigger.TriggeredEvent.Subscribe(OnSkipShopping)
# Fires when the round-start trigger activates.
# Agent is ?agent because TriggeredEvent sends an optional agent.
OnRoundStart(Agent : ?agent) : void =
# Open the shop for all players.
Shop.Enable()
# Start the countdown on a background task so we don't block.
spawn { CloseShopAfterDelay() }
# Fires when a player hits the "skip shopping" trigger.
OnSkipShopping(Agent : ?agent) : void =
Shop.Disable()
# Background coroutine: wait ShoppingWindowSeconds, then close the shop.
CloseShopAfterDelay()<suspends> : void =
Sleep(ShoppingWindowSeconds)
Shop.Disable()
Line-by-line breakdown:
| Lines | What's happening |
|---|---|
@editable Shop |
Declares the item_shop_device reference. You drag your placed device into this slot in UEFN. |
@editable RoundStartTrigger / SkipShoppingTrigger |
Two trigger_device references for the two game events. |
Shop.Disable() in OnBegin |
Ensures the shop is closed when the match starts — players can't buy anything yet. |
RoundStartTrigger.TriggeredEvent.Subscribe(OnRoundStart) |
Registers OnRoundStart as the handler. Every time the trigger fires, OnRoundStart runs. |
Shop.Enable() |
Opens the shop so players can interact with it. |
spawn { CloseShopAfterDelay() } |
Launches the countdown as a concurrent task so OnRoundStart returns immediately. |
Sleep(ShoppingWindowSeconds) |
Suspends the background task for 20 seconds. |
Shop.Disable() (second call) |
Closes the shop when the window expires — or immediately if the skip trigger fires. |
Common patterns
Pattern 1 — Toggle the shop on a class-selector event
Open the shop only for players who chose the "Merchant" class; close it for everyone else when they switch away.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
merchant_shop_gating := class(creative_device):
@editable
Shop : item_shop_device = item_shop_device{}
# A class_selector_device configured with the Merchant class.
@editable
MerchantSelector : class_selector_device = class_selector_device{}
OnBegin<override>()<suspends> : void =
# Shop closed by default.
Shop.Disable()
# Open when a player selects the Merchant class.
MerchantSelector.ClassSelectedEvent.Subscribe(OnMerchantSelected)
OnMerchantSelected(Agent : agent) : void =
# Any player picking the Merchant class opens the shop.
Shop.Enable()
Pattern 2 — Disable the shop permanently after a one-time purchase window
Some game modes give players a single pre-game buy phase. After it ends, the shop never reopens.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
buy_phase_controller := class(creative_device):
@editable
Shop : item_shop_device = item_shop_device{}
# A timer_device (or any signal) that marks the end of the buy phase.
@editable
BuyPhaseEndTrigger : trigger_device = trigger_device{}
# Duration of the buy phase in seconds.
BuyPhaseDuration : float = 30.0
OnBegin<override>()<suspends> : void =
# Open immediately when the game starts.
Shop.Enable()
# Also allow an explicit early-end signal.
BuyPhaseEndTrigger.TriggeredEvent.Subscribe(OnBuyPhaseEnd)
# Auto-close after the buy phase duration.
Sleep(BuyPhaseDuration)
# Permanently close — no re-enable after this point.
Shop.Disable()
OnBuyPhaseEnd(Agent : ?agent) : void =
Shop.Disable()
Pattern 3 — Alternating shops for two teams
Team A's shop opens while Team B's is closed, then they swap every 15 seconds.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
alternating_shops := class(creative_device):
@editable
TeamAShop : item_shop_device = item_shop_device{}
@editable
TeamBShop : item_shop_device = item_shop_device{}
# How long each team gets exclusive shop access.
SwapIntervalSeconds : float = 15.0
OnBegin<override>()<suspends> : void =
# Start with Team A's shop open.
TeamAShop.Enable()
TeamBShop.Disable()
# Loop forever, alternating access.
loop:
Sleep(SwapIntervalSeconds)
TeamAShop.Disable()
TeamBShop.Enable()
Sleep(SwapIntervalSeconds)
TeamBShop.Disable()
TeamAShop.Enable()
Gotchas
1. You MUST declare item_shop_device as an @editable field.
You cannot write item_shop_device{}.Enable() inline — the device must be a placed instance in your level, referenced through an @editable field. A bare item_shop_device{} creates a default struct, not your placed device, and calling methods on it does nothing visible in-game.
2. item_shop_device has NO events.
Unlike vending_machine_device (which has ItemSpawnedEvent), item_shop_device exposes only Enable and Disable. If you need to react to a purchase, you must use a separate device (e.g., an item_granter_device or a trigger_device the shop activates via editor wiring) to detect the transaction.
3. Disable does not refund in-progress transactions.
If a player has the shop UI open when you call Disable, behavior depends on the engine version and shop configuration. Close the shop between natural interaction windows (e.g., at round end) rather than mid-purchase.
4. TriggeredEvent sends ?agent, not agent.
When subscribing to trigger_device.TriggeredEvent, your handler signature must be (Agent : ?agent). If you need the actual agent, unwrap it: if (A := Agent?) { ... }. Forgetting the ? causes a compile error.
5. Sleep requires a <suspends> context.
The CloseShopAfterDelay coroutine in the walkthrough must be marked <suspends> and launched with spawn { }. Calling Sleep directly inside a non-suspending handler (like an event callback) will not compile.
6. There is no IsEnabled query.
The API has no way to ask whether the shop is currently enabled. Track state yourself with a var IsShopOpen : logic = false field if your logic needs to branch on the current state.