# How to use a single process to implement multiple headless clients for stress-testing a DS server

**URL:** <https://forums.unrealengine.com/t/how-to-use-a-single-process-to-implement-multiple-headless-clients-for-stress-testing-a-ds-server/2843374>\
**Category:** Programming & Scripting\
**Tags:** dedicated-server, testing, automated-testing, unreal-engine, Performance\
**Created:** [October 21, 2026, 4:50pm UTC](https://forums.unrealengine.com/t/how-to-use-a-single-process-to-implement-multiple-headless-clients-for-stress-testing-a-ds-server/2843374 "2026-10-21T16:50:14Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![Real.S](https://d3kjluh73b9h9o.cloudfront.net/original/4X/2/8/5/28502927f1d97ba1051b3b47ccfe17233bf41ef0.png) [@Real.S](https://forums.unrealengine.com/u/Real.S)\
**Post date:** [October 21, 2026, 4:50pm UTC](https://forums.unrealengine.com/t/how-to-use-a-single-process-to-implement-multiple-headless-clients-for-stress-testing-a-ds-server/2843374/1 "2026-10-21T16:50:15Z")

</div>

_Hey everyone,_

If you have ever tried to load-test an Unreal dedicated server at realistic player counts, you probably hit the same wall: launching one real client process per simulated player quickly turns into a hardware provisioning problem. External protocol bots avoid that, but then you are no longer measuring your actual game’s handshake, replication, and RPC paths.

I built a plugin called **RealNetRobot** to take a different approach: it drives **N simulated players from inside a single headless client process**. Each robot connects to a dedicated server named on the command line, goes through the real login flow, and behaves like a real player connection.

The important part is that robots are **not** server-side AI bots. Every robot owns its own `UWorld`, `UGameInstance`, `ULocalPlayer`, and `UNetDriver`, and goes through the same handshake, replication, and RPC paths a real client does. That is exactly where the server cost you are trying to measure lives.

What this buys you:

- **N headless clients per process** , each with a real connection to the DS
- **Per-robot world isolation** — robots do not share state
- **Much lower memory cost** — assets load once per process instead of once per client, so a fleet costs roughly _one client + N × (world + actors)_ instead of _N × one client_
- **Staggered joins** , so the fleet ramps instead of bursting
- **Command-line, console, Blueprint/C++ control** , with the command path working in Shipping
- **Inert on install** — nothing happens until you ask for robots
- Ships with a demo map and a task-oriented user guide

A few honest limits, so nobody buys the wrong tool:

1. **You drive the robots yourself.** There is no behaviour framework and no base class to inherit. The plugin exposes `IsRobotWorld` and `GetRobotIndex`, and you hang your own driver off them. An undriven fleet measures a floor, not a load.
2. **World Partition maps with runtime cells** need the optional engine class installed and must run from a packaged build.
3. **Identity travels in the connect URL, not through `UniqueNetId`.** Your login path has to read identity from the URL, or robots past the first will not log in distinctly.
4. **No metrics export** — results come out as log lines plus a fleet summary call.

If you are testing DS performance and want to push player counts without turning the test into a machine-count problem, you can find the plugin here:

> **[RealNetRobot](https://www.fab.com/listings/e32b71c2-b1aa-44cc-934a-66db0771dc09)**
>
> Load-testing a dedicated server at realistic player counts is hard, and the bottleneck is almost always the clients rather than the server. A UE dedicated server is not a conventional game server. The engine's networking is a world of its own —...

Happy to answer questions about the single-process approach or the trade-offs versus external protocol bots.
