Wytness Collector

The Collector is a container you run yourself. It polls the Azure logging stores you already have — Application Insights / Log Analytics rows from Microsoft Foundry server-side tracing and Copilot Studio telemetry — turns each row into a Wytness event, signs it with your Ed25519 key and PII-tokenizes it inside your own boundary, then POSTs signed envelopes to the ingest endpoint. It's how you capture agents that never call an SDK directly.

How it works

  1. Polls each configured source on a cadence and reads the new rows since its last cursor.
  2. Converts each row into a Wytness event, deterministically keyed so re-reads never duplicate.
  3. Signs and PII-tokenizes the event inside your container, reusing the same wytness-ai crypto the SDK uses — your keys and secrets never leave your boundary.
  4. POSTs the signed envelope to your ingest endpoint and advances the cursor.

The collected tier

Collector events carry the collected assurance tier: proof the log content is untouched since pickup. This is deliberately below — and never conflated with — the SDK's sdk-signed tier, which attests an action at the moment it happened. The dashboard labels each tier distinctly so an auditor always knows which guarantee applies.

Setting it up

Five things to gather, then one command. Everything except the container is a one-off, and every credential stays on your side — Wytness never receives your Azure keys, your signing private key or your PII secret.

1. Let the collector read your logs

The collector reads the Azure logging stores your agents already write to. Turn the export on, then create one identity that can read it.

  • Microsoft Foundry. Connect an Application Insights resource to the project — portal: project → Tracing → Connect, or scriptable via an ARM connection PUT.
  • Copilot Studio. Power Platform admin center → the environment → Data export → Application Insights. One environment-level switch covers both authoring experiences and autonomous runs. Prerequisites: Managed Environment, Dataverse capacity and Copilot Studio licensing.
  • The identity. Create a service principal and grant it Log Analytics Reader on the workspace's resource group. The same principal covers both sources when they share a workspace.
Important
From 30 September 2026 the AppGenAIContent table becomes Protected. The service principal will additionally need Privileged Monitoring Data Reader, or Foundry prompt and response content stops arriving.

Note down four values for step 5: the Log Analytics workspace GUID, and the principal's tenant id, client id and client secret.

2. Create a dedicated API key

In the dashboard, go to Crypto keys and create an API key used only by the collector. A dedicated key means its traffic is attributable, and revoking it never interrupts your SDK-instrumented agents. This is WYTNESS_API_KEY.

3. Generate a dedicated signing keypair

Also on Crypto keys, generate a new Ed25519 signing keypair, label it for the collector, and register the public key. The private half is shown once and never leaves your browser — paste it straight into your secret store. This is WYTNESS_SIGNING_KEY, and it is what makes each collected event non-repudiable.

Important
Generate the key before the collector starts. Ingest rejects envelopes signed by an unregistered key rather than trusting them on first sight, so an unregistered collector is refused, not silently accepted.

A key covers events from its creation onwards — that is what stops anyone signing back-dated evidence. The collector honours it: its first run normally back-fills 24 hours, but if the key is younger than that it starts at the key instead and says so in the log. Nothing is lost that could have been accepted, and if you want that first day captured, create the key before the period you intend to record.

4. Copy your PII tokenization keys

From Privacy, copy your organisation's PII public key and HMAC secret — WYTNESS_PII_PUBKEY and WYTNESS_PII_SECRET. The collector uses them to replace personal data with tokens before anything leaves your network, which is why Wytness can never read it back. See PII Protection for what is detected automatically and what you should declare.

5. Describe your sources

Each source is one entry in COLLECTOR_SOURCES — either inline JSON or a path to a mounted file. Use the four values from step 1.

sources.json
[
{
"kind": "foundry_traces",
"workspace_id": "<Log Analytics workspace GUID>",
"display_name": "Foundry — prod",
"resource_id": "<App Insights ARM id — required when sources share a workspace>",
"tenant_id": "...",
"client_id": "...",
"client_secret": "..."
}
]

Supported kinds are foundry_traces and copilot_studio_env. Source credentials live only in your container or vault — Wytness never stores them.

6. Run the container

terminal
docker run -d --name wytness-collector \
--restart unless-stopped \
--memory=512m --cpus=1 \
-v wytness-collector-state:/var/lib/wytness-collector \
-e WYTNESS_API_KEY=... -e WYTNESS_ENDPOINT=... -e WYTNESS_SIGNING_KEY=... \
-e WYTNESS_PII_PUBKEY=... -e WYTNESS_PII_SECRET=... \
-e COLLECTOR_SOURCES='[...]' \
ghcr.io/wytness-ai/wytness-collector:0.1.0
Tip
Pin by digest in production — ghcr.io/wytness-ai/wytness-collector@sha256:…. docker pull prints the digest, and every publish records it. Tags are mutable; digests are not.
  • Resource limits. The collector runs comfortably in 512 MB / 1 CPU; sources with very large model contexts may need more memory. The image ships a HEALTHCHECK against /healthz.
  • The volume matters. It persists the poll cursor (no re-ship or skip across restarts) and the dead-letter file (no event loss across delivery outages). Mount it on durable storage.

7. Check it's working

Three things should be true within a few minutes. If any is not, the collector tells you which.

  • The container is healthy. docker ps shows it healthy — the image ships a HEALTHCHECK against /healthz.
  • It has checked in. The Collectors page in the dashboard lists your instance with a recent heartbeat and one row per configured source.
  • Events are arriving. On Events, filter to the collected tier. Each event names the source it came from.
Tip
A source that is configured but has produced nothing is flagged as silent after COLLECTOR_SILENCE_HOURS (default 6). That is the signal to check step 1 — the export switch or the principal's role assignment is the usual cause.

Configuration

Wytness credentials are shared with the SDK. Use a dedicated API key and a dedicated Ed25519 signing keypair for the collector so its activity is attributable and revocable on its own.

Env varPurpose
WYTNESS_API_KEYOrg API key — use a dedicated key for the collector.
WYTNESS_ENDPOINTIngest endpoint (defaults to https://api.wytness.ai).
WYTNESS_SIGNING_KEYEd25519 key — use a dedicated signing keypair (label collector).
WYTNESS_PII_PUBKEY / WYTNESS_PII_SECRETCustomer-held PII tokenization keys.

Collector-specific settings:

Env varPurpose
COLLECTOR_SOURCESJSON list of source configs, or a path to a mounted JSON file.
COLLECTOR_POLL_SECONDSPoll cadence (default 120, min 30).
COLLECTOR_STATE_PATHCursor persistence path (default /var/lib/wytness-collector/state.json).
COLLECTOR_SILENCE_HOURSSilence threshold carried on every heartbeat (default 6).
COLLECTOR_ID / COLLECTOR_LABELInstance identity shown on the Collectors page.
COLLECTOR_HEALTH_PORT/healthz port (default 8080).

Sources

The source list is built in step 5. Two notes that matter once you have more than one.

Note
resource_id is required when two sources share a single Log Analytics workspace, so each stream is attributed to the right App Insights resource. Source credentials live only in your container or vault — Wytness never stores them.

Resilience

  • Log Analytics throttling or outage. 429s honour Retry-After (capped); 408/5xx and network errors retry with capped jittered backoff, and a revoked AAD token re-auths once. A source that exhausts its retries records the error on its heartbeat and retries next poll — one broken source never stalls the others.
  • Ingest outage or rejected delivery. Undeliverable batches append to a dead-letter file beside the cursor on the volume and replay through the live transport every cycle. Deterministic event IDs mean duplicates collapse server-side, so replay is safe by construction.
  • Bad or unregistered signing key. Validated at startup with a loud error and the fix path; capture continues — events dead-letter and replay automatically once the key is registered. Ongoing delivery failure also surfaces per-source on the Collectors page.
  • Corrupt state. A corrupt cursor restarts from empty (overlap re-reads are dedup-safe); unparseable dead-letter lines are set aside, never looped and never silently dropped.

Versioning & updates

The Collector has its own semver, independent of the SDKs (it pins a minimum wytness-ai). Images are published through CI only — collector tests, then image build, then an image-layer secret scan, then push to GHCR with the digest recorded in the run. To update, pull the new digest and recreate the container; the volume carries your cursor and any pending dead-letter forward.

Bring your Foundry and Copilot Studio activity into your audit trail.

Start recording

We set no cookies. Sign-in and preferences use essential first-party browser storage only — no tracking, advertising, or third-party analytics. Privacy Policy

Wytness Collector
TABLE OF CONTENTS