Skip to main content
Version: Stable

Hooks

Hooks run ZapScript at specific points in Core's lifecycle. Use them for local automation, webhooks, save workflows, startup actions, lighting, buttons, or scripts that need context from Core.

Hooks are configured in config.toml. Manual config edits require a Core restart or config reload where supported.

Hook reference

HookConfig locationWhen it runsCan block?Extra context
on_scan[readers.scan]After a token is scanned, before the token or mapping script runsYes, blocks token processingscanned
on_remove[readers.scan]After a token is removed in hold modeYes, blocks remove processing and keeps media runningnone
before_exit[[systems.default]]Before hold mode exits media for the matching systemWaits for script; errors are loggednone
before_media_start[launchers]Before a media-launching command runsYes, blocks launchlaunching
on_media_start[launchers]After active media is setNo, errors are loggedactive media
on_boot[service]First Core start after the device bootsNo, errors are loggedhook
on_ready[service]Every time Core starts and is readyNo, errors are loggedhook

Reader hooks

Reader hooks live under [readers.scan].

[readers.scan]
on_scan = "**http.post:https://example.com/scan,text/plain,Token scanned"
on_remove = "**echo:card was removed"

on_scan runs before the scanned token is processed. If the hook fails, the scan is blocked.

on_remove only runs in hold mode. If the hook fails, remove processing is blocked, so media keeps running.

Media launch hooks

Media launch hooks live under [launchers].

[launchers]
before_media_start = "**http.get:https://example.com/before-launch"
on_media_start = "**http.get:https://example.com/media-started"

before_media_start runs before launch commands such as **launch, **launch.random, **launch.title, and MiSTer MGL launches. If it fails, the launch is blocked.

on_media_start runs after Core starts media. It is useful for notifications or follow-up actions. If it fails, the launched media keeps running.

Exit hooks

Use before_exit on a system default when hold mode should run a script before exiting media.

[[systems.default]]
system = "SNES"
before_exit = "**input.keyboard:{f12}||**delay:2000"

This can be useful for opening an emulator menu, saving, or giving the platform time to settle before hold mode exits media.

Service startup hooks

Service hooks live under [service].

[service]
on_boot = "**execute:/media/fat/zaparoo/scripts/on-boot.sh"
on_ready = "**execute:/media/fat/zaparoo/scripts/on-ready.sh"

on_boot runs once after the device boots. If Core restarts without rebooting the device, on_boot is skipped.

on_ready runs every time Core starts and is ready.

Expression environment

Hook scripts can use the normal ZapScript expression environment. Hook-related fields include:

  • hook.name: current hook name, such as on_boot or on_ready.
  • hook.first_boot_start: true when this Core start is the first start for the current OS boot.
  • scanned: available in on_scan.
  • launching: available in before_media_start.

The normal environment also includes media_ready, which is true when active media is considered ready.

Example:

[service]
on_ready = "**echo:Hook [[hook.name]] started, first boot: [[hook.first_boot_start]]"

External scripts

The **execute command receives a ZAPAROO_ENVIRONMENT environment variable containing the expression environment as JSON.

[zapscript]
allow_execute = ["/media/fat/zaparoo/scripts/.*"]

[service]
on_ready = "**execute:/media/fat/zaparoo/scripts/on-ready.sh"

execute still requires a matching allow_execute entry. Input commands still follow the configured [zapscript.input] rules.

Examples

Send a webhook when a token is scanned:

[readers.scan]
on_scan = "**http.post:https://hooks.example.com/zaparoo,text/plain,[[scanned.id]]"

Block launches when an external script returns an error:

[launchers]
before_media_start = "**execute:/media/fat/zaparoo/scripts/check-launch.sh"