Semantic conventions
Belemetry follows the OpenTelemetry data model and its semantic conventions, so a page view, a fetch or an exception arrives with the attribute names every OTLP backend already knows how to query. This page is the reference: what each record looks like, the resource that describes where it came from, the feature bit it belongs to, and what the script keeps in browser storage.
Feature bits
Every record belongs to exactly one feature, and is only collected while that feature is both switched on
by configuration (options.Features) and granted by the user. The numbers are the same in C#
(BelemetryFeatures) and in the script (Features), and they are what
BitBelemetry.setConsent takes.
| Name | Bit | Covers |
|---|---|---|
Errors | 1 | JS errors and unhandled rejections; .NET logs at Error/Critical or carrying an exception; TrackException |
PageViews | 2 | Page views (history/enhanced navigation, TrackPageView) |
Interactions | 4 | Clicks and other user interactions |
Performance | 8 | Web vitals (LCP, INP, CLS, FCP, TTFB), document-load span, resource timing, long tasks |
Dependencies | 16 | Browser fetch/XHR client spans |
Sessions | 32 | A session id that survives reloads (in sessionStorage). Without it, the session id lives in memory only |
UserTracking | 64 | enduser.pseudo.id (random id persisted in localStorage) and user.id (authenticated id from SetUser) |
Logs | 128 | .NET logs below Error; browser console capture below error |
Traces | 256 | .NET Activity spans |
Metrics | 512 | .NET Meter metrics |
Persistence | 1024 | Keeping unsent telemetry on the device (localStorage / files) for retry after going offline or reloading |
Events | 2048 | Custom events (TrackEvent) |
| Group | Value | Members |
|---|---|---|
Diagnostics | 401 | Errors, Logs, Traces, Dependencies |
Analytics | 2150 | PageViews, Interactions, Sessions, UserTracking, Events |
Monitoring | 520 | Performance, Metrics |
All | 4095 | Every feature |
BelemetryFeatures
Enum
The independently consentable parts of Belemetry. Every telemetry record belongs to exactly one feature, and a record is only sent while its feature is both enabled by configuration and granted by the user.
| Value | Number | Description |
|---|---|---|
None |
0 |
Nothing. |
Errors |
1 |
JS errors and unhandled rejections, .NET logs at Error/Critical or carrying an exception, and TrackException. |
PageViews |
2 |
Page views - history and enhanced navigation, and TrackPageView. |
Interactions |
4 |
Clicks and other user interactions. |
Performance |
8 |
Web vitals (LCP, INP, CLS, FCP, TTFB), the document-load span, resource timing and long tasks. |
Dependencies |
16 |
Browser fetch/XHR client spans. |
Sessions |
32 |
A session id that survives page reloads (kept in sessionStorage). Without it the session id lives in memory only. |
UserTracking |
64 |
The pseudonymous user id (enduser.pseudo.id, persisted on the device) and the authenticated user id (user.id). |
Logs |
128 |
.NET logs below Error, and browser console capture below error. |
Traces |
256 |
.NET Activity spans. |
Metrics |
512 |
.NET Meter metrics. |
Persistence |
1024 |
Keeping unsent telemetry on the device (browser storage or files) to retry it after going offline or restarting. |
Events |
2048 |
Custom events (TrackEvent). |
Diagnostics |
401 |
Errors, logs, traces and dependencies - what is needed to troubleshoot the app. |
Analytics |
2150 |
Page views, interactions, sessions, user tracking and custom events - what describes how the app is used. |
Monitoring |
520 |
Web vitals and metrics - how the app performs. |
All |
4095 |
Every feature. |
Browser records
Events are log records with an eventName, the way the OpenTelemetry Events API models them.
Spans use the OTLP span kinds (1 internal, 2 server, 3 client) and status codes (0 unset, 1 ok, 2 error),
and log severities use the OTLP SeverityNumber. Times are milliseconds since the Unix epoch,
from performance.timeOrigin + performance.now().
| Record | Shape | Scope | Feature |
|---|---|---|---|
| Page view | Log record, eventName = "browser.page_view". Attributes: url.full, url.path, page.title, page.referrer (redacted), browser.navigation.type (initial/push/replace/pop/hash/manual) |
bit.belemetry.page_views |
PageViews |
| Page visit time | Log record, eventName = "browser.page_visit_time", only with TrackPageVisitTime: emitted for the previous page when the next page view starts, and for the current page when it is hidden. Attributes: url.full, url.path, page.title, page.visit.duration (ms) |
bit.belemetry.page_views |
PageViews |
| Click | Log record, eventName = "browser.user_interaction". Attributes: event.type, target.element, target.id, target.name (data-bit-belemetry-name, aria-label, then name), target.text (only with captureText), target.xpath. Elements under [data-bit-belemetry-ignore] are skipped |
bit.belemetry.interactions |
Interactions |
| Web vital | Log record, eventName = "browser.web_vital". Attributes: web_vital.name (LCP/INP/CLS/FCP/TTFB), web_vital.value, web_vital.delta, web_vital.rating (good/needs-improvement/poor), web_vital.id, web_vital.navigation_type |
bit.belemetry.web_vitals |
Performance |
| Document load | Internal span documentLoad, with events domInteractive, domContentLoadedEventEnd, loadEventEnd, ... from PerformanceNavigationTiming |
bit.belemetry.document_load |
Performance |
| Resource timing | Internal span resourceFetch with url.full, http.response.body.size, network.protocol.name |
bit.belemetry.resources |
Performance |
| Long task | Internal span longtask |
bit.belemetry.long_tasks |
Performance |
| fetch/XHR | Client span {METHOD}. Attributes: http.request.method, url.full, server.address, server.port, http.response.status_code, error.type. Adds traceparent only for targets matched by propagateTraceContextTo |
bit.belemetry.http |
Dependencies |
| JS error | Log record, severity 17 (ERROR), eventName = "exception". Attributes: exception.type, exception.message, exception.stacktrace |
bit.belemetry.errors |
Errors |
| Console | Log record at the console call's level (with captureConsole, for the levels in consoleLevels) |
bit.belemetry.console |
Errors at error, Logs below |
| Custom event | Log record, eventName = the name passed to trackEvent, with its attributes |
bit.belemetry.events |
Events |
| Common (every record) | session.id. enduser.pseudo.id and user.id only with UserTracking |
.NET records
| Record | Shape |
|---|---|
ILogger entry |
Log record with the category as its scope, the severity mapped from the LogLevel, the
structured values as attributes, log.event.id and log.event.name (from
the EventId, when set), the values of active scopes (Logs.IncludeScopes),
log.record.template (with Logs.IncludeMessageTemplate), and the current
trace and span id
|
ILogger entry with an exception |
The same, plus exception.type, exception.message, exception.stacktrace - feature Errors |
Activity |
A span with the activity's kind, status, tags as attributes, events and links, scoped by its ActivitySource |
Meter instrument |
Counters and up-down counters as sums, histograms with explicit buckets, gauges as last values; past the cardinality limit, an otel.metric.overflow = true point |
TrackEvent / TrackPageView / TrackException |
The same records as their browser counterparts: an event log record, a browser.page_view log record, an exception log record |
Resource attributes
The resource describes the producer rather than the event, and travels once per batch. The first eight are common to both sides; the rest say which side the record came from.
| Attribute | Value | Side |
|---|---|---|
service.name | ServiceName, else OTEL_SERVICE_NAME, else the entry assembly name | both |
service.version | ServiceVersion, else the entry assembly's informational version | both |
service.namespace | ServiceNamespace | both |
service.instance.id | ServiceInstanceId; else, on a server, the platform's instance name (WEBSITE_INSTANCE_ID, CONTAINER_APP_REPLICA_NAME) or the machine name; else a random id per process, and always a random id per page load in the browser | both |
deployment.environment.name | Environment | both |
telemetry.sdk.name | bit-belemetry | both |
telemetry.sdk.language | dotnet / webjs | both |
telemetry.sdk.version | The package version | both |
process.runtime.name, .version, .description | .NET, the runtime version and framework description | .NET |
os.type, os.description, host.arch | The operating system and process architecture | .NET |
process.pid | The process id (not in WebAssembly) | .NET |
host.name, process.executable.name, process.owner | The machine name, the executable and the account the process runs as (server only - a device's are its owner's) | .NET |
container.id | From /proc/self/mountinfo or /proc/self/cgroup (server only, Linux) | .NET |
cloud.provider, cloud.platform, cloud.region, cloud.resource_id, host.id, azure.* | Azure App Service, Functions or Container Apps, from their environment variables (server only, with UseEnvironmentVariables) | .NET |
browser.language, browser.mobile, browser.platform, browser.brands | From navigator and User-Agent Client Hints, where available | browser |
user_agent.original | The user agent string (with Privacy.CollectUserAgent) | browser |
options.ResourceAttributes adds your own, and outside the browser OTEL_RESOURCE_ATTRIBUTES
is merged in first, so explicit options win.
Browser storage keys
Belemetry sets no cookies. These are the only keys it writes, and each one is gated by the feature it serves.
| Key | Storage | Gated by | Content |
|---|---|---|---|
bit-belemetry-consent | localStorage | always (strictly necessary: records the choice itself) | {"v":1,"features":<int>,"time":<ms>} |
bit-belemetry-session | sessionStorage | Sessions | {"id":"<32 hex>","start":<ms>,"last":<ms>} |
bit-belemetry-pseudo-id | localStorage | UserTracking | 32 hex chars |
bit-belemetry-user-id | sessionStorage | UserTracking | authenticated id from setUser |
bit-belemetry-queue | localStorage | Persistence | [{"id","exporter","url","contentType","body"(base64),"time"}], capped by persistence.maxBytes |
Revoking a feature clears its key: Persistence removes the queue, Sessions the stored
session, and UserTracking the pseudo id and the user id.
Browser configuration
<BelemetryScript /> writes this object into
<script type="application/json" id="bit-belemetry-config">, built from the server's
BelemetryOptions, and the module starts from it on load. <BelemetryInitializer />
passes the same object to start(config), which is idempotent. Without .NET, pass it to
BitBelemetry.start yourself - every field is optional.
{
"service": { "name": "MyApp", "version": "1.0.0", "namespace": null, "instanceId": null, "environment": "Production" },
"resource": { "any.attribute": "value" }, // extra resource attributes
"sdkVersion": "10.6.2",
"transport": "direct", // "direct" (JS exports itself) | "relay" (JS hands records to .NET)
"exporters": [
{ "type": "otlp", "endpoint": "http://localhost:4318", "tracesEndpoint": null, "logsEndpoint": null,
"protocol": "http/protobuf", "headers": { "x-api-key": "..." }, "compression": "none", "signals": 3 }, // protocol: http/protobuf | http/json ; compression: none | gzip
{ "type": "azureMonitor", "connectionString": "InstrumentationKey=...;IngestionEndpoint=https://...", "maskIp": true,
"compression": "none", "signals": 3 },
{ "type": "console" }
],
"features": 4095, // instrumentations switched on by configuration
"consent": { "default": 0, "persist": true, "honorGlobalPrivacyControl": true, "pendingLimit": 500 },
"pageViews": { "trackHashChanges": false },
"interactions": { "events": ["click"], "captureText": false, "maxTextLength": 64 },
"performance": { "webVitals": true, "documentLoad": true, "resources": false, "longTasks": false },
"dependencies": { "fetch": true, "xhr": true, "propagateTraceContextTo": ["same-origin"], "ignoreUrls": ["/_framework/", "/_blazor", "/_content/"] },
"errors": { "ignoreMessages": ["ResizeObserver loop"] },
"logs": { "captureConsole": false, "consoleLevels": ["error", "warn"] },
"privacy": { "redactQueryParameters": ["token","code","password","pwd","secret","key","apikey","api_key","auth","authorization","session","sid","sig","signature","email","access_token","id_token","refresh_token"],
"stripQueryString": false, "stripFragment": true, "scrubPatterns": true, "collectUserAgent": true, "blockedAttributes": [] },
"session": { "inactivityTimeoutMinutes": 30, "maxDurationMinutes": 1440 },
"sampling": { "sessionRatio": 1.0 },
"batch": { "maxQueueSize": 1024, "maxBatchSize": 100, "flushIntervalMs": 5000 },
"persistence": { "enabled": true, "maxBytes": 1048576, "maxAgeHours": 48, "retryIntervalMs": 60000 },
"debug": false
}
propagateTraceContextToentries are"same-origin","*", or a regex source matched against the absolute URL.ignoreUrlsandignoreMessagesare regex sources.
The constants
BelemetrySemanticConventions holds every attribute and event name above as a
const string, for processors and custom exporters that read or write them - so a typo is a
compile error rather than an attribute nobody queries.
BelemetrySemanticConventions
Static class
The OpenTelemetry semantic-convention attribute and event names Belemetry emits and understands.
| Name | Type and default | Description |
|---|---|---|
ServiceName |
string= "service.name" |
service.name |
ServiceVersion |
string= "service.version" |
service.version |
ServiceNamespace |
string= "service.namespace" |
service.namespace |
ServiceInstanceId |
string= "service.instance.id" |
service.instance.id |
DeploymentEnvironmentName |
string= "deployment.environment.name" |
deployment.environment.name |
TelemetrySdkName |
string= "telemetry.sdk.name" |
telemetry.sdk.name |
TelemetrySdkLanguage |
string= "telemetry.sdk.language" |
telemetry.sdk.language |
TelemetrySdkVersion |
string= "telemetry.sdk.version" |
telemetry.sdk.version |
OsType |
string= "os.type" |
os.type |
OsDescription |
string= "os.description" |
os.description |
HostArch |
string= "host.arch" |
host.arch |
ProcessRuntimeName |
string= "process.runtime.name" |
process.runtime.name |
ProcessRuntimeVersion |
string= "process.runtime.version" |
process.runtime.version |
ProcessRuntimeDescription |
string= "process.runtime.description" |
process.runtime.description |
ProcessPid |
string= "process.pid" |
process.pid |
ProcessExecutableName |
string= "process.executable.name" |
process.executable.name |
ProcessOwner |
string= "process.owner" |
process.owner |
HostName |
string= "host.name" |
host.name |
HostId |
string= "host.id" |
host.id |
ContainerId |
string= "container.id" |
container.id |
CloudProvider |
string= "cloud.provider" |
cloud.provider |
CloudPlatform |
string= "cloud.platform" |
cloud.platform |
CloudRegion |
string= "cloud.region" |
cloud.region |
CloudResourceId |
string= "cloud.resource_id" |
cloud.resource_id |
DeviceModelIdentifier |
string= "device.model.identifier" |
device.model.identifier |
SessionId |
string= "session.id" |
session.id |
EndUserPseudoId |
string= "enduser.pseudo.id" |
enduser.pseudo.id - a random identifier not linked to the user's real identity. |
UserId |
string= "user.id" |
user.id - the authenticated user's identifier. |
ExceptionType |
string= "exception.type" |
exception.type |
ExceptionMessage |
string= "exception.message" |
exception.message |
ExceptionStacktrace |
string= "exception.stacktrace" |
exception.stacktrace |
HttpRequestMethod |
string= "http.request.method" |
http.request.method |
HttpResponseStatusCode |
string= "http.response.status_code" |
http.response.status_code |
HttpRoute |
string= "http.route" |
http.route |
UrlFull |
string= "url.full" |
url.full |
UrlPath |
string= "url.path" |
url.path |
UrlQuery |
string= "url.query" |
url.query |
UrlScheme |
string= "url.scheme" |
url.scheme |
ServerAddress |
string= "server.address" |
server.address |
ServerPort |
string= "server.port" |
server.port |
ClientAddress |
string= "client.address" |
client.address |
ErrorType |
string= "error.type" |
error.type |
DbSystemName |
string= "db.system.name" |
db.system.name |
DbQueryText |
string= "db.query.text" |
db.query.text |
PageTitle |
string= "page.title" |
page.title |
PageVisitDuration |
string= "page.visit.duration" |
page.visit.duration - how long a page was visited, in milliseconds. |
BrowserLanguage |
string= "browser.language" |
browser.language |
WebVitalName |
string= "web_vital.name" |
web_vital.name |
WebVitalValue |
string= "web_vital.value" |
web_vital.value |
LogCategory |
string= "log.category" |
log.category - the ILogger category name. |
LogEventId |
string= "log.event.id" |
log.event.id - the EventId.Id of an ILogger entry. |
LogEventName |
string= "log.event.name" |
log.event.name - the EventId.Name of an ILogger entry. |
LogMessageTemplate |
string= "log.record.template" |
log.record.template - the message template of a structured ILogger entry. |
PageViewEvent |
string= "browser.page_view" |
The event name of a page view log record. |
PageVisitTimeEvent |
string= "browser.page_visit_time" |
The event name of a page visit time log record (how long the page view before it lasted). |
UserInteractionEvent |
string= "browser.user_interaction" |
The event name of an interaction log record. |
WebVitalEvent |
string= "browser.web_vital" |
The event name of a web vital log record. |
ExceptionEvent |
string= "exception" |
The event name of an exception log record. |
SdkName |
string= "bit-belemetry" |
The telemetry.sdk.name Belemetry reports. |