Analytics Instrumentation
Add analytics events to Sentry's frontend UI using established patterns.
Answering "How Many People Do X?"
When the user asks about usage, adoption, or interaction counts for a feature:
- Find the event: search Amplitude first (fastest), fall back to grepping the codebase.
- If the Amplitude MCP is connected, query the data directly and report results.
- If no matching event exists, tell the user the event is not tracked — then use
AskUserQuestionto ask whether they want to instrument it. Do not proceed to instrumentation without explicit confirmation.
Read references/amplitude-mcp.md for the full discovery and querying workflow.
Before Any Change: Search First
NEVER create a new event without checking if one already exists.
- Search
static/app/utils/analytics/for events matching the feature domain. - Grep for keywords related to the interaction (e.g.,
clicked,viewed,created). - If a matching event exists, reuse it — add parameters if needed rather than creating a duplicate.
grep -rn "keyword" static/app/utils/analytics/ --include="*.tsx"
Event Naming Rules
| Rule | Example |
|---|---|
Use snake_case with dots as separators |
feedback.list-item-selected |
| First segment = feature domain | dashboards2., issue_details., feedback. |
| Middle segments = section/context (optional) | dashboards2.edit. |
| Last segment = action | .clicked, .viewed, .created, .changed |
| Match the existing domain file's prefix | If events are in feedbackAnalyticsEvents.tsx, use feedback. prefix |
Standard action suffixes:
| User action | Suffix |
|---|---|
| Clicks a button/link | .clicked or _clicked |
| Views a page | .viewed |
| Submits a form | .submitted or .created |
| Changes a setting | .changed |
| Renders/loads content | .rendered or .loaded |
| Dismisses UI | .dismissed |
| Opens a modal/panel | .opened |
Choose the Right Tracking Pattern
| What to track | Pattern | Open reference |
|---|---|---|
| Page view on route navigation | Route analytics hooks | references/tracking-patterns.md § Route-Level |
| Button or link click | Button analyticsEventKey prop |
references/tracking-patterns.md § Button |
| Custom interaction (toggle, drag, select) | trackAnalytics() call |
references/tracking-patterns.md § Manual |
| Modal or panel open/close | trackAnalytics() in handler |
references/tracking-patterns.md § Manual |
| UI area context for events | AnalyticsArea wrapper |
references/tracking-patterns.md § Area Context |
When You Need to Define a New Event
Read references/event-definitions.md for step-by-step instructions.
Common Mistakes and Debugging
Read references/troubleshooting.md when:
- An event isn't firing or appearing in Amplitude
- You see TypeScript errors when calling
trackAnalytics - You need to debug analytics locally
- You're unsure whether an event needs an Amplitude name
Key Files
| File | Purpose |
|---|---|
static/app/utils/analytics.tsx |
Master registry — all event maps merged, trackAnalytics export |
static/app/utils/analytics/{domain}AnalyticsEvents.tsx |
Domain-specific event type definitions and name maps |
static/app/utils/analytics/makeAnalyticsFunction.tsx |
Factory that creates typed trackAnalytics — do not call directly |
static/app/utils/routeAnalytics/useRouteAnalyticsEventNames.tsx |
Hook for route-level page view event names |
static/app/utils/routeAnalytics/useRouteAnalyticsParams.tsx |
Hook for route-level page view parameters |
static/app/components/analyticsArea.tsx |
AnalyticsArea component and useAnalyticsArea hook |
static/app/components/core/button/types.tsx |
Button analytics props (analyticsEventKey, analyticsEventName, analyticsParams) |
Interaction Rules
Users of this skill may be less technical. Use AskUserQuestion at every decision point instead of dumping plans or code.
| Situation | Action |
|---|---|
| Event not found, user asked a data question | Use AskUserQuestion: "This isn't tracked yet. Want me to add instrumentation?" |
| User confirms they want instrumentation | Go straight to implementation. Do not show code previews or step-by-step plans — just make the changes and summarize what you did. |
| Implementation is done, needs user action (e.g., Reload registration) | State the remaining step clearly in your summary. |
Never dump code blocks as a "plan" and then ask "Want me to make these changes?" — either present a short plain-English summary via AskUserQuestion for confirmation, or proceed directly if the user already asked for instrumentation.
Event Pipeline
Every trackAnalytics call flows through the GetSentry override in static/gsApp/utils/rawTrackAnalyticsEvent.tsx:
| Destination | When it fires | What it uses | How to query |
|---|---|---|---|
| Reload | Always | eventKey |
Redash |
| Amplitude | When eventName is non-null and org exists |
eventName |
Amplitude UI or MCP |
| Pendo | Same as Amplitude | eventName |
Pendo |
- Set
eventNameto a string (e.g.,'Logs Trace Link Clicked') to send to both Reload and Amplitude. This is the default for almost all events. - Set
eventNametonullonly for high-volume events that would be too expensive for Amplitude. These are Reload-only and queryable via Redash. - Reload accepts events with
allow_no_schema: true— no separate registration step is needed. - When searching for events, note that Reload-only events (
nullname) will not appear in Amplitude search. Fall back to grepping the codebase if Amplitude returns no results.
Non-Negotiable Constraints
- All events must be type-safe. Every event key must exist in a
*EventParameterstype and be registered in the domain's event map. - All events flow through
trackAnalytics(). Never callwindow.analytics,Amplitude.track(), or any other analytics SDK directly. - Organization context is automatic. Pass
organizationtotrackAnalytics— the override system handles the rest. - Reuse over create. Always search for existing events before defining new ones.
- One event per interaction. Do not fire multiple events for the same user action.
- No PII in event parameters. Never include user emails, IP addresses, full names, or other personally identifiable information. Use opaque IDs (org ID, user ID) when identity context is needed.