Usage Reporting
Counts, never content. Here is every field.
Self-hosted GraphnAI deployments send GraphnAI a small usage report over HTTPS. It carries product counters: versions, scale and feature usage. It never carries identity data: no account names, domain names, SIDs, hostnames, IP addresses or free text. This page lists every field that can leave your deployment. One feature sends more than counts: automatic Microsoft Entra setup. To see the exact report your deployment would send now, open Admin > License, then select View today's report under Usage reporting.
This page is the field reference. An automated test in the product's build checks this table against the report format in both directions. The table can't drift unnoticed.
What every field means
Class legend: envelope (build and platform), identity (identifiers for the deployment or the customer organization, never a person), lifecycle (license state), inventory (graph scale), sync, feature (product usage), user (registered platform users), error (failure counts).
| Field | Type | Class | Example | Source | Why GraphnAI collects it |
|---|---|---|---|---|---|
schemaVersion | number | envelope | 2 | Report format version | Lets the receiver change the format safely |
reportType | enum | envelope | daily | startup | daily | activation | Which schedule produced this report |
recordedAt | string (RFC3339) | envelope | 2026-07-06T09:14:03Z | Generation time (UTC) | Orders reports. Kept the same when a report is sent again. |
version | string | envelope | 0.9.2 | Build version | Product version distribution |
gitCommit | string | envelope | 28691975 | Build commit | Exact build identification |
goVersion | string | envelope | go1.26.4 | Runtime version | Runtime version distribution |
platformOS | string | envelope | linux | Operating system | Operating-system distribution |
platformArch | string | envelope | amd64 | CPU architecture | CPU-architecture distribution |
uptimeSeconds | number | envelope | 431019 | Time since the server started | Puts the counts since startup on a common rate |
installId | string (UUIDv4) | identity | 0b6cbe1c-4a1e-4c6a-9f3e-1d2b8a7c5e90 | Created once, stored locally | Identifies an install (a machine), never a person |
tenantId | string | identity | tnt_8f2c1a | License subject | Identifies the customer organization (a legal entity) |
licenseId | string | identity | lic_01j9x4 | License instance | Tells license instances apart, for renewals |
licenseTier | string | lifecycle | preview | License tier | Tier distribution |
telemetryPolicy | enum | lifecycle | required | License policy | Whether reporting is required or optional |
licenseState | enum | lifecycle | active | Current license state | active or read_only. Shows when installs expire and convert. |
capState | enum | lifecycle | ok | Whether your directory has grown past the plan's identity limit | ok, grace or blocked. An install over its limit still reports active, so this is the only sign that collection is paused. |
effectiveExpiresAt | string (RFC3339) | lifecycle | 2026-08-05T14:02:11Z | Current expiry date | Renewal timing. Empty means it never expires. |
inventory.identitiesTotal | number | inventory | 913164 | Count | Deployment scale |
inventory.identitiesByType[].type | enum | inventory | User | Identity type | Mix of identity types (a fixed list) |
inventory.identitiesByType[].count | number | inventory | 502390 | Count | Scale per identity type |
inventory.edgesTotal | number | inventory | 8720662 | Count | Number of relationships in the access graph |
inventory.edgesByType[].type | enum | inventory | HasPermission | Relationship type | Mix of permissions and memberships (a fixed list) |
inventory.edgesByType[].count | number | inventory | 5982520 | Count | Relationships per type |
inventory.resourcesTotal | number | inventory | 0 | Count | Resource scale |
inventory.domainCount | number | inventory | 6 | Count only | Number of directories, never their names |
inventory.bridgeCount | number | inventory | 2 | Count | Number of Identity Bridges |
inventory.entraTenantCount | number | inventory | 1 | Count | Number of Entra ID tenants |
inventory.inventorySource | enum | inventory | snapshot | snapshot | live | Which collection path produced the counts |
sync.sinceLastReport[].syncType | enum | sync | delta | Sync type | Mix of sync types since the last report |
sync.sinceLastReport[].status | enum | sync | success | Final status | Mix of success, partial and failed syncs |
sync.sinceLastReport[].count | number | sync | 24 | Count | Number of syncs since the last report |
sync.lifetime[].syncType | enum | sync | full | Sync type | Mix of sync types since install |
sync.lifetime[].status | enum | sync | success | Final status | Mix of outcomes since install |
sync.lifetime[].count | number | sync | 9 | Count | Number of syncs since install |
sync.lastFullSyncDurationMs | number | sync | 1477402 | Duration (ms) | Duration of the last full sync |
sync.avgDurationMs | number | sync | 240670 | Average (ms) | Average sync duration since the last report |
sync.maxDurationMs | number | sync | 1477402 | Maximum (ms) | Slowest sync since the last report |
features.selectFireExecutionsByMode[].mode | enum | feature | semi-auto | Remediation mode | Mix of Select Fire™ modes |
features.selectFireExecutionsByMode[].count | number | feature | 27 | Count | Number of runs per mode |
features.selectFireRollbacks | number | feature | 5 | Actions with the Reverted status | Number of undone actions |
features.simulationsRun | number | feature | 12 | Count since the server started | Number of what-if simulations |
features.agentQueries | number | feature | 44 | Graphne activity | Number of Graphne questions answered |
features.detectionsByRule[].ruleName | enum | feature | unusual_hour | Detection rule name | Mix of detection rules (product names only) |
features.detectionsByRule[].count | number | feature | 64 | Count | Number of detections per rule |
features.alertsOpen | number | feature | 9 | Open alerts | Number of alerts open now |
users.registered | number | user | 4 | Count | Number of registered platform users |
users.byRole[].role | enum | user | admin | Role | Role distribution |
users.byRole[].count | number | user | 1 | Count | Number of users per role |
errors.syncFailures | number | error | 1 | Failed count | Number of failed syncs since the last report |
errors.syncPartials | number | error | 0 | Partial count | Number of partial syncs since the last report |
Example payload
json
{
"schemaVersion": 2,
"reportType": "daily",
"recordedAt": "2026-07-06T09:14:03Z",
"installId": "0b6cbe1c-4a1e-4c6a-9f3e-1d2b8a7c5e90",
"tenantId": "tnt_8f2c1a",
"licenseId": "lic_01j9x4",
"licenseTier": "preview",
"telemetryPolicy": "required",
"licenseState": "active",
"capState": "ok",
"effectiveExpiresAt": "2026-08-05T14:02:11Z",
"version": "0.9.2",
"gitCommit": "28691975",
"goVersion": "go1.26.4",
"platformOS": "linux",
"platformArch": "amd64",
"uptimeSeconds": 431019,
"inventory": {
"identitiesTotal": 913164,
"identitiesByType": [ { "type": "User", "count": 502390 }, { "type": "Computer", "count": 410019 } ],
"edgesTotal": 8720662,
"edgesByType": [ { "type": "HasPermission", "count": 5982520 }, { "type": "MemberOf", "count": 912505 } ],
"resourcesTotal": 0,
"domainCount": 6,
"bridgeCount": 2,
"entraTenantCount": 1,
"inventorySource": "snapshot"
},
"sync": {
"sinceLastReport": [ { "syncType": "delta", "status": "success", "count": 24 } ],
"lifetime": [ { "syncType": "full", "status": "success", "count": 9 }, { "syncType": "full_pull", "status": "success", "count": 3 } ],
"lastFullSyncDurationMs": 1477402,
"avgDurationMs": 240670,
"maxDurationMs": 1477402
},
"features": {
"selectFireExecutionsByMode": [ { "mode": "semi-auto", "count": 27 } ],
"selectFireRollbacks": 5,
"simulationsRun": 12,
"agentQueries": 44,
"detectionsByRule": [ { "ruleName": "unusual_hour", "count": 64 } ],
"alertsOpen": 9
},
"users": { "registered": 4, "byRole": [ { "role": "admin", "count": 1 }, { "role": "operator", "count": 3 } ] },
"errors": { "syncFailures": 1, "syncPartials": 0 }
}What's never sent
This list covers the usage report. Automatic Microsoft Entra setup is separate: see Automatic Microsoft Entra setup.
The report's format can't carry identity content. It has no free-text fields and no maps, and an automated test in the product's build enforces that. GraphnAI never receives:
- Distinguished names (DNs)
- Account names (sAMAccountName, UPN, display names)
- Domain names or DNS names
- Security identifiers (SIDs)
- Hostnames or computer names
- IP addresses
- Free text of any kind, including error messages
- File paths
Domains, bridges and Entra ID tenants appear only as counts, never as names.
Per-policy behavior
Your license sets one of two policies. The Usage reporting card on Admin > License shows which applies.
- Required (Public Preview and free plans): reporting is part of the license terms and is always on. The card shows "Included with your plan" and has no off switch. This page lists exactly what's sent.
- Optional (paid plans): reporting is off by default. Nothing is sent until an administrator turns it on, on the License page. The card shows "Optional" and a switch that reads "Sharing" or "Not sharing".
- Air-gapped: a deployment with no outbound access never reports. Under the required policy, after 14 days without a successful report, administrators see a banner. Nothing else changes: syncs, sign-ins and every feature keep working, and the license expiry stays the same.
Turning it on in the app takes effect without a server restart. If you turned it off and back on since the server started, reporting resumes with the next daily report.
Turning it off
For deployments under the optional policy:
- Open Admin > License and turn off the switch under Usage reporting. It takes effect before the next daily report.
- Whoever deploys GraphnAI can also turn it off, or on, in the server's configuration before it starts.
- When the server's configuration sets it, the switch is disabled and says so. Whoever manages the server can remove that setting and restart the server to use the switch again.
Under the required policy, reporting can't be turned off.
The Usage reporting switch and its server setting don't control the daily update check. Only GRAPHNAI_UPDATE_CHECK does.
Outbound connectivity (for firewall teams)
- Host and port:
api.graphnai.com:443(HTTPS, standard public TLS certificates). - Schedule: a report 5 to 15 minutes after the server starts, then one every 23 to 25 hours. A one-time report follows the first successful sync.
- Size: usually 2 to 8 KiB, with a hard limit of 32 KiB.
- Retries: each report is tried up to 3 times. A report that still fails waits, for up to 30 days, and is sent later. The card shows how many are waiting.
- Update check: the daily check for a new release uses the same host, but it's a separate request that carries no report. It sends only the server version in its User-Agent.
- Direction: outbound only. Each report is signed with a key derived from your license, so the receiver can check where it came from. The usage report never carries the license itself. Automatic Microsoft Entra setup is the one exception, described below.
Automatic Microsoft Entra setup
Setup with Sign in with Microsoft, adding an Entra ID tenant and updating an app registration go through GraphnAI's sign-in service at api.graphnai.com. During these sign-ins only, your server sends the service your license and the return address of your GraphnAI server, which can contain an internal host name.
This differs from usage reporting in these ways:
- It isn't counts-only, and the usage reporting setting doesn't control it.
- Your usage reports are signed with a key derived from your license. Anyone who can read the license where GraphnAI's sign-in service receives it can derive that key.
- It happens only when you start one of these sign-ins. Nothing is sent otherwise.
If you don't want to send the license, use Use an existing app registration and add the permissions in the Microsoft Entra admin center. The manual path sends nothing to GraphnAI. Your browser must also reach https://api.graphnai.com over HTTPS for the automatic path.
The Usage reporting card
The card on Admin > License shows the policy and whether reporting is on. A status line shows when the last report went out: "Last sent", "No report sent yet" or "Not sending". When reports fail, it says so and names the fix: "Reports aren't reaching GraphnAI. Allow outbound HTTPS to api.graphnai.com." Under the required policy, it adds the date to fix it by.
Under the required policy, after 14 days without a report, a banner reads "Usage reports haven't reached GraphnAI since {date}, and your license requires them." Only administrators see it. You can dismiss it for the rest of your browser session.
See your exact report
On Admin > License, select View today's report under Usage reporting. The Today's usage report dialog shows the exact report this deployment would send now. It works under every policy, including when reporting is off. Viewing it sends nothing.
Optional-class metrics
None defined yet. An optional class is reserved for future metrics that you choose to share, such as performance distributions or posture totals. It's empty today. Each metric will get a row on this page before GraphnAI collects it.