
Strapi 管理后臺前端遙測useTracking 與 trackUsage 事件體系全解【免費(fèi)下載鏈接】strapi Strapi is the leading open-source headless CMS. It’s 100% JavaScript/TypeScript, fully customizable, and developer-first.項(xiàng)目地址: https://gitcode.com/GitHub_Trending/st/strapiStrapi 管理面板會把用戶在后臺的操作行為以事件形式直接從瀏覽器發(fā)送到 Strapi 分析端點(diǎn)這套前端遙測機(jī)制與strapi.telemetry.send所代表的服務(wù)端遙測相互獨(dú)立。本文基于 Strapi 倉庫中的docs/docs/docs/01-core/admin/04-features/telemetry.md文檔與對應(yīng)源碼完整解析其架構(gòu)分層、發(fā)送門禁、請求負(fù)載結(jié)構(gòu)、事件命名規(guī)范以及插件/包如何以 wrapper hook 模式接入統(tǒng)一的上報(bào) API。讀完本文你將能夠準(zhǔn)確理解前端事件的觸發(fā)時(shí)機(jī)與隱私設(shè)計(jì)并能在核心模塊或自定義插件中按官方約定新增一個(gè)類型安全的前端遙測事件。架構(gòu)總覽瀏覽器直連分析端點(diǎn)前端遙測的調(diào)用鏈路如下引自文檔并已對照源碼核實(shí)┌──────────────────────────────────────────────────────────────────┐ │ React components / hooks │ │ trackUsage(didSaveContentType) │ │ trackUsage(didCreateEntry, { documentId, status }) │ └────────────────────────────┬─────────────────────────────────────┘ │ ┌────────────────────────────▼─────────────────────────────────────┐ │ packages/core/admin/admin/src/features/Tracking.tsx │ │ TrackingProvider → context (uuid, telemetryProperties) │ │ useTracking() → trackUsage() │ └────────────┬───────────────────────────────┬───────────────────────┘ │ │ │ GET /admin/telemetry-properties│ POST /api/v2/track ▼ ▼ Strapi backend analytics.strapi.io (group metadata) (override: STRAPI_ANALYTICS_URL)從源碼結(jié)構(gòu)看整條鏈路的關(guān)鍵事實(shí)是常規(guī) UI 事件沒有服務(wù)端代理admin SPA 直接用axios向分析端點(diǎn)發(fā)起 POST 請求且失敗被靜默吞掉——追蹤永不阻塞 UI 流程。這一設(shè)計(jì)在 Tracking.tsx 中可以直接印證trackUsage主體包在try/catch中catch分支只留了一句注釋// Silence is golden異常時(shí)函數(shù)返回null。核心 API 之一useTracking()useTracking是管理后臺與所有插件使用遙測的主入口實(shí)現(xiàn)位于 Tracking.tsx并通過 admin/src/index.ts 從strapi/admin導(dǎo)出。官方用法示例與源碼 JSDoc 注釋一致import { useTracking } from strapi/admin/strapi-admin; const MyComponent () { const { trackUsage } useTracking(); const handleSave () { trackUsage(didSaveContentType); // or with properties: trackUsage(didCreateEntry, { documentId: abc, status: draft }); }; };trackUsage的類型簽名通過三組重載見 Tracking.tsx#L507-L525實(shí)現(xiàn)了一個(gè)關(guān)鍵能力有屬性的事件必須傳屬性無屬性的事件禁止傳屬性——export interface UseTrackingReturn { trackUsageTEvent extends TrackingEvent( event: TEvent[name], properties: TEvent[properties] ): Promisenull | AxiosResponsestring; trackUsageTEvent extends ExtractTrackingEvent, { properties?: never }( event: TEvent[name], properties?: never ): Promisenull | AxiosResponsestring; trackUsageTEvent extends ExtractTrackingEvent, { properties: object }( event: TEvent[name], properties: TEvent[properties] ): Promisenull | AxiosResponsestring; }返回值是Promisenull | AxiosResponsestring發(fā)送成功返回 axios 響應(yīng)被門禁攔截或請求失敗則返回null。核心 API 之二TrackingProvider 與 didInitializeAdministrationTrackingProvider掛載在 Providers.tsx 中位于AuthProvider、HistoryProvider、Theme等 Provider 之內(nèi)包裹整個(gè)已認(rèn)證應(yīng)用樹負(fù)責(zé)三件事通過useInitQuery()讀取項(xiàng)目uuid對應(yīng)GET /admin/init用戶登錄后通過useTelemetryPropertiesQuery()拉取telemetryProperties——源碼中該查詢帶skip: !initData?.uuid || !token條件見 Tracking.tsx#L49-L51即沒有 uuid 或沒有登錄 token 時(shí)根本不會發(fā)起該請求當(dāng)uuid與遙測屬性同時(shí)就緒時(shí)用原生fetch而非trackUsage發(fā)送一次didInitializeAdministration且該事件是匿名的userId: 見 Tracking.tsx#L52-L78。值得注意的一個(gè)源碼細(xì)節(jié)didInitializeAdministration的匿名事件體中g(shù)roupProperties除了展開服務(wù)端返回的遙測屬性外還會附帶projectId: uuid與registeredWidgets當(dāng)前注冊的全部 widget uid。這與常規(guī)事件的負(fù)載略有不同屬于“會話級初始化”特有的字段組合。發(fā)送門禁事件什么時(shí)候才真正發(fā)出trackUsage只有在所有條件同時(shí)滿足時(shí)才發(fā)出網(wǎng)絡(luò)請求門禁來源項(xiàng)目uuid為真值GET /admin/init——當(dāng)package.json中禁用遙測時(shí)為falsewindow.strapi.telemetryDisabled false構(gòu)建時(shí)由STRAPI_TELEMETRY_DISABLED在render.ts中注入只要任一門禁不滿足trackUsage直接返回null不產(chǎn)生任何網(wǎng)絡(luò)請求。源碼中的判斷只有一行Tracking.tsx#L557if (uuid !window.strapi.telemetryDisabled) { /* 才會 POST */ }兩個(gè)門禁的上游分別在哪里生成window.strapi.telemetryDisabled在 render.ts 中被初始化為process.env.STRAPI_TELEMETRY_DISABLED true即構(gòu)建期由環(huán)境變量決定uuid由服務(wù)端 controllers/admin.ts 的initaction 返回。該 action 會讀取strapi.config.get(packageJsonStrapi.telemetryDisabled)若用戶在項(xiàng)目package.json的strapi.telemetryDisabled中顯式置為true則uuid被強(qiáng)制改為false——這是在用戶側(cè)永久關(guān)閉前端遙測的官方配置點(diǎn)另外服務(wù)端strapi.telemetry.isDisabled還會影響GET /admin/telemetry-properties的返回禁用時(shí)直接返回204 No Content見 controllers/admin.ts#L103-L108使 group 元數(shù)據(jù)不可用。也就是說Strapi 把遙測開關(guān)做成了“構(gòu)建期環(huán)境變量 項(xiàng)目 package.json 服務(wù)端運(yùn)行時(shí)狀態(tài)”三層任一層關(guān)閉都會讓前端事件靜默消失。請求負(fù)載結(jié)構(gòu)POST /api/v2/track 的 Body每次通過門禁的trackUsage調(diào)用都會向以下地址發(fā)起 POSTTracking.tsx#L559${STRAPI_ANALYTICS_URL || https://analytics.strapi.io}/api/v2/track請求體各字段的來源前端視角如下端點(diǎn)與服務(wù)端遙測相同字段前端來源eventtrackUsage的第一個(gè)參數(shù)userId管理員郵箱的 SHA-256 哈希hashAdminUserEmail在AuthenticatedLayout中計(jì)算eventPropertiestrackUsage的第二個(gè)參數(shù)各事件自定義屬性userProperties.deviceTypedesktop \| tablet \| mobile來自useDeviceType()的 user-agent 啟發(fā)式判斷groupPropertiestelemetryProperties展開 projectId: uuidprojectType: window.strapi.projectType請求頭額外攜帶X-Strapi-Event: event name便于接收側(cè)按事件名路由。其中隱私處理最典型的是userId的生成AuthenticatedLayout掛載后調(diào)用 users.ts 中的hashAdminUserEmail內(nèi)部用 Web Crypto 的crypto.subtle.digest(SHA-256, ...)對郵箱做單向哈希后再轉(zhuǎn) 16 進(jìn)制字符串——郵箱原文從不離開瀏覽器失敗時(shí)返回null而不是拋錯(cuò)。服務(wù)端提供的 group 元數(shù)據(jù)GET /admin/telemetry-properties由 controllers/admin.ts 的telemetryPropertiesaction 實(shí)現(xiàn)要求已認(rèn)證的管理員身份返回的字段及其計(jì)算方式均摘自該 action 源碼useTypescriptOnServer/useTypescriptOnAdmin懶加載strapi/typescript-utils分別探測項(xiàng)目根目錄與src/admin是否使用 TypeScriptisHostedOnStrapiCloud判斷環(huán)境變量STRAPI_HOSTING strapi.cloudnumberOfAllContentTypesstrapi.contentTypes的條目數(shù)numberOfComponentsstrapi.components的條目數(shù)numberOfDynamicZones用 lodash/fp 管道m(xù)ap(attributes) → flatMap(values) → sumBy(propEq(type, dynamiczone))統(tǒng)計(jì)所有內(nèi)容類型 attributes 中的動態(tài)區(qū)數(shù)量。生命周期與會話事件以下事件由框架自動發(fā)出通常不需要在業(yè)務(wù)代碼里手動添加事件觸發(fā)時(shí)機(jī)說明didInitializeAdministrationuuid telemetry properties 齊備后的首次加載匿名userId: 走原生fetch而非trackUsagedidAccessAuthenticatedAdministration認(rèn)證布局掛載且projectId可用時(shí)攜帶registeredWidgets與projectId第二個(gè)事件的源碼在 AuthenticatedLayout.tsx#L82-L89當(dāng)useInformationQuery()返回的projectId就緒時(shí)useEffect依賴projectId觸發(fā)一次trackUsage(didAccessAuthenticatedAdministration, { registeredWidgets, projectId })——依賴數(shù)組的寫法保證了每次進(jìn)入已認(rèn)證布局都會上報(bào)一次“管理員訪問”事實(shí)。事件命名規(guī)范與類型定義前端遙測沿用與服務(wù)端遙測相同的詞表并額外強(qiáng)調(diào)will*意圖事件用戶在 UI 中啟動了某個(gè)動作前綴含義示例will*用戶發(fā)起 / 即將執(zhí)行willCreateEntry、willNavigate、willSaveContentTypedid*動作完成didCreateEntry、didSaveContentType、didPublishEntrydidNot*失敗或取消didNotCreateEntry、didNotDeleteEntry事件名被定義為 Tracking.tsx 中的 TypeScript 聯(lián)合類型TrackingEvent分為兩組EventWithoutProperties無第二參數(shù)的約 100 個(gè)事件名如didSaveContentType、willCreateContentType、didClickOnDocLink等properties?: never強(qiáng)制禁止傳屬性EventsWithProperties帶類型化屬性形狀的事件按業(yè)務(wù)域劃分接口例如interface CreateEntryEvents { name: willCreateEntry | didCreateEntry | didNotCreateEntry; properties: { documentId?: string; status?: string; error?: unknown; fromPreview?: boolean; fromRelationModal?: boolean; }; } interface WillNavigateEvent { name: willNavigate; properties: { from: string; to: string; }; } interface DidPublishRelease { name: didPublishRelease; properties: { totalEntries: number; totalPublishedEntries: number; totalUnpublishedEntries: number; }; }從源碼結(jié)構(gòu)看覆蓋的屬性化事件域包括內(nèi)容管理器的條目 CRUDCreateEntryEvents/UpdateEntryEvents/DeleteEntryEvents/PublishEntryEvents、媒體庫MediaEvents、DidFilterMediaLibraryElementsEvent等、API tokenTokenEvents、引導(dǎo)式教程DidStartGuidedTour/DidCompleteGuidedTour/DidSkipGuidedTour、content-releases 的DidPublishRelease、CTB 的 AI 事件DidUsePresetPromptEvent、DidAnswerMessageEvent、DidUpdateCTBSchema以及首頁 widgetDidOpenHomeWidgetLink等。新增事件必須更新Tracking.tsx中的聯(lián)合類型調(diào)用方才能獲得類型檢查與自動補(bǔ)全繞過類型系統(tǒng)直接傳字符串事件名在 TS 下會編譯報(bào)錯(cuò)。插件與包的接入模式wrapper hook 而非直接 POST各插件統(tǒng)一從strapi/admin/strapi-admin導(dǎo)入useTracking在組件或 hook 中調(diào)用trackUsage。主要消費(fèi)方一覽包典型事件strapi/adminSettings、roles、tokens、導(dǎo)航、引導(dǎo)教程、widgetsstrapi/content-manager條目 CRUD、批量操作、列表配置、過濾器、歷史記錄strapi/content-type-builderSchema 編輯、AI 對話經(jīng)下述 wrapperstrapi/upload媒體庫操作經(jīng)下述 wrapperstrapi/content-releasesdidPublishRelease兩個(gè) wrapper hook 是官方推薦的“擴(kuò)展屬性但不替換 API”范式CTB 的useCTBTrackinguseCTBTracking.ts包裝useTracking從useCTBSession()取sessionId并自動合并ctbSessionId到每個(gè)事件的屬性中同時(shí)刻意放寬了類型接受任意字符串事件名使 CTB 特有事件不必每次都去更新上游中央類型定義。Upload 的useTrackingupload/admin/src/hooks/useTracking.ts包裝核心useTracking在 AI 可用時(shí)useAIAvailability()向?qū)傩灾凶芳觟sAiMediaLibraryConfigured字段與服務(wù)端 upload 指標(biāo)的模式保持一致。官方約定很明確為插件添加遙測時(shí)若每個(gè)事件都需要一致的額外字段優(yōu)先包裝核心 hook而不是自己直接向分析端點(diǎn) POST——這樣可以統(tǒng)一繼承門禁、負(fù)載封裝與靜默失敗行為。其他分析端點(diǎn)不走 trackUsage除標(biāo)準(zhǔn)事件外還有兩處請求繞過Tracking.tsx但訪問同一分析主機(jī)端點(diǎn)組件用途POST /api/v2/trackTracking.tsx、useTracking標(biāo)準(zhǔn)事件POST /registerUseCasePage.tsx首個(gè)管理員的 persona 登記email、rolePOST /submit-npsNpsSurvey.tsxNPS 問卷提交其中 NPS 端點(diǎn)可從源碼直接驗(yàn)證NpsSurvey.tsx#L200-L204 用原生fetch向${STRAPI_ANALYTICS_URL || https://analytics.strapi.io}/submit-nps發(fā)送問卷響應(yīng)負(fù)載中附帶isHostedOnStrapiCloud: process.env.STRAPI_HOSTING strapi.cloud問卷的觸發(fā)時(shí)機(jī)詳見 NPS 文檔。請求量與速率控制約定與服務(wù)端遙測不同admin 前端沒有任何速率限制器或批量合并機(jī)制——每一次通過門禁的trackUsage調(diào)用都會產(chǎn)生一個(gè)獨(dú)立的 HTTP 請求。實(shí)踐中依靠以下約定控制量級will*與did*/didNot*配對只在有意義的完成點(diǎn)發(fā)出而不是每次按鍵都發(fā)屬性上優(yōu)先使用類別而非高基數(shù)標(biāo)識符盡管部分事件確實(shí)包含documentId導(dǎo)航追蹤willNavigate在菜單點(diǎn)擊時(shí)觸發(fā)而不是每次路由渲染都觸發(fā)。文檔同時(shí)給出明確約束不要在沒有明確產(chǎn)品需求的情況下添加 per-render 或高頻追蹤。window.strapi 上的遙測字段render.ts 在掛載 admin 應(yīng)用前初始化window.strapi與遙測相關(guān)的字段為window.strapi.telemetryDisabled process.env.STRAPI_TELEMETRY_DISABLED true; window.strapi.projectType Community | Enterprise; // 由 /admin/project-type 返回后更新其中projectType初始為Community隨后render.ts會調(diào)用GET /admin/project-type并以getProjectType({ isEE, planPriceId })更新它render.ts#L88-L113失敗時(shí)保持默認(rèn)值不報(bào)錯(cuò)。這些全局字段的完整 TypeScript 聲明在 admin/custom.d.ts 的BrowserStrapi接口中包括telemetryDisabled: boolean與projectType: Community | Growth | Enterprise。新增一個(gè)前端遙測事件的檢查清單命名——遵循will*/did*/didNot*約定更新類型——加入EventWithoutProperties或在 Tracking.tsx 中新建屬性接口并納入EventsWithProperties聯(lián)合調(diào)用trackUsage——在組件或 hook 的正確生命周期時(shí)機(jī)按鈕點(diǎn)擊、mutation 成功/失敗調(diào)用屬性設(shè)計(jì)——用eventProperties承載動作上下文項(xiàng)目與設(shè)備元數(shù)據(jù)交給自動填充的groupProperties/userProperties插件場景——從strapi/admin/strapi-admin導(dǎo)入若每個(gè)事件都需要額外字段考慮寫一個(gè) wrapper hook測試——mockaxios.post和/或useTracking參考Tracking.test.tsx與各插件的__mocks__/useTracking.ts。特別提醒不要為純服務(wù)端功能例如 MCP 類能力添加前端追蹤——那類場景應(yīng)使用服務(wù)端的strapi.telemetry.send參見 Server-side telemetry 文檔。測試實(shí)踐Tracking.test.tsx 是前端遙測的行為契約覆蓋三類斷言負(fù)載形狀斷言axios.post以https://analytics.strapi.io/api/v2/track為 URL 被調(diào)用且 body 含userId、eventProperties、groupProperties、userProperties.deviceType門禁行為telemetryDisabled為真或缺少uuid時(shí)不發(fā)出請求失敗降級axios.postreject 時(shí)trackUsage靜默返回而非拋錯(cuò)。插件側(cè)測試則普遍采用jest.mock(strapi/admin/strapi-admin, () ({ useTracking: ... }))或本地__mocks__/useTracking.ts來隔離遙測依賴避免單測產(chǎn)生真實(shí)網(wǎng)絡(luò)調(diào)用。小結(jié)Strapi 管理后臺的前端遙測是一個(gè)“輕量、匿名、可整體關(guān)閉”的瀏覽器端事件體系TrackingProvider負(fù)責(zé)聚合 uuid 與服務(wù)端 group 元數(shù)據(jù)useTracking().trackUsage以類型安全的聯(lián)合類型約束事件名與屬性兩層門禁uuidtelemetryDisabled保證尊重用戶與環(huán)境的關(guān)閉配置SHA-256 郵箱哈希保證不上報(bào)個(gè)人標(biāo)識原文。對插件開發(fā)者而言正確的接入姿勢是包裝核心 hook 附加屬性并更新Tracking.tsx的類型定義讓新事件進(jìn)入編譯期檢查——這套約定與 docs/docs/docs/01-core/admin/04-features/telemetry.md 文檔、Tracking.tsx 實(shí)現(xiàn)及其測試用例完全一致。【免費(fèi)下載鏈接】strapi Strapi is the leading open-source headless CMS. It’s 100% JavaScript/TypeScript, fully customizable, and developer-first.項(xiàng)目地址: https://gitcode.com/GitHub_Trending/st/strapi創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考