Client identity in backend events
Client identity describes what kind of application sent a request: a browser, an IDE, a CLI, a mobile app, or a script.
GitLab Rails resolves it for every request from the HTTP headers X-Gitlab-Client-Type and X-Gitlab-Client-Name, which IDE extensions, the Duo CLI, the AI Gateway, and the Duo Workflow Service already use, and records the client’s release from X-Gitlab-Client-Version beside it.
Rails checks the declared values against an allowlist and drops anything it does not recognize, instead of storing arbitrary client-supplied text.
The allowlist lives in Gitlab::Tracking::ClientIdentity.
Client type values
| Type | Meaning |
|---|---|
browser | Web browser, including the Web IDE |
ide | Code editor or IDE extension |
cli | Command-line tool |
mobile | Mobile app |
integration | Request made through an integration, such as the MCP server or Slack |
system | GitLab itself: cron jobs, runners, Git over HTTP, Workhorse |
api | Unidentified API caller, such as a script |
Client name slugs
| Client names | Type |
|---|---|
chrome, firefox, safari, edge, opera, electron | browser |
vscode, jetbrains, jetbrains-bundled, visual-studio, neovim, zed, kiro | ide |
duo-cli, glab | cli |
gitlab-mobile-ios, gitlab-mobile-android | mobile |
slack, mcp | integration |
gitlab-rails | system |
For browser, Rails accepts the X-Gitlab-Client-Name header when it carries chrome, firefox, safari, edge, opera, or electron.
Workhorse sends it when it runs an agent’s HTTP actions for a browser session, forwarding the family Rails resolved when the websocket was opened.
Otherwise, Rails reads the family from the User-Agent.
The web frontend sends only the X-Gitlab-Client-Type header.
Other browsers keep the browser type with no name.
Client version
X-Gitlab-Client-Version carries the client’s own release, such as 6.21.0 for an IDE extension or 1.2.0 for the mobile app.
A release cannot be allowlisted by value, so Rails keeps it only when it is shaped like a version: an optional v, a leading digit, then up to 62 more digits, letters, ., -, +, or _ characters, which fits the client_version field of the gitlab_standard schema.
Anything else is dropped, and the version is kept only for a client that declared its type or name in the headers.
Resolution precedence
- The
X-Gitlab-Client-Typeheader, normalized through an alias table.webandweb_browsermeanbrowser, andduo_climeanscli. - The
X-Gitlab-Client-Nameheader, which also determines the type when no valid type header is present. Product names such asVisual Studio Code,IntelliJ IDEA, andDuo CLImap to slugs. A name that belongs to a different type than the declared one is dropped. - The User-Agent: the existing IDE and glab patterns;
gitlab-runner,git/,GitLab-Shell,gitlab-workhorse, andAgent-Flow-via-GitLab-Workhorsemeansystem; aMozilla/User-Agent meansbrowser. - Otherwise
apiwith no name.
A browser identity without an allowlisted name takes its name from the User-Agent browser family.
Propagation to background jobs
The request middleware stores the identity on Gitlab::ApplicationContext.
Labkit copies that context into every Sidekiq job the request enqueues and restores it in the worker.
A session created by a background job because a user assigned Duo as a reviewer or mentioned Duo in a note therefore inherits that user’s client.
Jobs with no request lineage, such as cron jobs, resolve to system.
Where the value appears
- The
client_type,client_name, andclient_versionfields of thegitlab_standardSnowplow context.client_typeandclient_nameare theCLIENT_TYPEandCLIENT_NAMEcolumns ofPROD.COMMON.FCT_BEHAVIOR_STRUCTURED_EVENTin Snowflake. - The
clientproperty on theexecute_llm_methodandperform_completion_workerDuo Chat events. Clients with a historical value keep it (web,web_ide,vscode,jetbrains,jetbrains_bundled,visual_studio,neovim,gitlab_cli), the Duo CLI reportsduo_cli, and every other client reports its client type, addingmobile,ide,cli,integration,system, andapi. - The
extrasof AI usage events, when a request lineage exists. - The
meta.client_type,meta.client_name, andmeta.client_versionfields of Rails and Sidekiq structured logs.
Adding a client
- Add the slug and its type to the allowlist in
Gitlab::Tracking::ClientIdentity, and add the slug to the table on this page. - Send
X-Gitlab-Client-Nameon every request, including websocket upgrades, not only AI calls. An allowlisted name is enough to resolve the type, soX-Gitlab-Client-Typeis optional. SendX-Gitlab-Client-Versionwith the client’s release too, so analytics can tell the builds apart. Background work triggered by the request can only inherit what the request carried.