From d647c8a0e7056a86f8bfa488c20fd7223104819f Mon Sep 17 00:00:00 2001 From: Jeremias Menichelli Date: Thu, 1 Oct 2026 16:00:51 -0300 Subject: [PATCH] chore: Add telemetry to search v2 user actions --- .../docs/features/SearchV2/SearchV2Dialog.tsx | 12 +++- .../features/SearchV2/SearchV2Trigger.tsx | 30 +++++++-- packages/common/telemetry-constants.ts | 66 +++++++++++++++++++ 3 files changed, 103 insertions(+), 5 deletions(-) diff --git a/apps/docs/features/SearchV2/SearchV2Dialog.tsx b/apps/docs/features/SearchV2/SearchV2Dialog.tsx index ee12c97675a..d475a107065 100644 --- a/apps/docs/features/SearchV2/SearchV2Dialog.tsx +++ b/apps/docs/features/SearchV2/SearchV2Dialog.tsx @@ -19,6 +19,7 @@ import { } from 'ui' import { formatHeadingPath, highlightMatches } from './SearchV2.utils' +import { useSendTelemetryEvent } from '@/lib/telemetry' interface SearchV2DialogProps { open: boolean @@ -27,6 +28,7 @@ interface SearchV2DialogProps { export function SearchV2Dialog({ open, onOpenChange }: SearchV2DialogProps) { const router = useRouter() + const sendTelemetryEvent = useSendTelemetryEvent() const { searchState, handleDocsSearchDebounced, resetSearch } = useDocsSearchV2() const [highlightQuery, setHighlightQuery] = useState('') @@ -40,10 +42,14 @@ export function SearchV2Dialog({ open, onOpenChange }: SearchV2DialogProps) { useEffect(() => { if (searchState.status === 'results' || searchState.status === 'noResults') { setHighlightQuery(searchState.query) + sendTelemetryEvent({ + action: 'docs_search_v2_search_submitted', + properties: { query: searchState.query }, + }) } else if (searchState.status === 'initial') { setHighlightQuery('') } - }, [searchState]) + }, [searchState, sendTelemetryEvent]) const results: DocsSearchV2Result[] = 'results' in searchState @@ -61,6 +67,10 @@ export function SearchV2Dialog({ open, onOpenChange }: SearchV2DialogProps) { } function handleSelect(path: string) { + sendTelemetryEvent({ + action: 'docs_search_v2_result_clicked', + properties: { resultPath: path, query: highlightQuery }, + }) router.push(path) onOpenChange(false) } diff --git a/apps/docs/features/SearchV2/SearchV2Trigger.tsx b/apps/docs/features/SearchV2/SearchV2Trigger.tsx index ae91f54d1f8..21d9c73cda2 100644 --- a/apps/docs/features/SearchV2/SearchV2Trigger.tsx +++ b/apps/docs/features/SearchV2/SearchV2Trigger.tsx @@ -1,10 +1,11 @@ 'use client' import { Search } from 'lucide-react' -import { useEffect, useState, type ReactNode } from 'react' +import { useCallback, useEffect, useState, type ReactNode } from 'react' import { cn, KeyboardShortcut } from 'ui' import { SearchV2Dialog } from './SearchV2Dialog' +import { useSendTelemetryEvent } from '@/lib/telemetry' interface SearchV2TriggerProps { className?: string @@ -13,6 +14,17 @@ interface SearchV2TriggerProps { export function SearchV2Trigger({ className, placeholder = 'Search...' }: SearchV2TriggerProps) { const [open, setOpen] = useState(false) + const sendTelemetryEvent = useSendTelemetryEvent() + + const handleOpenChange = useCallback( + (next: boolean) => { + setOpen(next) + if (!next) { + sendTelemetryEvent({ action: 'docs_search_v2_closed' }) + } + }, + [sendTelemetryEvent] + ) useEffect(() => { function openOnKeyDown(event: globalThis.KeyboardEvent) { @@ -25,6 +37,10 @@ export function SearchV2Trigger({ className, placeholder = 'Search...' }: Search event.preventDefault() setOpen(true) + sendTelemetryEvent({ + action: 'docs_search_v2_opened', + properties: { triggerType: 'keyboard_shortcut' }, + }) } } @@ -33,7 +49,7 @@ export function SearchV2Trigger({ className, placeholder = 'Search...' }: Search return () => { window.removeEventListener('keydown', openOnKeyDown, { capture: true }) } - }, []) + }, [sendTelemetryEvent]) return ( <> @@ -42,7 +58,13 @@ export function SearchV2Trigger({ className, placeholder = 'Search...' }: Search tabIndex={0} aria-haspopup="dialog" aria-expanded={open} - onClick={() => setOpen(true)} + onClick={() => { + setOpen(true) + sendTelemetryEvent({ + action: 'docs_search_v2_opened', + properties: { triggerType: 'search_input' }, + }) + }} className={cn( 'group cursor-pointer', 'grow md:min-w-44 xl:min-w-56 h-[30px] rounded-md', @@ -69,7 +91,7 @@ export function SearchV2Trigger({ className, placeholder = 'Search...' }: Search className="hidden md:inline-flex border border-default bg-surface-300 text-foreground-lighter shadow-xs shadow-background-surface-100" /> - + ) } diff --git a/packages/common/telemetry-constants.ts b/packages/common/telemetry-constants.ts index bf8bed7b580..b784a553876 100644 --- a/packages/common/telemetry-constants.ts +++ b/packages/common/telemetry-constants.ts @@ -1075,6 +1075,68 @@ export interface DocsContentListingClickedEvent { } } +/** + * User opened the Search V2 dialog. + * + * @group Events + * @source docs + */ +export interface DocsSearchV2OpenedEvent { + action: 'docs_search_v2_opened' + properties: { + /** + * The trigger that opened the Search V2 dialog. + */ + triggerType: 'keyboard_shortcut' | 'search_input' + } +} + +/** + * User's search term was sent to the Search V2 endpoint. + * + * @group Events + * @source docs + */ +export interface DocsSearchV2SearchSubmittedEvent { + action: 'docs_search_v2_search_submitted' + properties: { + /** + * The search term sent to the Search V2 endpoint. + */ + query: string + } +} + +/** + * User activated a Search V2 result, either by clicking it or selecting it via keyboard. + * + * @group Events + * @source docs + */ +export interface DocsSearchV2ResultClickedEvent { + action: 'docs_search_v2_result_clicked' + properties: { + /** + * The path of the result that was activated. + */ + resultPath: string + /** + * The search term whose results were showing when the result was activated. + */ + query: string + } +} + +/** + * User closed the Search V2 dialog. + * + * @group Events + * @source docs + */ +export interface DocsSearchV2ClosedEvent { + action: 'docs_search_v2_closed' +} + /** * User clicked a recommended page card shown on a docs "not found" page. * @@ -4120,6 +4182,10 @@ export type TelemetryEvent = | AskAiClickedEvent | DocsAiPromptCopiedEvent | DocsContentListingClickedEvent + | DocsSearchV2OpenedEvent + | DocsSearchV2SearchSubmittedEvent + | DocsSearchV2ResultClickedEvent + | DocsSearchV2ClosedEvent | Docs404RecommendationClickedEvent | DocsProjectConfigVariablesCopyButtonClickedEvent | HomepageFrameworkQuickstartClickedEvent