Attribute backend analytics events to the requesting client
What does this MR do and why?
GitLab Rails has not populated the client_type and client_name fields of the gitlab_standard Snowplow context. Chat events like execute_llm_method derived client identity from User-Agent regexes (IDE and glab only) or defaulted to web. Agent Platform events and background jobs had no client at all.
This MR makes Rails resolve and populate client identity consistently:
- New class
Gitlab::Tracking::ClientIdentityparsesX-Gitlab-Client-TypeandX-Gitlab-Client-Nameheaders, User-Agent, and defaults toapiwith no name. - Request middleware (
Gitlab::Middleware::RequestContext) resolves identity per request and wraps it inGitlab::ApplicationContext. - Labkit propagates context to Sidekiq jobs, so background workers inherit the triggering user's client.
- Frontend (axios and Apollo) send the client type header on same-origin requests; for
browserclients Rails derivesclient_namefrom the User-Agent browser family (chrome,firefox,safari,edge,opera,electron). - Tracking classes emit
client_typeandclient_nameinto the standard context and AI usage event extras. - Documentation: new page
doc/development/internal_analytics/internal_event_instrumentation/client_identity.md. - MCP and Slack integrations explicitly set
client_type: integration.
Client type values are browser, ide, cli, mobile, integration, system, and api. Unknown header values are dropped (client-controlled headers are not stored as free text).
Verification: 130 RSpec examples in tracking/context/chat, 82 in resolver/middleware/Slack/MCP specs, all green. ee/spec/lib/gitlab/tracking/ai_tracking_spec.rb could not run locally because it needs a ClickHouse configuration. 27 Jest examples green. RuboCop and linters clean.
References
Follows !256654 (merged), which added the request User-Agent to backend events.
Stacked follow-up: !257626 (merged) makes Workhorse forward the resolved identity on the agent actions it runs for websocket clients.
Client side: https://gitlab.com/mvanremmerden/gitlab-mobile/-/merge_requests/13 sends the headers from the mobile app.
How to set up and validate locally
- Send a request with
curl -H 'X-Gitlab-Client-Type: mobile' -H 'X-Gitlab-Client-Name: gitlab-mobile-ios' http://gdk.test:3000/api/v4/userwith a token and checklog/api_json.logformeta.client_type. - Run
Gitlab::Tracking::StandardContext.new.to_h.slice(:client_type, :client_name)in a Rails console (expect system/gitlab-rails). - With Snowplow Micro running, start a Duo Chat from the browser and inspect the
gitlab_standardcontext of theexecute_llm_methodevent forclient_type: browser.
Reviewer notes
- Needs an
~"analytics instrumentation"review; the label is applied. - Data team should be told that the
clientproperty gains new valuesapiandmobile, and that unknown User-Agents move fromwebtoapi. - Labelled
pipeline:run-as-if-fossbecause CE and EE both change. - No database migration.
- No feature flag, because the middleware only does string matching and the resolver is covered by a table-driven spec.
Follow-up
- #630922 tracks the client names and types the IDE plugins, the Duo CLI, and the language server send, the Web IDE naming collision, and who owns the allowlist.
MR acceptance checklist
Evaluated against the MR acceptance checklist.