How to automate playtesting in Godot: simulated input, bots, MCP servers and AI agents
To automate playtesting in Godot, something has to press the buttons for you and something has to decide whether what happened was right. You can script both yourself, with input tests in GUT or GdUnit4 or a bot autoload
To automate playtesting in Godot, something has to press the buttons for you and something has to decide whether what happened was right. You can script both yourself, with input tests in GUT or GdUnit4 or a bot autoload you run from the command line, including headless in CI. Or you can hand the pressing to an AI: an MCP server that lets Claude Code or Cursor run the game, or an agent inside the editor such as Ziva.
Disclosure: Ziva.sh publishes this page and makes Ziva. Facts about other tools come from their own pages, as of 5 November 2026. We ran every Godot command and test on this page on 5 November 2026 with Godot 4.7.2 on Linux, on the public Star Catcher sample, a small game with one deliberate bug: collecting a star should add a point, but the score label is never found.
The ways to automate playtesting in Godot
| Way | Who decides what to press | Headless or CI | Price |
|---|---|---|---|
| GUT input tests | GUT: your test script, through GutInputSender | GUT: yes; exited 1 on a failing test in our run | GUT: free, MIT |
| GdUnit4 scene runner | GdUnit4: your test script, through the scene runner | GdUnit4: yes; exited 100 on a failing test in our run | GdUnit4: free, MIT |
| A bot autoload run from the command line | Bot: your script | Bot: yes with godot --headless; screenshots and video need a display |
Godot: free, MIT |
| Godot MCP servers with Claude Code or Cursor | MCP servers: the AI client's model | MCP servers: drive a running editor or game; Beckett Full adds a headless CI runner | MCP servers: free to $19 one-time, plus the client |
| Ziva run_scene | Ziva run_scene: Ziva's agent, or Claude Code over Ziva's MCP | Ziva run_scene: no; the Godot editor must be open | Ziva run_scene: every plan, including the free Hobby plan |
| Ziva Full Game Playtest Agent | Ziva Full Game Playtest Agent: an AI playing toward your goal | Ziva Full Game Playtest Agent: no; the Godot editor must be open | Ziva Full Game Playtest Agent: Pro ($50/month) and Ultra |
| modl.ai, nunu.ai | modl.ai, nunu.ai: their AI agents, from the screen | modl.ai: "upload your latest build"; nunu.ai: "PC and mobile (iOS and Android)" | modl.ai, nunu.ai: no price on their home pages |
Scripted tests and bots are free, repeatable and fast, but they only check what you thought to script. Agents find paths you did not script, but each run costs model time and an agent's choices vary between runs. Most games want both: scripted checks on every commit, an agent pass before a release.
Simulate keyboard and mouse input in Godot
Godot itself has two ways to fake input from code. Both moved the Star Catcher player 360 px to the right in 1.2 seconds of game time in our run.
# A raw key, as if the Right arrow were pressed. _input() sees it, and it drives the ui_right action.
var key := InputEventKey.new()
key.keycode = KEY_RIGHT
key.pressed = true
Input.parse_input_event(key)
# A named action from the Input Map. No InputEvent is created, so _input() never sees it.
Input.action_press("ui_right")
Input.action_release("ui_right")
Godot's Input docs say parse_input_event "Feeds an InputEvent to the game" and "Also generates Node._input() calls", and that action_press "will not cause any Node._input() calls". Neither touches the operating system: sending an InputEventKey "won't toggle between active windows". To release a parsed key, send a copy with pressed = false. An InputEventAction sent through parse_input_event works the same way for actions.
GUT: GutInputSender
GUT's GutInputSender "can be used to send InputEvent* events to various objects. It also allows you to script out a series of inputs and play them back in real time." With Input as the receiver, GUT's Mocking Input page says Godot treats the events "exactly the same as if the events were triggered from hardware". This test passed on the fixed game and failed on the sample's main branch:
# res://test/test_star.gd
extends GutTest
var _sender := GutInputSender.new(Input)
func after_each() -> void:
_sender.release_all()
_sender.clear()
func test_walking_right_collects_a_star() -> void:
var main: Node = add_child_autofree(load("res://main.tscn").instantiate())
_sender.action_down("ui_right").hold_for(1.2).wait(0.3)
await _sender.idle
assert_eq(main.get_node("HUD/ScoreLabel").text, "Score: 1")
After importing the project once with godot --headless --path . --import, GUT 9.6.1 ran it headless with godot --headless --path . -s addons/gut/gut_cmdln.gd -gdir=res://test -gexit. On the buggy branch GUT reported ["Score: 0"] expected to equal ["Score: 1"], listed the Invalid assignment of property or key 'text' ... on a base object of type 'null instance' error under "Unexpected Errors", and exited with code 1. GutInputSender also has key_down, key_up, mouse_left_click_at and other mouse methods.
GdUnit4: the scene runner
GdUnit4's scene runner has functions that "mimic user key inputs as actions for testing purposes", plus key and mouse functions such as simulate_key_pressed(KEY_ENTER) and simulate_mouse_button_pressed(MOUSE_BUTTON_LEFT). The same check in GdUnit4 7.0.0:
# res://test/test_star.gd
extends GdUnitTestSuite
func test_walking_right_collects_a_star() -> void:
var runner := scene_runner("res://main.tscn")
runner.simulate_action_press("ui_right")
await runner.simulate_frames(72)
runner.simulate_action_release("ui_right")
await runner.await_input_processed()
assert_str(runner.find_child("ScoreLabel").text).is_equal("Score: 1")
GdUnit4 ran it with ./addons/gdUnit4/runtest.sh --godot_binary /usr/bin/godot --headless -a res://test, printed "Running in headless mode, Godot does not render anything.", reported a Godot runtime error and "Expecting: 'Score: 1' but was 'Score: 0'" on the buggy branch, and exited with code 100. On the fixed game it exited 0.
Make the game play itself: a bot and the command line
For a run through the real game rather than a test scene, add an autoload that plays only when you ask it to. This one walks right into the first star and checks the score:
# res://bot.gd, registered under [autoload] in project.godot as Bot="*res://bot.gd"
extends Node
# Plays only when the game is started with "-- --bot", then quits with exit code 0 (pass) or 1 (fail).
func _ready() -> void:
if not OS.get_cmdline_user_args().has("--bot"):
return
await get_tree().create_timer(0.3).timeout
Input.action_press("ui_right")
await get_tree().create_timer(1.2).timeout
Input.action_release("ui_right")
await get_tree().create_timer(0.5).timeout
var label: Label = get_tree().current_scene.get_node("HUD/ScoreLabel")
print("BOT: score label says '%s'" % label.text)
get_tree().quit(0 if label.text == "Score: 1" else 1)
Run it from the project folder:
godot --headless --path . --fixed-fps 60 --quit-after 600 -- --bot
On the sample's buggy main branch, Godot 4.7.2 printed:
Godot Engine v4.7.2.stable.arch_linux.ed1daf0bf (2026-08-17 01:18:38 UTC) - https://godotengine.org
ERROR: Node not found: "%ScoreLabel" (relative to "/root/Main").
at: get_node (scene/main/node.cpp:1975)
GDScript backtrace (most recent call first):
[0] @implicit_ready (res://main.gd:5)
SCRIPT ERROR: Invalid assignment of property or key 'text' with value of type 'String' on a base object of type 'null instance'.
at: _on_star_collected (res://main.gd:15)
GDScript backtrace (most recent call first):
[0] _on_star_collected (res://main.gd:15)
[1] _on_body_entered (res://star.gd:8)
BOT: score label says 'Score: 0'
The exit code was 1. After changing %ScoreLabel to $HUD/ScoreLabel in main.gd, the same command printed BOT: score label says 'Score: 1' and exited 0. What the flags did:
-
--headlessruns with no window and no audio, so it works on a CI machine. Nothing is rendered, so there are no screenshots. -
--fixed-fps 60gives every frame exactly 1/60 s of game time;godot --helpsays it "disables real-time synchronization". The whole run, startup included, took 0.78 s of wall time for 2 seconds of game time, and the player moved the same 360 px in every run we measured. -
--quit-after 600stops the game after 600 iterations (frames) if the bot never quits, so a stuck run cannot hang CI. - Arguments after
--reach the game throughOS.get_cmdline_user_args(), so normal launches ignore the bot.
The bot must decide pass or fail itself. Without the bot, godot --headless --path . --fixed-fps 60 --quit-after 600 printed the same Node not found error and still exited 0.
To watch what the bot did, record it with --write-movie run.avi. That needs rendering: with --headless, Godot 4.7.2 crashed (signal 11) in our test. On a virtual X display (Xvfb, no GPU), the same run without --headless wrote a 122-frame AVI at 60 FPS and printed Done recording movie at path. For longer games, chain several inputs, check signals or node state at each step, and give each level its own bot path.
Let Claude Code or Cursor run the game: Godot MCP servers
An MCP server gives an AI client such as Claude Code or Cursor tools to control Godot. The client's model decides what to press. These servers list tools for running the game, sending input and seeing the result:
| MCP server | Run the game | Send input | See the running game | Licence and price |
|---|---|---|---|---|
| Ziva's MCP server | Ziva: run_scene runs a scene from the open editor |
Ziva: actions, keys, mouse clicks, clicks on a Control by path or text, mouse motion | Ziva: final screenshot plus console output and runtime errors; get_screenshot (editor) |
Ziva: run_scene on every plan, including the free Hobby plan |
| Godot MCP Pro | Godot MCP Pro: "Launch the game" | Godot MCP Pro: simulate_key, simulate_mouse_click, simulate_action, simulate_sequence
|
Godot MCP Pro: get_game_screenshot
|
Godot MCP Pro: "$15 one-time purchase" |
| GDAI MCP | GDAI MCP: runs the game and checks it with screenshots | GDAI MCP: "press keyboard keys and input actions" | GDAI MCP: screenshots of "the editor and running game" | GDAI MCP: "$19 one-time payment", binary-only licence |
| Beckett | Beckett Lite and Full: "run your game" | Beckett Full: "simulate input, click 2D and 3D UI, scroll, drag, record and replay" | Beckett Lite and Full: "screenshot the running game" | Beckett: Lite free (MIT), Full "$15, one-time" |
| satelliteoflove/godot-mcp | satelliteoflove/godot-mcp: run, stop, restart; freeze and step | satelliteoflove/godot-mcp: "actions, joypad, raw keys, mouse-look, text" | satelliteoflove/godot-mcp: game screenshots and live state as JSON | satelliteoflove/godot-mcp: free, MIT; Godot 4.5+ |
| Godot AI (hi-godot/godot-ai) | Godot AI: project_run
|
Godot AI: input_key, input_mouse, input_gamepad, input_action, input_sequence
|
Godot AI: editor_screenshot with the running game's framebuffer |
Godot AI: free, MIT; Godot 4.7+ |
| Open Godot MCP | Open Godot MCP: godot_game play, stop, freeze |
Open Godot MCP: godot_input for keyboard, mouse, gamepad and text |
Open Godot MCP: godot_screenshot
|
Open Godot MCP: free, MIT; Godot 4.5+ |
| Coding-Solo/godot-mcp | Coding-Solo/godot-mcp: "run projects, capture debug output" | Coding-Solo/godot-mcp: no input tool listed | Coding-Solo/godot-mcp: no game screenshot listed | Coding-Solo/godot-mcp: free, MIT |
| Summer Engine MCP | Summer Engine: "play" | Summer Engine: "input" | Summer Engine: "screenshots" | Summer Engine: MIT CLI and MCP tools that "drive Summer's desktop editor, not stock Godot" |
Two vendors also describe verification beyond pressing keys. Godot MCP Pro's page says it can "assert game state, and run stress tests with random input". Beckett's author wrote on 10 July 2026 about Beckett Full: "A headless runner plays every saved suite in your own CI and exits non-zero on failure."
Let Ziva run the game and read the errors
Ziva is an AI agent that works inside the Godot editor. Since version 3.0.0 (June 2026), Ziva's run_scene tool runs a scene live from the open editor, in the editor's embedded game view, and returns a screenshot of the running game plus the console output and runtime errors from that run. Ziva's run_scene is on every plan, including the free Hobby plan. Ziva's agent calls it on its own when you ask for a concrete check, for example: "Run my level, jump onto the first platform, and check that the player lands."
Ziva's run_scene takes a timed list of inputs, each with a start time and a hold time:
-
action: a named input action, pressed withInput.action_press, so it works without a key mapping. -
key: a rawInputEventKey, which_inputsees. -
mouse: a left or right click at a pixel position. -
target: a click on a Control found by node path or visible text. -
motion: relative mouse movement, for a first-person camera with a captured mouse.
Ziva sends raw keys and mouse clicks as InputEvents through Input.parse_input_event, the channel a keyboard's events take inside Godot, and presses named actions with Input.action_press. Ziva presses no physical key, and Ziva's run_scene has no gamepad or touch input. Each Ziva run_scene result includes a delivery report with the frame and millisecond every press and release landed on, and speed: true adds average FPS, 1% low and worst frame time.
What Ziva's run_scene returned on Star Catcher
We called Ziva's run_scene directly through Ziva's local MCP endpoint, without a model, on the Star Catcher sample in Godot 4.7.2:
- A plain 2.5-second run returned
Node not found: "%ScoreLabel" (relative to "/root/Main")with sourceres://main.gd:5. - Holding
ui_rightfrom 300 ms for 1,200 ms moved the player 360 px and collected the first star. Ziva's result addedInvalid assignment of property or key 'text' with value of type 'String' on a base object of type 'null instance'atres://main.gd:15, and the screenshot showed the score still at 0. - For a UI check, we added a Restart button inside a CanvasLayer to our test copy (it is not in the public sample). Ziva's
run_sceneclicked it by its visible text "Restart", by its node pathRestartLayer/RestartButtonand by a mouse click at its pixel position, and the button'spressedhandler printed each time. - A target that matched nothing, "Play Again", came back in Ziva's delivery report as
delivered: falsewith "no Control matched target 'Play Again'". The run itself still reported success, so read the delivery report.
In a separate unedited recording on the same sample, one prompt asked Ziva to add stars, play the game and check that the score goes up. Ziva ran the game while holding ui_right, read the two errors, changed the lookup in main.gd to $HUD/ScoreLabel, ran the game again and saw Score: 1. The sample's README has the exact prompt and every change.
Use Ziva's run_scene from Claude Code or Cursor
Ziva runs a local MCP server, so Claude Code, Codex, Cursor and other MCP apps can call Ziva's run_scene and get_screenshot tools. Ziva's MCP server is local only, with no hosted URL. To connect Claude Code (full steps):
- Open your project in Godot with Ziva installed and signed in.
- In Ziva, open Settings → Models & Providers → Ziva as an MCP server and check that it shows Running.
- Under AI application, choose Claude Code and click Install for Claude Code.
- Start a new Claude Code session from your Godot project folder and ask, for example: "Use ziva-godot's run_scene tool to run res://main.tscn for 2500 ms, holding ui_right from 300 ms for 1200 ms, and tell me which errors it printed."
Claude Code then gets the same screenshot, console output and errors as Ziva's own agent. Ziva's run_scene only appears when playtesting is enabled in Ziva's settings, and Ziva's Full Game Playtest Agent is not available over MCP.
Ziva Full Game Playtest Agent
Ziva's Full Game Playtest Agent, added in 3.1.4 (August 2026), plays a whole game toward a goal you set, such as "chop down a tree and build a crafting bench". Ziva's Full Game Playtest Agent is on Ziva's Pro ($50/month) and Ultra plans. Ask Ziva to "use the Full Game Playtest Agent". Ziva's Full Game Playtest Agent starts the game, keeps it paused while the model thinks, sends keyboard and mouse input one action at a time, checks the result with screenshots and values it reads from the running scene, and returns pass, fail or blocked with evidence. With Record playtests on in Settings → Agent, Ziva saves a video of the run with its goal and inputs drawn in. Ziva's Full Game Playtest Agent cannot edit your project: it reports, and you or Ziva's normal chat fix the bug. See Is there an AI agent that can playtest a Godot game? and the Full Game Tester page.
Checklist: find bugs in your Godot game before release
- Make errors fail the run. Godot exited 0 after a
SCRIPT ERRORin our test, so have the bot callget_tree().quit(1), or fail the CI step when the log containsSCRIPT ERROR. - Script the main path: start, first level, win, lose, restart. Run it as a bot or as GUT or GdUnit4 tests headless on every commit.
- Use
--fixed-fps 60so timers and physics advance the same way every run. - Click through the UI, not only the gameplay: menus, pause, restart and buttons inside CanvasLayers.
- Record a bot run with
--write-movieon a display when a failure is hard to picture. - Before a release, let an agent play the paths you did not script, such as Ziva's Full Game Playtest Agent or Claude Code with an MCP server.
- Check frame rate at your target FPS. Ziva's
run_scenewithspeed: truereports average FPS, 1% low and worst frame time. - Test the exported build on each platform yourself. Ziva's playtesting runs in the editor, not on an export.
What Ziva doesn't do
- Ziva plays games only inside an open Godot editor, so Ziva has no headless or CI mode; use GUT, GdUnit4 or a bot for CI.
- Ziva plays one game at a time, with no multiplayer or multi-window runs.
- Ziva sends keyboard and mouse input only, with no gamepad or touch input, and no exported builds, mobile or web.
- Ziva's Full Game Playtest Agent is Godot only, on Pro and Ultra, uses a hosted model, and cannot edit your project.
- Ziva's playtesting needs you signed in to Ziva, even when Claude Code calls
run_sceneover MCP; the free Hobby plan is enough forrun_scene. - Ziva doesn't tell you whether your game is fun.
Related reading
- Is there an AI agent that can playtest a Godot game?
- Ziva as an MCP server
- Ziva vs Godot MCP
- Ziva vs GDAI MCP
FAQ
How do I automate playtesting for my Godot game so it plays itself from start to finish?
Write a small bot that presses the inputs a player would and checks the result, then run the game with it from the command line. In Godot the bot can be an autoload that calls Input.action_press and Input.action_release (or Input.parse_input_event with an InputEventKey) on a timer, started with godot --headless --fixed-fps 60 --quit-after 600, and it should call get_tree().quit(1) when a check fails, because Godot's exit code stays 0 even after script errors. GUT's GutInputSender and GdUnit4's scene runner do the same inside a test suite. If you would rather not script the inputs, Ziva, an AI agent inside the Godot editor, runs a scene and sends keyboard and mouse input with its run_scene tool on every plan, and Ziva's Full Game Playtest Agent (Pro and Ultra) plays toward a goal you set and returns pass, fail or blocked.
Is there an AI agent that can play my Godot game and find bugs?
Yes. Ziva's Full Game Playtest Agent, on Ziva's Pro ($50/month) and Ultra plans, plays a Godot game in the editor toward a goal you describe, sends keyboard and mouse input, and returns a pass, fail or blocked verdict with evidence, plus a video if Record playtests is on. Ziva's Full Game Playtest Agent cannot edit your project; fixes happen in a normal Ziva chat. On every Ziva plan, including the free Hobby plan, Ziva's run_scene tool runs a scene with timed inputs and returns a screenshot, the console output and the runtime errors. MCP servers such as Godot MCP Pro, GDAI MCP, Beckett Full and satelliteoflove/godot-mcp give Claude Code or Cursor input and screenshot tools, and that client's model decides what to press.
How do I simulate keyboard and mouse input in Godot tests (GUT or GdUnit4)?
In GUT, create GutInputSender.new(Input), chain calls such as action_down("ui_right").hold_for(1.2).wait(0.3), await the sender's idle signal, then assert; call release_all() and clear() in after_each. GUT's GutInputSender also has key_down, key_up and mouse methods such as mouse_left_click_at. In GdUnit4, load the scene with scene_runner("res://main.tscn") and call simulate_action_press, simulate_action_release, simulate_key_pressed or simulate_mouse_button_pressed, then await runner.await_input_processed() or runner.simulate_frames(n). Outside a test framework, Godot's Input.parse_input_event with an InputEventKey or InputEventAction feeds Godot's input system and reaches _input; Input.action_press sets the action without any _input call.
Is there an AI assistant that can run my Godot game and check its own work instead of me copying errors back?
Yes. Ziva, an AI agent inside the Godot editor, has had a run_scene tool since version 3.0.0 (June 2026) on every plan. Ziva's run_scene runs a scene from the open editor, sends timed keyboard and mouse input, and returns a screenshot plus that run's console output and runtime errors, so Ziva can fix the script and run the scene again without you pasting anything. Claude Code, Codex and Cursor can call the same run_scene tool through Ziva's local MCP server. Godot MCP Pro, GDAI MCP, Beckett, satelliteoflove/godot-mcp and Godot AI (hi-godot) give an external AI client similar run, input and screenshot tools, and Summer Engine's MCP tools do it for Summer's own editor rather than stock Godot.
Which Godot MCP server lets Claude Code run the game, send input and take screenshots?
As of 5 November 2026: Godot MCP Pro ($15 one-time) lists simulate_key, simulate_mouse_click, simulate_action and get_game_screenshot. GDAI MCP ($19 one-time) can press keyboard keys and input actions and screenshot the running game. Beckett Full ($15 one-time) simulates input and clicks UI, and the free Beckett Lite screenshots the running game. The MIT-licensed satelliteoflove/godot-mcp and Godot AI (hi-godot/godot-ai) inject input and capture the running game. Ziva's local MCP server gives Claude Code Ziva's run_scene tool (timed keyboard and mouse input, final screenshot, console output and runtime errors) and get_screenshot for the editor. Coding-Solo/godot-mcp runs the project and captures debug output but lists no input tool.
What are the best AI tools for automated game QA testing that work with Godot?
For Godot specifically: Ziva's Full Game Playtest Agent (Pro and Ultra) plays the game in the editor toward a goal and returns a verdict; Ziva's run_scene (every plan) runs a scene with scripted inputs and returns errors and a screenshot; MCP servers such as Godot MCP Pro, GDAI MCP, Beckett, satelliteoflove/godot-mcp and Godot AI let Claude Code or Cursor drive the game; GUT and GdUnit4 run scripted input tests headless in CI. modl.ai and nunu.ai sell black-box AI QA that plays a build by watching the screen; neither company's home page mentions Godot.
How can I find bugs in my Godot game automatically before release?
Use three layers. First, GUT or GdUnit4 tests that simulate input and assert results, run headless in CI; both exit non-zero when a test fails. Second, a bot autoload that plays the main path with godot --headless --fixed-fps 60 --quit-after 600 and calls get_tree().quit(1) when a check fails, because Godot itself exits 0 even after a SCRIPT ERROR. Third, an exploratory pass by an agent that decides what to press, such as Ziva's Full Game Playtest Agent (Pro and Ultra) or Claude Code with a Godot MCP server. Ziva plays the game inside the Godot editor, not an exported build, so test exports on each target platform separately.
Is there a Godot editor plugin with an AI agent that can playtest my game inside the editor?
Ziva is a Godot editor plugin (Godot 4.2 or later) with an AI agent in a dock. On every plan, Ziva's run_scene tool runs a scene from the editor, sends keyboard and mouse input through Godot's own input system, and returns a screenshot, console output and runtime errors. On Pro and Ultra, Ziva's Full Game Playtest Agent plays the game one action at a time toward a goal, with the game paused while it thinks, and returns pass, fail or blocked with evidence. The Godot editor has to stay open, Ziva plays one game at a time, and Ziva has no gamepad or touch input. Beckett and Godot MCP Pro are editor plugins too, but their agent is an external MCP client such as Claude Code.
The full guide is at https://ziva.sh/blogs/godot-automated-playtesting.
How do you playtest your Godot game today? Drop your setup in the comments.
Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.