Monitoring Config Reference

📋 Introduction

A monitoring rule is a JSON document that tells the Agent/Worker/Profiler which
application to watch and exactly what to collect from it (window/click activity, CPU and
memory, HTTP calls, session replay, and so on). This document is the full reference for
that JSON format.

⚙️ How a rule reaches the Agent

You will normally author these rules in the GermainUX server's admin UI, not hand-edit
JSON files — but understanding where the JSON comes from helps when diagnosing why a
setting doesn't seem to be taking effect:

  1. The Agent polls the server for the list of target applications and their rule names.

  2. For each rule, it fetches the rule's JSON from the server by name.

  3. If the server request fails, it falls back to a file named
    {Agent install folder}\\config\\{ruleName}.json.

  4. A local rule (registry
    Targets\\{exe}\\ConfigFile) bypasses all of the above and is read directly from the
    file path you specify — this is the only path that doesn't need a server at all.

In every case, the resulting JSON has the same shape described below, and you can always
confirm exactly what's currently applied via the tray icon's Configurations submenu
(see Agent Settings).

A minimal starting point is shown in full at the bottom of this document. Every field
below is optional unless stated otherwise — omitting a block leaves that feature at its
default (generally: off).

📁 Top-level fields

JSON
{
  "application": "My Application",
  "version": "2026.1",
  "agentName": "MyApplication-Prod",
  "profileName": "Default",
  "correlationId": ""
}

Field

Purpose

application

Free-text application name attached to every fact this rule produces.

version

Informational agent/rule version string.

agentName

Unique name identifying this monitoring rule instance; used for provenance and is the name the Agent uses when fetching this rule's config by name.

profileName

Name of the monitoring profile this rule belongs to; informational/provenance only.

correlationId

Normally left unset — the Agent mints one per monitored process automatically so the Worker and Profiler's facts for the same running instance can be joined together.

🔧 monitorConfig

JSON
"monitorConfig": {
  "winTitle": "My Application",
  "useImageSibling": false
}

Field

Purpose

winTitle

Partial window title used to help identify the application's main window.

useImageSibling

When a click lands on an image control, also look for a sibling element to attribute the click to (useful for icon-only buttons where the clickable label lives in a neighboring element).

📦 queue — how facts are sent

JSON
"queue": {
  "pushInterval": 30,
  "bufferSize": 1000,
  "batchSize": 100,
  "outputPath": "",
  "prettyOutput": false,
  "httpTimeoutMs": 5000
}

Field

Default

Purpose

pushInterval

30

Seconds between pushes to GermainUX.

bufferSize

1000

Max facts held in memory before older ones are dropped.

batchSize

100

Max facts sent per HTTP request.

outputPath

(none)

When set, facts are written to this local file instead of sent over HTTP — useful for offline capture/testing. Leave unset for normal operation.

prettyOutput

false

Indent the JSON when writing to outputPath.

httpTimeoutMs

5000

Timeout for each data-upload HTTP request. Keep this well below the Agent's worker shutdown grace period so a final flush at shutdown has time to complete or fail cleanly rather than being force-killed mid-send.

🛡️ proxy

JSON
"proxy": {
  "url": "http://localhost:",
  "delayInit": false,
  "excludedPorts": [ 443, 4225, 4226 ],
  "minPort": 10000
}

Configures an outbound proxy used for HTTP monitoring interception. excludedPorts keeps
the proxy from intercepting traffic on ports you don't want captured (commonly the
GermainUX ports themselves, to avoid the agent monitoring its own uploads).

🐛 debug

JSON
"debug": {
  "walkSiblings": false,
  "walkTree": false,
  "dumpTree": false,
  "dumpSnapshot": false,
  "printCreateWinInfo": false
}

Verbose diagnostic logging switches for the UI Worker's own troubleshooting (dumping
control trees, sibling walks, snapshot contents, etc. to the log). All should stay false
in normal production use — they add log volume and are only useful when working with
support to diagnose a UI-capture issue.

💡 logging

JSON
"logging": {
  "level": "INFO",
  "name": "myapplication",
  "path": "C:/germainagent/"
}

Informational metadata carried with the rule. This does not control where the Worker or
Profiler actually write their log files — that's governed entirely by the
LogPath/WorkerLogLevel/CLRLogLevel registry settings described in
Agent Settings. Leave this block as-is or omit it.

🌐 globalVariables — context attached to every fact

JSON
"globalVariables": [
  {
    "name": "username",
    "filter": { "type": "text", "name": "UsernameControlAutomationId" },
    "lowerCase": true
  }
]

Each entry describes a value to read from the UI once and attach as context to every
fact emitted afterward (e.g. the logged-in username shown somewhere in the app's chrome).
See Context variable fields below for the full field list —
userClicks selector variables use the exact same shape.

🔒 Data privacy: masking and exclusions

Two related, independent settings control what raw values are allowed to leave the
machine:

JSON
"maskAll": false,
"exclusions": [
  {
    "name": "Suppress username from facts",
    "fieldName": "user.name",
    "type": 1,
    "factType": "",
    "pattern": "",
    "preserveLength": true,
    "preserveWhitespace": false
  }
]

Field

Purpose

maskAll

When true, every text field is masked by default unless it has its own explicit rule below. Use this for applications where sensitive data could appear almost anywhere and you'd rather opt fields in to being sent raw (by not needing a rule for them, once excluded rules apply) than try to enumerate every sensitive field.

exclusions[].name

Descriptive label for the rule (not sent anywhere, just for your own reference).

exclusions[].fieldName

Dot-path of the fact field this rule applies to (e.g. user.name).

exclusions[].factType

Optional — restrict the rule to a specific fact type value; omit to apply to the field name across all fact types.

exclusions[].type

Which sanitization to apply — see table below.

exclusions[].pattern

Optional regular expression. When set, only the matched portion of the value is sanitized; when omitted, the entire value is sanitized.

exclusions[].preserveLength

Mask-only: replace each character with * (keeping the original length) rather than a fixed-length placeholder. Default true.

exclusions[].preserveWhitespace

Mask-only: leave whitespace characters unmasked so the text still "looks like" separate words. Default false.

type values:

type

Behavior

0 — Mask

Replace the value (or matched portion) with * characters.

1 — Anonymize

Replace the value with a one-way hash — irreversible, but two occurrences of the same original value hash identically, so equality-based analysis still works.

2 — Exclude

Remove the value entirely.

features — everything else is opt-in

All monitoring capability beyond basic identification lives under features, one block
per capability, each independently enabled. This section is required to be present in
the rule JSON (even if every sub-feature inside it is left off).

📊 processMetrics

JSON
"processMetrics": {
  "enabled": true,
  "interval": 60,
  "clrFallbackEnabled": false,
  "threadDetailEnabled": true,
  "threadPoolEnabled": false,
  "resourceCountersEnabled": false
}

Periodic OS-level process metrics: CPU %, working-set memory, thread count/detail, and
(optionally) handle/GDI/USER object counts and disk I/O deltas — the classic native
resource-leak indicators for a long-running desktop app.

Field

Purpose

enabled / interval

Turn on collection and set its interval (seconds).

clrFallbackEnabled

Only relevant for a headless .NET process with no UI Worker — makes the CLR Profiler collect these metrics itself instead. Leave false for normal WPF/WinForms applications, which are already covered by the UI Worker.

threadDetailEnabled

Emit a per-thread CPU/state sample (via WMI), not just a total thread count.

threadPoolEnabled

Also report a best-effort count of .NET ThreadPool-named threads (only meaningful on .NET 6+ targets; reads 0 on older runtimes).

resourceCountersEnabled

Also report process handle count, GDI object count, USER object count, and disk read/write byte deltas since the last sample.

♻️ gcMetrics

JSON
"gcMetrics": { "enabled": false, "interval": 60 }

.NET garbage-collection metrics: a fact per GC pause as it happens (with generation,
whether it was induced, and heap size before/after), plus periodic cumulative gen0/1/2
collection counts every interval seconds. Requires the CLR Profiler to be attached.

⏱️ freezeDetection

JSON
"freezeDetection": { "enabled": false, "pollIntervalMs": 2000, "hangTimeoutMs": 2000 }

Periodically pings each monitored window (pollIntervalMs) to see if it's still
responding to messages, waiting up to hangTimeoutMs before considering it hung. A fact
is emitted when a previously-hung window recovers, reporting how long it was
unresponsive. This runs its own background thread independent of other UI monitoring, so
it has a real (small) always-on cost — weigh that against how important freeze detection
is for the target application.

🔬 profiler — CPU sampling

JSON
"profiler": { "enabled": false, "interval": 1000, "inclusions": [], "exclusions": [] }

Stack-sampling CPU profiler (requires the CLR Profiler attached). interval is how often
(ms) a stack sample is taken. inclusions/exclusions are executable-name filters for
which modules' code should appear in samples (both empty = everything).

📡 http — outbound HTTP monitoring

JSON
"http": {
  "enabled": false,
  "sslEnabled": true,
  "sslPorts": [ 443 ],
  "excludedPorts": [ 4225, 4226 ],
  "collectRequestBody": true,
  "requestBodyExclusions": "",
  "collectResponseBody": true,
  "responseBodyExclusions": ".*(css|js|png|jpg|jpeg|gif|svg|mpg)",
  "collectHeaders": false
}

Captures outbound HTTP(S) calls made by the target process, broken into connect/wait/
download timing phases.

Field

Purpose

sslEnabled / sslPorts

Enable TLS interception on the listed ports, needed to see HTTPS request/response detail (not just timing).

excludedPorts

Ports never monitored — typically your own GermainUX ports, to avoid capturing the agent's own uploads.

collectRequestBody / requestBodyExclusions

Whether to capture request bodies, and a regex of URLs/content to skip (e.g. large binary uploads).

collectResponseBody / responseBodyExclusions

Same, for responses — the sample regex above skips static assets (CSS/JS/images) as noise.

collectHeaders

Also capture request/response headers, including parsed Server-Timing data.

exception

JSON
"exception": { "enabled": false }

Reports managed (.NET) exceptions as they're thrown, with a captured stack trace.
Requires the CLR Profiler.

👁️ monitor — core UI activity

JSON
"monitor": {
  "enabled": true,
  "windowEventsEnabled": true,
  "mouseEnabled": false,
  "changeEnabled": false,
  "keyboardEnabled": false
}

The baseline UI Worker monitoring feature; everything below it in this section
(clickMaps, userClicks, userSearches, userFacingErrors) requires enabled: true
here as well.

Field

Purpose

enabled

Master switch — when false, no monitoring facts are produced at all.

windowEventsEnabled

Report windows being created/destroyed, and the app's own startup.

mouseEnabled

Report every mouse click on a control (raw telemetry — not filtered to specific business actions; see userClicks for that).

changeEnabled

Report when an input control's value changes (text edits, checkbox/radio toggles).

keyboardEnabled

Report command-style key presses (Enter, Escape, function keys, Ctrl/Alt/Win combinations) — not general text typed into fields.

🔥 clickMaps / mouseMaps — heatmap overlays

JSON
"clickMaps": { "enabled": false },
"mouseMaps": { "enabled": false }

clickMaps reports one point per click (control + screen position) for click-heatmap
visualizations. mouseMaps buffers raw mouse movement and flushes it periodically (every
5 minutes, on view change, or at shutdown) for movement heatmaps. Both are tagged with
whichever "view" was most recently identified by a userClicks selector — see below.

☝️ userClicks — business-level click tracking

JSON
"userClicks": {
  "enabled": false,
  "typeValue": "Native:User Click",
  "selectors": {
    "Button Click": {
      "prefix": "Click on",
      "filter": { "type": "button" },
      "variables": [
        {
          "name": "argument1",
          "contextScan": false,
          "filter": { "name": "hierarchy" },
          "childIndex": 0
        }
      ],
      "requireDoubleClick": false
    }
  }
}

Unlike monitor.mouseEnabled (which reports every click), userClicks only reports a
click when it matches one of your named selectors — intended for tracking specific
business actions ("clicked Submit", "opened a customer record") rather than raw UI noise.

Field

Purpose

typeValue

The fact type string stamped on every match (e.g. Native:User Click).

selectors.{name}.filter

Which control this selector matches — see Filter fields.

selectors.{name}.prefix

Text prefix used when building a description of the click (default: "Click on \<control\>").

selectors.{name}.labelExpression / nameExpression

Optional regexes further constraining the match against the control's label/name.

selectors.{name}.requireDoubleClick

Only match when the click was paired as a double-click (e.g. a DataGrid row drill-down), not a single click.

selectors.{name}.variables

Extra context variables captured from elsewhere in the UI and attached to this specific click's fact.

🔍 userSearches

JSON
"userSearches": {
  "enabled": false,
  "selectors": {
    "Search Button": {
      "trigger": { "type": "button", "name": "SearchButton" },
      "valueControl": { "name": "SearchBox" }
    }
  }
}

When the trigger control is clicked, the current value of the separate valueControl
is captured as the search term. Use this for search boxes where the meaningful value
lives in a different control than the one that was clicked.

warning userFacingErrors

JSON
"userFacingErrors": {
  "enabled": false,
  "rules": [
    { "label": "Error Dialog", "pattern": "[Ee]rror|[Ff]ailed|[Ee]xception" }
  ]
}

Reports when a newly created window's title matches one of the given regular
expressions — a lightweight way to detect error/failure dialogs without needing to
identify their exact controls. label becomes the fact's name field on a match.

🎞️ replay — session replay

JSON
"replay": {
  "enabled": false,
  "pointerEnabled": true,
  "controlMutationEnabled": true,
  "structuralChangesEnabled": true,
  "windowLifecycleEnabled": true,
  "focusMonitoringEnabled": true,
  "scrollMonitoringEnabled": true,
  "scrollbarMonitoringEnabled": true,
  "fragmentMaxEvents": 1000,
  "fragmentMaxAge": 15,
  "snapshotInterval": 30,
  "iconWin32Enabled": false,
  "thumbnailRules": [],
  "colorSamplingEnabled": false,
  "colorSamplingTypes": [ "pane", "window", "group", "button" ],
  "selfHealEnabled": false,
  "selfHealBurstThreshold": 3
}

Captures enough of the UI tree over time to reconstruct a visual replay of the session,
independent of the plain monitoring facts above.

Field

Purpose

enabled

Master switch for all replay capture.

pointerEnabled

Record mouse clicks/moves.

controlMutationEnabled

Record control property changes (label, bounds, visibility).

structuralChangesEnabled

Record controls being added/removed from the UI tree.

windowLifecycleEnabled

Record windows being created/destroyed.

focusMonitoringEnabled

Record focus changes between controls.

scrollMonitoringEnabled / scrollbarMonitoringEnabled

Record scroll position/size and scrollbar thumb/track position changes.

fragmentMaxEvents / fragmentMaxAge

Flush the current batch of replay events after this many events, or this many seconds, whichever comes first.

snapshotInterval

Emit a full state snapshot at least this often (seconds); 0 disables periodic snapshots (a snapshot is always still captured at startup).

iconWin32Enabled

Capture each monitored window's application icon (via WM_GETICON/executable resource) for display in the replay viewer.

thumbnailRules

Ordered rules selecting which child controls get a captured visual thumbnail, and when to re-capture one — see Thumbnail rule criteria.

colorSamplingEnabled / colorSamplingTypes

Sample background/border colors of controls (restricted to the listed UIA control type names; empty = all types) so the replay viewer can approximate styling without a full screenshot.

selfHealEnabled / selfHealBurstThreshold

Periodically re-scan the live UI tree to correct any drift between it and the Worker's in-memory copy; a rescan is also triggered after this many consecutive forced/deadline flushes in a row. Leave off unless replay data has been observed to drift from the real UI.

🏷️ Filter fields

Used by userClicks/userSearches selectors, globalVariables, and context variables,
to identify a specific control:

Field

Matches on

type

UIA control type, as a lowercase name (button, edit, combo box, data grid, check box, list item, tab item, tree item, hyperlink, image, menu item, and other standard UIA control type names).

name

The control's UIA AutomationId.

label

The control's visible label/name text.

classname

The Win32 window class name.

Any combination of these can be set; all specified fields must match (AND).

📑 Context variable fields

Used by both globalVariables and a userClicks selector's variables:

Field

Purpose

name

The name this value is attached to the fact under.

filter

Which control to read the value from — see Filter fields above.

childIndex

If ≥ 0, read from the Nth child of the matched element instead of the element itself.

siblingIndex

If non-zero, read from a sibling offset by this many positions instead.

expression

Optional regex applied to the raw value; if present, only the matched portion is kept.

contextScan

Whether to actively search the UI tree for this value (true, default) vs. only checking the element directly involved in the triggering event.

defaultOnFailure

If expression is set and doesn't match, fall back to a default value instead of omitting the variable.

lowerCase

Lowercase the captured value.

🖼️ Thumbnail rule criteria

Each replay.thumbnailRules[] entry has a method ("win32" or "screen" capture) and
a criteria object of AND'd match conditions, evaluated against each control the Worker
encounters:

Criteria field

Matches

type / not_type

UIA control type name(s) that must / must not match (see Filter fields for the naming convention).

aid / not_aid

AutomationId(s) that must / must not match.

classname / not_classname

Exact Win32 class name(s) that must / must not match.

classnameSplit / all_classnameSplit / not_classnameSplit

Win32 class name, split on whitespace into tokens: "any of these tokens present" / "all of these tokens present" / "none of these tokens present".

label / not_label

Visible label(s) that must / must not match (use "" to match/exclude an empty label).

hasChildren

true/false — require the control to have/not have children.

hasRect

true/false — require the control to have/not have a non-zero bounding rectangle (i.e. actually visible on screen).

Each rule also takes a top-level recaptureOn array listing which attribute changes
(label, visibility, bounds, value, selected) should trigger re-capturing the
thumbnail for a matched control after its first capture; omit it (or leave it empty) to
capture once and never recapture.

📄 Full example

See Config/agent-config-sample.json in the agent source tree for a complete, valid
starting-point file combining every block above with realistic default values and a
"description" field explaining it's meant to be copied and customized per application.

🖼️ Thumbnail rule criteria

Each replay.thumbnailRules[] entry has a method ("win32" or "screen" capture) and
a criteria object of AND'd match conditions, evaluated against each control the Worker
encounters:

Criteria field

Matches

type / not_type

UIA control type name(s) that must / must not match (see Filter fields for the naming convention).

aid / not_aid

AutomationId(s) that must / must not match.

classname / not_classname

Exact Win32 class name(s) that must / must not match.

classnameSplit / all_classnameSplit / not_classnameSplit

Win32 class name, split on whitespace into tokens: "any of these tokens present" / "all of these tokens present" / "none of these tokens present".

label / not_label

Visible label(s) that must / must not match (use "" to match/exclude an empty label).

hasChildren

true/false — require the control to have/not have children.

hasRect

true/false — require the control to have/not have a non-zero bounding rectangle (i.e. actually visible on screen).

Each rule also takes a top-level recaptureOn array listing which attribute changes
(label, visibility, bounds, value, selected) should trigger re-capturing the
thumbnail for a matched control after its first capture; omit it (or leave it empty) to
capture once and never recapture.

📄 Full example

See Config/agent-config-sample.json in the agent source tree for a complete, valid
starting-point file combining every block above with realistic default values and a
"description" field explaining it's meant to be copied and customized per application.

🖼️ Thumbnail rule criteria

Each replay.thumbnailRules[] entry has a method ("win32" or "screen" capture) and
a criteria object of AND'd match conditions, evaluated against each control the Worker
encounters:

Criteria field

Matches

type / not_type

UIA control type name(s) that must / must not match (see Filter fields for the naming convention).

aid / not_aid

AutomationId(s) that must / must not match.

classname / not_classname

Exact Win32 class name(s) that must / must not match.

classnameSplit / all_classnameSplit / not_classnameSplit

Win32 class name, split on whitespace into tokens: "any of these tokens present" / "all of these tokens present" / "none of these tokens present".

label / not_label

Visible label(s) that must / must not match (use "" to match/exclude an empty label).

hasChildren

true/false — require the control to have/not have children.

hasRect

true/false — require the control to have/not have a non-zero bounding rectangle (i.e. actually visible on screen).

Each rule also takes a top-level recaptureOn array listing which attribute changes
(label, visibility, bounds, value, selected) should trigger re-capturing the
thumbnail for a matched control after its first capture; omit it (or leave it empty) to
capture once and never recapture.

📄 Full example

See Config/agent-config-sample.json in the agent source tree for a complete, valid
starting-point file combining every block above with realistic default values and a
"description" field explaining it's meant to be copied and customized per application.

🖼️ Thumbnail rule criteria

Each replay.thumbnailRules[] entry has a method ("win32" or "screen" capture) and
a criteria object of AND'd match conditions, evaluated against each control the Worker
encounters:

Criteria field

Matches

type / not_type

UIA control type name(s) that must / must not match (see Filter fields for the naming convention).

aid / not_aid

AutomationId(s) that must / must not match.

classname / not_classname

Exact Win32 class name(s) that must / must not match.

classnameSplit / all_classnameSplit / not_classnameSplit

Win32 class name, split on whitespace into tokens: "any of these tokens present" / "all of these tokens present" / "none of these tokens present".

label / not_label

Visible label(s) that must / must not match (use "" to match/exclude an empty label).

hasChildren

true/false — require the control to have/not have children.

hasRect

true/false — require the control to have/not have a non-zero bounding rectangle (i.e. actually visible on screen).

Each rule also takes a top-level recaptureOn array listing which attribute changes
(label, visibility, bounds, value, selected) should trigger re-capturing the
thumbnail for a matched control after its first capture; omit it (or leave it empty) to
capture once and never recapture.

📄 Full example

See Config/agent-config-sample.json in the agent source tree for a complete, valid
starting-point file combining every block above with realistic default values and a
"description" field explaining it's meant to be copied and customized per application.

🖼️ Thumbnail rule criteria

Each replay.thumbnailRules[] entry has a method ("win32" or "screen" capture) and
a criteria object of AND'd match conditions, evaluated against each control the Worker
encounters:

Criteria field

Matches

type / not_type

UIA control type name(s) that must / must not match (see Filter fields for the naming convention).

aid / not_aid

AutomationId(s) that must / must not match.

classname / not_classname

Exact Win32 class name(s) that must / must not match.

classnameSplit / all_classnameSplit / not_classnameSplit

Win32 class name, split on whitespace into tokens: "any of these tokens present" / "all of these tokens present" / "none of these tokens present".

label / not_label

Visible label(s) that must / must not match (use "" to match/exclude an empty label).

hasChildren

true/false — require the control to have/not have children.

hasRect

true/false — require the control to have/not have a non-zero bounding rectangle (i.e. actually visible on screen).

Each rule also takes a top-level recaptureOn array listing which attribute changes
(label, visibility, bounds, value, selected) should trigger re-capturing the
thumbnail for a matched control after its first capture; omit it (or leave it empty) to
capture once and never recapture.

📄 Full example

See Config/agent-config-sample.json in the agent source tree for a complete, valid
starting-point file combining every block above with realistic default values and a
"description" field explaining it's meant to be copied and customized per application.