From c9582230d6671cd47500ff23eaf19ab768e419fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aatu=20V=C3=A4is=C3=A4nen?= Date: Fri, 24 Oct 2025 15:14:27 +0300 Subject: [PATCH 1/9] Add tracking events --- src/hooks/useInkeepSearch.ts | 104 ++++++++++++++---------- src/theme/DocRoot/Layout/Main/index.tsx | 97 ++++++++++++++++++++-- 2 files changed, 153 insertions(+), 48 deletions(-) diff --git a/src/hooks/useInkeepSearch.ts b/src/hooks/useInkeepSearch.ts index f7667ce8..1e57d421 100644 --- a/src/hooks/useInkeepSearch.ts +++ b/src/hooks/useInkeepSearch.ts @@ -1,5 +1,5 @@ -import { useState, useRef, useCallback, useEffect } from 'react'; -import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; +import { useState, useRef, useCallback, useEffect } from "react"; +import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; import type { InkeepAIChatSettings, InkeepSearchSettings, @@ -7,7 +7,9 @@ import type { InkeepBaseSettings, AIChatFunctions, SearchFunctions, -} from '@inkeep/cxkit-react'; + InkeepCallbackEvent, +} from "@inkeep/cxkit-react"; +import { trackEvent } from "../utils/analytics"; interface UseInkeepSearchOptions { version?: string; @@ -18,15 +20,15 @@ interface UseInkeepSearchOptions { } export function useInkeepSearch(options: UseInkeepSearchOptions = {}) { - const { - version, - enableKeyboardShortcut = false, - keyboardShortcut = 'k', + const { + version, + enableKeyboardShortcut = false, + keyboardShortcut = "k", enableAIChat = false, autoOpenOnInput = false, } = options; - - const [message, setMessage] = useState(''); + + const [message, setMessage] = useState(""); const [isOpen, setIsOpen] = useState(false); const [ModalSearchAndChat, setModalSearchAndChat] = useState(null); @@ -39,7 +41,7 @@ export function useInkeepSearch(options: UseInkeepSearchOptions = {}) { // Load the modal component dynamically useEffect(() => { (async () => { - const { InkeepModalSearchAndChat } = await import('@inkeep/cxkit-react'); + const { InkeepModalSearchAndChat } = await import("@inkeep/cxkit-react"); setModalSearchAndChat(() => InkeepModalSearchAndChat); })(); }, []); @@ -55,61 +57,78 @@ export function useInkeepSearch(options: UseInkeepSearchOptions = {}) { } }; - document.addEventListener('keydown', handleKeyDown); - return () => document.removeEventListener('keydown', handleKeyDown); + document.addEventListener("keydown", handleKeyDown); + return () => document.removeEventListener("keydown", handleKeyDown); }, [enableKeyboardShortcut, keyboardShortcut]); const inkeepBaseSettings: InkeepBaseSettings = { - apiKey: inkeepConfig.apiKey || '', - organizationDisplayName: 'Teleport', - primaryBrandColor: '#512FC9', - aiApiBaseUrl: 'https://goteleport.com/inkeep-proxy', - analyticsApiBaseUrl: 'https://goteleport.com/inkeep-proxy/analytics', + apiKey: inkeepConfig.apiKey || "", + organizationDisplayName: "Teleport", + primaryBrandColor: "#512FC9", + aiApiBaseUrl: "https://goteleport.com/inkeep-proxy", + analyticsApiBaseUrl: "https://goteleport.com/inkeep-proxy/analytics", privacyPreferences: { optOutAllAnalytics: false, }, transformSource: (source) => { const isDocs = - source.contentType === 'docs' || - source.type === 'documentation'; + source.contentType === "docs" || source.type === "documentation"; if (!isDocs) { return source; } return { ...source, - tabs: ['Docs', ...(source.tabs ?? [])], - icon: { builtIn: 'IoDocumentTextOutline' }, + tabs: ["Docs", ...(source.tabs ?? [])], + icon: { builtIn: "IoDocumentTextOutline" }, }; }, colorMode: { - forcedColorMode: 'light', + forcedColorMode: "light", }, theme: { zIndex: { - overlay: '2100', - modal: '2200', - popover: '2300', - skipLink: '2400', - toast: '2500', - tooltip: '2600', + overlay: "2100", + modal: "2200", + popover: "2300", + skipLink: "2400", + toast: "2500", + tooltip: "2600", }, }, + // reference: https://docs.inkeep.com/cloud/ui-components/customization-guides/use-your-own-analytics + onEvent: (event: InkeepCallbackEvent) => { + const { eventName, properties } = event; + + const eventsToTrack = [ + "user_message_submitted", + "search_query_submitted", + ]; + + if (!eventsToTrack.includes(eventName)) { + return; + } + + trackEvent({ + event_name: `inkeep_${eventName}`, + custom_parameters: properties, + }); + }, }; const inkeepSearchSettings: InkeepSearchSettings = { - placeholder: 'Search Docs', + placeholder: "Search Docs", tabs: [ - ['Docs', { isAlwaysVisible: true }], - ['GitHub', { isAlwaysVisible: true }], + ["Docs", { isAlwaysVisible: true }], + ["GitHub", { isAlwaysVisible: true }], ], shouldOpenLinksInNewTab: true, - view: 'dual-pane', + view: "dual-pane", }; const inkeepAIChatSettings: InkeepAIChatSettings | undefined = enableAIChat ? { - aiAssistantName: 'Teleport', - aiAssistantAvatar: 'https://goteleport.com/static/pam-standing.svg', + aiAssistantName: "Teleport", + aiAssistantAvatar: "https://goteleport.com/static/pam-standing.svg", } : undefined; @@ -152,13 +171,14 @@ export function useInkeepSearch(options: UseInkeepSearchOptions = {}) { }, searchSettings: dynamicSearchSettings, modalSettings: modalSettings, - ...(enableAIChat && inkeepAIChatSettings && { - aiChatSettings: { - ...inkeepAIChatSettings, - chatFunctionsRef: chatCallableFunctionsRef, - onInputMessageChange: handleChange, - }, - }), + ...(enableAIChat && + inkeepAIChatSettings && { + aiChatSettings: { + ...inkeepAIChatSettings, + chatFunctionsRef: chatCallableFunctionsRef, + onInputMessageChange: handleChange, + }, + }), }; return { @@ -170,4 +190,4 @@ export function useInkeepSearch(options: UseInkeepSearchOptions = {}) { inkeepModalProps, handleChange, }; -} \ No newline at end of file +} diff --git a/src/theme/DocRoot/Layout/Main/index.tsx b/src/theme/DocRoot/Layout/Main/index.tsx index 10f54e35..03cbe9a5 100644 --- a/src/theme/DocRoot/Layout/Main/index.tsx +++ b/src/theme/DocRoot/Layout/Main/index.tsx @@ -1,15 +1,100 @@ -// Manually swizzled to allow theming +// Manually swizzled to allow theming // See https://docusaurus.io/docs/swizzling // This is wrapped, not ejected -import React, {type ReactNode} from 'react'; -import Main from '@theme-original/DocRoot/Layout/Main'; -import type MainType from '@theme/DocRoot/Layout/Main'; -import type {WrapperProps} from '@docusaurus/types'; -import './styles.module.css'; +import React, { useEffect, type ReactNode } from "react"; +import Main from "@theme-original/DocRoot/Layout/Main"; +import type MainType from "@theme/DocRoot/Layout/Main"; +import type { WrapperProps } from "@docusaurus/types"; +import "./styles.module.css"; +import { trackEvent } from "@site/src/utils/analytics"; type Props = WrapperProps; export default function MainWrapper(props: Props): ReactNode { + useEffect(() => { + const inkeepLinkTracker = (clickEvent: MouseEvent) => { + clickEvent.stopPropagation(); + + const path = clickEvent.composedPath(); + + if (!path) return; + + const link = path.find((el) => el instanceof HTMLAnchorElement) as + | HTMLAnchorElement + | undefined; + + const inkeepSearch = path.find( + (el) => + el instanceof HTMLElement && + el.classList?.contains("ikp-ai-search-content") + ) as HTMLElement | undefined; + + const inkeepChat = path.find( + (el) => + el instanceof HTMLElement && + el.classList?.contains("ikp-ai-chat-content") + ) as HTMLElement | undefined; + + const navbar = path.find( + (el) => + el instanceof HTMLElement && + el.classList?.contains("theme-layout-navbar") + ) as HTMLElement | undefined; + + const sidebar = path.find( + (el) => + el instanceof HTMLElement && + el.classList?.contains("theme-doc-sidebar-menu") + ) as HTMLElement | undefined; + + const mainContent = path.find( + (el) => + el instanceof HTMLElement && + el.classList?.contains("theme-doc-markdown") + ) as HTMLElement | undefined; + + const breadcumbs = path.find( + (el) => + el instanceof HTMLElement && + el.classList?.contains("theme-doc-breadcrumbs") + ) as HTMLElement | undefined; + + if (link && (inkeepSearch || inkeepChat)) { + trackEvent({ + event_name: "inkeep_link_click", + }); + } + + if (link && navbar) { + trackEvent({ + event_name: "navbar_link_click", + }); + } + + if (link && sidebar) { + trackEvent({ + event_name: "sidebar_link_click", + }); + } + + if (link && mainContent) { + trackEvent({ + event_name: "active_page_link_click", + }); + } + + if (link && breadcumbs) { + trackEvent({ + event_name: "breadcrumbs_link_click", + }); + } + }; + + window.addEventListener("click", inkeepLinkTracker); + + return () => window.removeEventListener("click", inkeepLinkTracker); + }, []); + return ( <>
From b698b641476e3dbcd18e0dc54502db341f0669f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aatu=20V=C3=A4is=C3=A4nen?= Date: Wed, 29 Oct 2025 13:30:11 +0200 Subject: [PATCH 2/9] Add more tracked events --- src/hooks/useInkeepSearch.ts | 138 +++++++++++++++++++++++- src/theme/DocRoot/Layout/Main/index.tsx | 18 ---- utils/general.ts | 16 ++- 3 files changed, 148 insertions(+), 24 deletions(-) diff --git a/src/hooks/useInkeepSearch.ts b/src/hooks/useInkeepSearch.ts index 1e57d421..3c43b7bd 100644 --- a/src/hooks/useInkeepSearch.ts +++ b/src/hooks/useInkeepSearch.ts @@ -8,8 +8,10 @@ import type { AIChatFunctions, SearchFunctions, InkeepCallbackEvent, + ConversationMessage, } from "@inkeep/cxkit-react"; import { trackEvent } from "../utils/analytics"; +import { debounce } from "@site/utils/general"; interface UseInkeepSearchOptions { version?: string; @@ -19,6 +21,13 @@ interface UseInkeepSearchOptions { autoOpenOnInput?: boolean; // Auto-open modal when typing } +const debouncedTrackEvent = debounce((eventName: string, properties: any) => { + trackEvent({ + event_name: eventName, + custom_parameters: properties, + }); +}, 1000); + export function useInkeepSearch(options: UseInkeepSearchOptions = {}) { const { version, @@ -102,16 +111,137 @@ export function useInkeepSearch(options: UseInkeepSearchOptions = {}) { const eventsToTrack = [ "user_message_submitted", "search_query_submitted", + "search_result_clicked", + "assistant_source_item_clicked", + "assistant_negative_feedback_submitted", + "assistant_positive_feedback_submitted", + "assistant_message_inline_link_opened", + "assistant_message_copied", + "assistant_code_block_copied", ]; if (!eventsToTrack.includes(eventName)) { return; } - trackEvent({ - event_name: `inkeep_${eventName}`, - custom_parameters: properties, - }); + const getLatestMessage = ( + messages: ConversationMessage[], + role: "assistant" | "system" | "user" + ) => { + return ( + messages.filter((msg) => msg.role === role).slice(-1)[0]?.content || + "" + ); + }; + + try { + switch (eventName) { + case "search_query_submitted": { + // For search queries, we debounce to avoid spamming analytics + debouncedTrackEvent("search", { + search_term: properties.searchQuery, + }); + break; + } + case "user_message_submitted": { + // Also debounce Ask AI chat message input + debouncedTrackEvent(`inkeep_${eventName}`, { + latest_message: getLatestMessage( + properties.conversation.messages, + "user" + ), + }); + break; + } + case "search_result_clicked": { + trackEvent({ + event_name: `inkeep_${eventName}`, + custom_parameters: { + search_term: properties.searchQuery, + title: properties.title, + url: properties.url, + }, + }); + break; + } + case "assistant_source_item_clicked": { + trackEvent({ + event_name: `inkeep_${eventName}`, + custom_parameters: { + latest_message: getLatestMessage( + properties.conversation.messages, + "user" + ), + title: properties.link.title, + url: properties.link.url, + }, + }); + break; + } + case "assistant_positive_feedback_submitted": + case "assistant_negative_feedback_submitted": { + trackEvent({ + event_name: `inkeep_${eventName}`, + custom_parameters: { + latest_message: getLatestMessage( + properties.conversation.messages, + "assistant" + ), + feedback_reason_labels: + properties?.reasons?.map((r) => r.label).join(", ") || "", + feedback_reason_details: + properties?.reasons?.map((r) => r.details).join(", ") || "", + }, + }); + break; + } + case "assistant_message_inline_link_opened": { + trackEvent({ + event_name: `inkeep_${eventName}`, + custom_parameters: { + title: properties.title || "", + url: properties.url || "", + }, + }); + break; + } + case "assistant_message_copied": { + trackEvent({ + event_name: `inkeep_${eventName}`, + custom_parameters: { + latest_message: getLatestMessage( + properties.conversation.messages, + "assistant" + ), + }, + }); + break; + } + case "assistant_code_block_copied": { + trackEvent({ + event_name: `inkeep_${eventName}`, + custom_parameters: { + latest_message: getLatestMessage( + properties.conversation.messages, + "assistant" + ), + code_language: properties.language || "", + code_value: properties.code || "", + }, + }); + break; + } + default: { + trackEvent({ + event_name: `inkeep_${eventName}`, + custom_parameters: properties, + }); + break; + } + } + } catch (error) { + console.error("Error processing Inkeep event:", error); + } }, }; diff --git a/src/theme/DocRoot/Layout/Main/index.tsx b/src/theme/DocRoot/Layout/Main/index.tsx index 03cbe9a5..3f2a65a8 100644 --- a/src/theme/DocRoot/Layout/Main/index.tsx +++ b/src/theme/DocRoot/Layout/Main/index.tsx @@ -23,18 +23,6 @@ export default function MainWrapper(props: Props): ReactNode { | HTMLAnchorElement | undefined; - const inkeepSearch = path.find( - (el) => - el instanceof HTMLElement && - el.classList?.contains("ikp-ai-search-content") - ) as HTMLElement | undefined; - - const inkeepChat = path.find( - (el) => - el instanceof HTMLElement && - el.classList?.contains("ikp-ai-chat-content") - ) as HTMLElement | undefined; - const navbar = path.find( (el) => el instanceof HTMLElement && @@ -59,12 +47,6 @@ export default function MainWrapper(props: Props): ReactNode { el.classList?.contains("theme-doc-breadcrumbs") ) as HTMLElement | undefined; - if (link && (inkeepSearch || inkeepChat)) { - trackEvent({ - event_name: "inkeep_link_click", - }); - } - if (link && navbar) { trackEvent({ event_name: "navbar_link_click", diff --git a/utils/general.ts b/utils/general.ts index b2ce2b00..a92cd06c 100644 --- a/utils/general.ts +++ b/utils/general.ts @@ -9,10 +9,10 @@ */ export const toCopyContent = ( commandNode: HTMLElement, - commandLineClasses: string[], + commandLineClasses: string[] ): string => { const lines = Array.from( - commandNode.querySelectorAll(commandLineClasses.join(",")), + commandNode.querySelectorAll(commandLineClasses.join(",")) ).reduce((allLines, commandLine) => { allLines.push(commandLine.textContent); return allLines; @@ -59,3 +59,15 @@ export const getFromSecretOrEnv = (name: string): string => { : process.env; return configVars[name]; }; + +/* Debounce function to limit the rate of function calls */ +export const debounce = ( + func: (...args: any[] | undefined) => void, + wait: number +) => { + let timeout: NodeJS.Timeout; + return (...args: any[]) => { + clearTimeout(timeout); + timeout = setTimeout(() => func(...args), wait); + }; +}; From c6ec8fb4a239dfcbffe3dd198116713d209c58d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aatu=20V=C3=A4is=C3=A4nen?= Date: Wed, 29 Oct 2025 14:00:48 +0200 Subject: [PATCH 3/9] Pass link url as an event parameter --- src/theme/DocRoot/Layout/Main/index.tsx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/theme/DocRoot/Layout/Main/index.tsx b/src/theme/DocRoot/Layout/Main/index.tsx index 3f2a65a8..5be529aa 100644 --- a/src/theme/DocRoot/Layout/Main/index.tsx +++ b/src/theme/DocRoot/Layout/Main/index.tsx @@ -50,24 +50,36 @@ export default function MainWrapper(props: Props): ReactNode { if (link && navbar) { trackEvent({ event_name: "navbar_link_click", + custom_parameters: { + url: link.href, + }, }); } if (link && sidebar) { trackEvent({ event_name: "sidebar_link_click", + custom_parameters: { + url: link.href, + }, }); } if (link && mainContent) { trackEvent({ event_name: "active_page_link_click", + custom_parameters: { + url: link.href, + }, }); } if (link && breadcumbs) { trackEvent({ event_name: "breadcrumbs_link_click", + custom_parameters: { + url: link.href, + }, }); } }; From 13e6f21a6e221ca286b85498d7c6756aed7ab9dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aatu=20V=C3=A4is=C3=A4nen?= Date: Thu, 30 Oct 2025 11:04:49 +0200 Subject: [PATCH 4/9] Clean up useInkeepSearch, make sure search isn't triggered when chat is used --- .../Homepage/DocsHeader/InlineSearch.tsx | 4 -- src/components/Search/InkeepSearch.tsx | 5 -- src/hooks/useInkeepSearch.ts | 67 +++++++++++-------- 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/src/components/Pages/Homepage/DocsHeader/InlineSearch.tsx b/src/components/Pages/Homepage/DocsHeader/InlineSearch.tsx index 8f183c78..18875b83 100644 --- a/src/components/Pages/Homepage/DocsHeader/InlineSearch.tsx +++ b/src/components/Pages/Homepage/DocsHeader/InlineSearch.tsx @@ -12,8 +12,6 @@ type InlineSearchProps = { export function InlineSearch({ className = "", version }: InlineSearchProps) { const { - message, - setMessage, isOpen, setIsOpen, ModalSearchAndChat, @@ -46,8 +44,6 @@ export function InlineSearch({ className = "", version }: InlineSearchProps) { className={styles.searchInput} onClick={() => setIsOpen(true)} onFocus={() => setIsOpen(true)} - value={message} - onChange={(e) => setMessage(e.target.value)} readOnly /> {ModalSearchAndChat && ( diff --git a/src/components/Search/InkeepSearch.tsx b/src/components/Search/InkeepSearch.tsx index 5cc6ee6b..a9fe942e 100644 --- a/src/components/Search/InkeepSearch.tsx +++ b/src/components/Search/InkeepSearch.tsx @@ -6,13 +6,10 @@ import InkeepSearchIconSvg from "./inkeepIcon.svg"; export function InkeepSearch() { const { - message, - setMessage, isOpen, setIsOpen, ModalSearchAndChat, inkeepModalProps, - handleChange, } = useInkeepSearch({ enableAIChat: true, autoOpenOnInput: true, @@ -25,10 +22,8 @@ export function InkeepSearch() { handleChange(e.target.value)} onClick={() => setIsOpen(true)} placeholder="Search Docs" - value={message} /> }> diff --git a/src/hooks/useInkeepSearch.ts b/src/hooks/useInkeepSearch.ts index 3c43b7bd..7bb524ce 100644 --- a/src/hooks/useInkeepSearch.ts +++ b/src/hooks/useInkeepSearch.ts @@ -110,7 +110,7 @@ export function useInkeepSearch(options: UseInkeepSearchOptions = {}) { const eventsToTrack = [ "user_message_submitted", - "search_query_submitted", + "search_query_response_received", "search_result_clicked", "assistant_source_item_clicked", "assistant_negative_feedback_submitted", @@ -136,20 +136,27 @@ export function useInkeepSearch(options: UseInkeepSearchOptions = {}) { try { switch (eventName) { - case "search_query_submitted": { - // For search queries, we debounce to avoid spamming analytics - debouncedTrackEvent("search", { - search_term: properties.searchQuery, - }); + case "search_query_response_received": { + if (properties.totalResults) { + trackEvent({ + event_name: "search", + custom_parameters: { + search_term: properties.searchQuery, + total_results: properties.totalResults, + }, + }); + } break; } case "user_message_submitted": { - // Also debounce Ask AI chat message input - debouncedTrackEvent(`inkeep_${eventName}`, { - latest_message: getLatestMessage( - properties.conversation.messages, - "user" - ), + trackEvent({ + event_name: `inkeep_${eventName}`, + custom_parameters: { + latest_user_message: getLatestMessage( + properties.conversation.messages, + "user" + ), + }, }); break; } @@ -168,7 +175,7 @@ export function useInkeepSearch(options: UseInkeepSearchOptions = {}) { trackEvent({ event_name: `inkeep_${eventName}`, custom_parameters: { - latest_message: getLatestMessage( + latest_user_message: getLatestMessage( properties.conversation.messages, "user" ), @@ -183,7 +190,7 @@ export function useInkeepSearch(options: UseInkeepSearchOptions = {}) { trackEvent({ event_name: `inkeep_${eventName}`, custom_parameters: { - latest_message: getLatestMessage( + latest_assistant_message: getLatestMessage( properties.conversation.messages, "assistant" ), @@ -209,7 +216,7 @@ export function useInkeepSearch(options: UseInkeepSearchOptions = {}) { trackEvent({ event_name: `inkeep_${eventName}`, custom_parameters: { - latest_message: getLatestMessage( + latest_assistant_message: getLatestMessage( properties.conversation.messages, "assistant" ), @@ -221,7 +228,7 @@ export function useInkeepSearch(options: UseInkeepSearchOptions = {}) { trackEvent({ event_name: `inkeep_${eventName}`, custom_parameters: { - latest_message: getLatestMessage( + latest_assistant_message: getLatestMessage( properties.conversation.messages, "assistant" ), @@ -231,13 +238,8 @@ export function useInkeepSearch(options: UseInkeepSearchOptions = {}) { }); break; } - default: { - trackEvent({ - event_name: `inkeep_${eventName}`, - custom_parameters: properties, - }); + default: break; - } } } catch (error) { console.error("Error processing Inkeep event:", error); @@ -265,9 +267,8 @@ export function useInkeepSearch(options: UseInkeepSearchOptions = {}) { const chatCallableFunctionsRef = useRef(null); const searchCallableFunctionsRef = useRef(null); - const handleChange = useCallback( + const handleSearchChange = useCallback( (str: string) => { - chatCallableFunctionsRef.current?.updateInputMessage(str); searchCallableFunctionsRef.current?.updateQuery(str); setMessage(str); if (autoOpenOnInput && str) { @@ -277,11 +278,22 @@ export function useInkeepSearch(options: UseInkeepSearchOptions = {}) { [autoOpenOnInput] ); + const handleChatChange = useCallback( + (str: string) => { + chatCallableFunctionsRef.current?.updateInputMessage(str); + setMessage(str); + if (autoOpenOnInput && str) { + setIsOpen(true); + } + }, + [autoOpenOnInput] + ); + // Create dynamic search settings based on version const dynamicSearchSettings = { ...inkeepSearchSettings, searchFunctionsRef: searchCallableFunctionsRef, - onQueryChange: handleChange, + onQueryChange: handleSearchChange, // Add version-specific metadata if version is provided ...(version && { metadata: { @@ -306,18 +318,15 @@ export function useInkeepSearch(options: UseInkeepSearchOptions = {}) { aiChatSettings: { ...inkeepAIChatSettings, chatFunctionsRef: chatCallableFunctionsRef, - onInputMessageChange: handleChange, + onInputMessageChange: handleChatChange, }, }), }; return { - message, - setMessage, isOpen, setIsOpen, ModalSearchAndChat, inkeepModalProps, - handleChange, }; } From f4f91d56abc5045a69f5dca8d4a71352d4295632 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aatu=20V=C3=A4is=C3=A4nen?= Date: Thu, 30 Oct 2025 14:18:41 +0200 Subject: [PATCH 5/9] Adjust event parameters --- src/hooks/useInkeepSearch.ts | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/hooks/useInkeepSearch.ts b/src/hooks/useInkeepSearch.ts index 7bb524ce..92153d93 100644 --- a/src/hooks/useInkeepSearch.ts +++ b/src/hooks/useInkeepSearch.ts @@ -129,8 +129,10 @@ export function useInkeepSearch(options: UseInkeepSearchOptions = {}) { role: "assistant" | "system" | "user" ) => { return ( - messages.filter((msg) => msg.role === role).slice(-1)[0]?.content || - "" + messages + .filter((msg) => msg.role === role) + .slice(-1)[0] + ?.content.slice(0, 100) || "" ); }; @@ -141,7 +143,7 @@ export function useInkeepSearch(options: UseInkeepSearchOptions = {}) { trackEvent({ event_name: "search", custom_parameters: { - search_term: properties.searchQuery, + search_term: properties.searchQuery.slice(0, 100), total_results: properties.totalResults, }, }); @@ -164,9 +166,8 @@ export function useInkeepSearch(options: UseInkeepSearchOptions = {}) { trackEvent({ event_name: `inkeep_${eventName}`, custom_parameters: { - search_term: properties.searchQuery, - title: properties.title, - url: properties.url, + search_term: properties.searchQuery.slice(0, 100), + clicked_link_url: properties.url, }, }); break; @@ -179,8 +180,7 @@ export function useInkeepSearch(options: UseInkeepSearchOptions = {}) { properties.conversation.messages, "user" ), - title: properties.link.title, - url: properties.link.url, + clicked_link_url: properties.link.url, }, }); break; @@ -197,7 +197,9 @@ export function useInkeepSearch(options: UseInkeepSearchOptions = {}) { feedback_reason_labels: properties?.reasons?.map((r) => r.label).join(", ") || "", feedback_reason_details: - properties?.reasons?.map((r) => r.details).join(", ") || "", + properties?.reasons + ?.map((r) => r.details.slice(0, 100)) + .join(", ") || "", }, }); break; @@ -206,8 +208,7 @@ export function useInkeepSearch(options: UseInkeepSearchOptions = {}) { trackEvent({ event_name: `inkeep_${eventName}`, custom_parameters: { - title: properties.title || "", - url: properties.url || "", + clicked_link_url: properties.url, }, }); break; @@ -228,12 +229,8 @@ export function useInkeepSearch(options: UseInkeepSearchOptions = {}) { trackEvent({ event_name: `inkeep_${eventName}`, custom_parameters: { - latest_assistant_message: getLatestMessage( - properties.conversation.messages, - "assistant" - ), + code_value: properties.code.slice(0, 100), code_language: properties.language || "", - code_value: properties.code || "", }, }); break; From 1a591f21c7e2a18597abcfd7193c6c20cb5e3237 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aatu=20V=C3=A4is=C3=A4nen?= Date: Thu, 30 Oct 2025 14:27:19 +0200 Subject: [PATCH 6/9] Update parameter name --- src/theme/DocRoot/Layout/Main/index.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/theme/DocRoot/Layout/Main/index.tsx b/src/theme/DocRoot/Layout/Main/index.tsx index 5be529aa..f7f4f9b7 100644 --- a/src/theme/DocRoot/Layout/Main/index.tsx +++ b/src/theme/DocRoot/Layout/Main/index.tsx @@ -51,7 +51,7 @@ export default function MainWrapper(props: Props): ReactNode { trackEvent({ event_name: "navbar_link_click", custom_parameters: { - url: link.href, + clicked_link_url: link.href, }, }); } @@ -60,7 +60,7 @@ export default function MainWrapper(props: Props): ReactNode { trackEvent({ event_name: "sidebar_link_click", custom_parameters: { - url: link.href, + clicked_link_url: link.href, }, }); } @@ -69,7 +69,7 @@ export default function MainWrapper(props: Props): ReactNode { trackEvent({ event_name: "active_page_link_click", custom_parameters: { - url: link.href, + clicked_link_url: link.href, }, }); } @@ -78,7 +78,7 @@ export default function MainWrapper(props: Props): ReactNode { trackEvent({ event_name: "breadcrumbs_link_click", custom_parameters: { - url: link.href, + clicked_link_url: link.href, }, }); } From 2d06a668f5f1e318763f480727b74b4c433b6f21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aatu=20V=C3=A4is=C3=A4nen?= Date: Thu, 30 Oct 2025 14:53:03 +0200 Subject: [PATCH 7/9] Add event for toc link clicks --- src/theme/DocRoot/Layout/Main/index.tsx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/theme/DocRoot/Layout/Main/index.tsx b/src/theme/DocRoot/Layout/Main/index.tsx index f7f4f9b7..1bc1a23b 100644 --- a/src/theme/DocRoot/Layout/Main/index.tsx +++ b/src/theme/DocRoot/Layout/Main/index.tsx @@ -47,6 +47,13 @@ export default function MainWrapper(props: Props): ReactNode { el.classList?.contains("theme-doc-breadcrumbs") ) as HTMLElement | undefined; + const toc = path.find( + (el) => + el instanceof HTMLElement && + (el.classList?.contains("theme-doc-toc-mobile") || + el.classList?.contains("theme-doc-toc-desktop")) + ) as HTMLElement | undefined; + if (link && navbar) { trackEvent({ event_name: "navbar_link_click", @@ -82,6 +89,12 @@ export default function MainWrapper(props: Props): ReactNode { }, }); } + + if (link && toc) { + trackEvent({ + event_name: "toc_link_click", + }); + } }; window.addEventListener("click", inkeepLinkTracker); From 48f0626c7be994111bcbdc63242cde47ecbf12d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aatu=20V=C3=A4is=C3=A4nen?= Date: Thu, 30 Oct 2025 14:56:13 +0200 Subject: [PATCH 8/9] Revert adding debounce utility function --- src/hooks/useInkeepSearch.ts | 8 -------- utils/general.ts | 18 +++--------------- 2 files changed, 3 insertions(+), 23 deletions(-) diff --git a/src/hooks/useInkeepSearch.ts b/src/hooks/useInkeepSearch.ts index 92153d93..695f4152 100644 --- a/src/hooks/useInkeepSearch.ts +++ b/src/hooks/useInkeepSearch.ts @@ -11,7 +11,6 @@ import type { ConversationMessage, } from "@inkeep/cxkit-react"; import { trackEvent } from "../utils/analytics"; -import { debounce } from "@site/utils/general"; interface UseInkeepSearchOptions { version?: string; @@ -21,13 +20,6 @@ interface UseInkeepSearchOptions { autoOpenOnInput?: boolean; // Auto-open modal when typing } -const debouncedTrackEvent = debounce((eventName: string, properties: any) => { - trackEvent({ - event_name: eventName, - custom_parameters: properties, - }); -}, 1000); - export function useInkeepSearch(options: UseInkeepSearchOptions = {}) { const { version, diff --git a/utils/general.ts b/utils/general.ts index a92cd06c..ec402464 100644 --- a/utils/general.ts +++ b/utils/general.ts @@ -9,10 +9,10 @@ */ export const toCopyContent = ( commandNode: HTMLElement, - commandLineClasses: string[] + commandLineClasses: string[], ): string => { const lines = Array.from( - commandNode.querySelectorAll(commandLineClasses.join(",")) + commandNode.querySelectorAll(commandLineClasses.join(",")), ).reduce((allLines, commandLine) => { allLines.push(commandLine.textContent); return allLines; @@ -58,16 +58,4 @@ export const getFromSecretOrEnv = (name: string): string => { ? JSON.parse(process.env.secrets) : process.env; return configVars[name]; -}; - -/* Debounce function to limit the rate of function calls */ -export const debounce = ( - func: (...args: any[] | undefined) => void, - wait: number -) => { - let timeout: NodeJS.Timeout; - return (...args: any[]) => { - clearTimeout(timeout); - timeout = setTimeout(() => func(...args), wait); - }; -}; +}; \ No newline at end of file From 8d945c1b5b7de3eb85aec2d17cbf7335439b9bcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aatu=20V=C3=A4is=C3=A4nen?= Date: Thu, 30 Oct 2025 14:58:57 +0200 Subject: [PATCH 9/9] revert change --- utils/general.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/general.ts b/utils/general.ts index ec402464..b2ce2b00 100644 --- a/utils/general.ts +++ b/utils/general.ts @@ -58,4 +58,4 @@ export const getFromSecretOrEnv = (name: string): string => { ? JSON.parse(process.env.secrets) : process.env; return configVars[name]; -}; \ No newline at end of file +};