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