Embedding the server
veriCue works by running the veriCue Runtime - the VeriCueServer class from libvericue-server - inside the application under test. Embedding puts it there on your terms: you link the library and start it yourself in main(), on the transport that suits your setup. This page covers wiring it into your build, configuring authentication and licensing, and - importantly - keeping it out of your production binaries.
Do you need to touch the build at all?
On Linux, vericue-inject starts the server inside an unmodified dynamically linked Qt application via LD_PRELOAD, with the same feature set, authentication and licensing as embedding. It is a supported path on the configurations listed there.
Embed instead when you need a platform injection does not cover (Windows, macOS), a statically linked Qt, a hardened process, or a server you can compile out of release builds and start on your own terms.
1. Link the library
With the veriCue SDK installed (see Installation), add to your CMakeLists.txt:
find_package(vericue REQUIRED)
target_link_libraries(my-app PRIVATE vericue::vericue-server)If CMake can't find the package, point it at the install prefix:
cmake -B build -DCMAKE_PREFIX_PATH="/usr/local;/path/to/Qt/6.7/gcc_64"2. Start the Runtime
Create a VeriCueServer after your main window exists and start it. On Linux and macOS, startLocal() is the recommended call for same-host runs:
#include <vericue/server.h>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QMainWindow window;
window.setObjectName("MainWindow");
// ... build your UI ...
vericue::VeriCueServer server(&window); // parented - cleaned up with the window
if (!server.startLocal()) {
qWarning("veriCue server failed to start");
} else {
qInfo() << "VERICUE_ENDPOINT=" << server.localEndpoint();
}
window.show();
return app.exec();
}startLocal() uses the local IPC transport: a user-private endpoint that is not reachable over the network. It is supported on Linux and macOS. On Windows, and whenever the client runs on another host, in another container, or on a device, start the TCP transport instead:
if (!server.start(4242)) { // reachable from other hosts
qWarning("veriCue server failed to start");
}A portable main() can pick per platform, since the rest of the protocol, the authentication and the licensing are identical either way:
#ifdef Q_OS_WIN
server.start(4242); // Windows: TCP is the supported transport
#else
server.startLocal(); // Linux/macOS: local IPC when tests run here
#endifNotes:
startLocal()with no argument picks$XDG_RUNTIME_DIR/vericue/vericue-<pid>.sock; read the resolved path back withserver.localEndpoint()and print it so the harness can discover it (the injector printsVERICUE_ENDPOINT=<path>).start(0)lets the OS pick a free port; read it back withserver.serverPort(). Useful for parallel CI jobs - print it to stdout so the test harness can discover it (the bundled test app printsVERICUE_PORT=<port>).- Both at once is allowed: calling
startLocal()andstart(port)on the same server serves local and remote clients simultaneously. They share the one licensed concurrent-session budget, andstop()shuts both down. - The constructor takes an optional
QObject*parent. Parenting to your main window ties the server's lifetime to the UI. started()/stopped()/errorOccurred(QString)signals are available if you want to log or react to lifecycle events.- Works for QWidget and QML applications alike. Toolkit support is not linked into the Runtime:
vericue-widgetsandvericue-quickare loaded at run time from the directory holding the Runtime library, and only when the matching Qt module is already in your process. Nothing to configure - just deploy them next tolibvericue-server(bin/on Windows). Confirm with theversioncommand, which reports one status line per toolkit.
3. Name your objects
Clients address objects by path, e.g. MainWindow/centralWidget/okButton. Path segments use QObject::objectName(), falling back to ClassName#N for unnamed objects. Unnamed-object paths break when the UI changes, so:
okButton->setObjectName("okButton");Give stable objectNames to every widget you intend to automate. In QML, set the objectName property.
4. Authentication
server.setAuthToken(qEnvironmentVariable("MYAPP_VERICUE_TOKEN"));When a token is set, clients must present it during the handshake; connections with a missing or wrong token are rejected. Read the token from the environment or a config file - don't hardcode secrets.
5. Licensing
Without any license configuration the server runs in 30-day trial mode. For licensed use, pick one:
// Organization license: RSA-signed JSON key file (from your license email / portal)
server.setLicenseFile("/etc/myapp/vericue-license.json");
// Floating: lease a session from your self-hosted LAN license server
server.setLicenseServer("licenses.internal.example.com", 5252);Licensing is fully offline - the server never phones home. Session accounting differs by mode: with an organization key file (or trial), each connected client occupies one concurrent automation session while connected; with a floating license, the application process checks out one lease from the pool at the first start()/startLocal() and holds it (with heartbeats) until it exits. Starting both transports still checks out exactly one lease. When a license expires (trial or paid), the server keeps answering handshake, ping and version but refuses everything else. See Trial & paid tiers.
6. Compile it out of release builds
The veriCue Runtime is a test-time tool. Don't ship it in production binaries: whichever transport you start, it opens a full control channel into your application's internals. The recommended pattern is a dedicated build option:
option(ENABLE_VERICUE "Embed the veriCue automation Runtime" OFF)
if(ENABLE_VERICUE)
find_package(vericue REQUIRED)
target_link_libraries(my-app PRIVATE vericue::vericue-server)
target_compile_definitions(my-app PRIVATE MYAPP_WITH_VERICUE)
endif()#ifdef MYAPP_WITH_VERICUE
#include <vericue/server.h>
#endif
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QMainWindow window;
// ...
#ifdef MYAPP_WITH_VERICUE
vericue::VeriCueServer server(&window);
server.setAuthToken(qEnvironmentVariable("MYAPP_VERICUE_TOKEN"));
# ifdef Q_OS_WIN
server.start(4242); // Windows: TCP
# else
server.startLocal(); // Linux/macOS: local IPC
qInfo().noquote() << "VERICUE_ENDPOINT=" << server.localEndpoint();
# endif
#endif
window.show();
return app.exec();
}Your QA/CI builds configure with -DENABLE_VERICUE=ON; release builds don't reference veriCue at all - no linked library, no endpoint, no open port, nothing to audit in the shipped artifact.
Security model
Be deliberate about where the automation server is reachable:
- A connected client can read widget contents, click anything, invoke methods and take screenshots - full control of the UI.
startLocal()is local by construction: a UNIX-domain socket with owner-only permissions, no port, no network presence. Prefer it whenever the client runs on the same machine.start(port)listens on all network interfaces - there is currently no bind-address option. On a developer machine or CI runner that's usually fine; on a shared network it means anyone who can reach the port can drive your application.- The TCP transport is plaintext (length-prefixed JSON). There is no TLS. Treat the port like a local debug interface, not a network service.
Recommendations, in order of importance:
- Only embed in test builds (compile-out pattern above). The strongest control is the server not existing.
- Use local IPC unless you actually need cross-host access - see Transports. On Windows local IPC is not supported yet, so a Windows rig runs on TCP and depends more heavily on the token and the firewall.
- Always set an auth token outside single-developer machines.
- Firewall the port to localhost or the CI subnet.
- For remote debugging across machines, tunnel instead of exposing:
ssh -L 4242:localhost:4242 testrigand connect tolocalhost. - Never expose the port on an untrusted or public network.

