diff --git a/package.json b/package.json index 9ecacecf..0265409b 100644 --- a/package.json +++ b/package.json @@ -139,7 +139,7 @@ "@scure/bip32": "1.3.0", "@scure/bip39": "1.2.0", "@scure/btc-signer": "0.5.1", - "@segment/analytics-next": "1.49.2", + "@segment/analytics-next": "1.51.5", "@sentry/react": "7.35.0", "@sentry/tracing": "7.35.0", "@stacks/auth": "6.1.1", diff --git a/src/app/common/hooks/analytics/use-analytics.ts b/src/app/common/hooks/analytics/use-analytics.ts index 23c906bf..0d68e418 100644 --- a/src/app/common/hooks/analytics/use-analytics.ts +++ b/src/app/common/hooks/analytics/use-analytics.ts @@ -1,4 +1,4 @@ -import { useMemo } from 'react'; +import { useEffect, useMemo } from 'react'; import { useLocation } from 'react-router-dom'; import { @@ -6,9 +6,9 @@ import { PageParams, } from '@segment/analytics-next/dist/types/core/arguments-resolver'; -import { IS_TEST_ENV } from '@shared/environment'; +import { IS_TEST_ENV, SEGMENT_WRITE_KEY } from '@shared/environment'; import { logger } from '@shared/logger'; -import { analytics } from '@shared/utils/analytics'; +import { analytics, initAnalytics } from '@shared/utils/analytics'; import { flow, origin } from '@app/common/initial-search-params'; import { useWalletType } from '@app/common/use-wallet-type'; @@ -25,13 +25,20 @@ function isHiroApiUrl(url: string) { return /^https:\/\/.*\.stacks.co/.test(url); } +export function useInitalizeAnalytics() { + const hasUserDeclinedAnalytics = useHasUserExplicitlyDeclinedAnalytics(); + + useEffect(() => { + if (hasUserDeclinedAnalytics || !SEGMENT_WRITE_KEY || IS_TEST_ENV) return; + initAnalytics(); + }, [hasUserDeclinedAnalytics]); +} + export function useAnalytics() { const currentNetwork = useCurrentNetworkState(); const location = useLocation(); const { walletType } = useWalletType(); - const hasDeclined = useHasUserExplicitlyDeclinedAnalytics(); - return useMemo(() => { const defaultProperties = { network: currentNetwork.name.toLowerCase(), @@ -48,37 +55,29 @@ export function useAnalytics() { }; return { + async identify(properties: object) { + return analytics.identify(properties).catch(logger.error); + }, + async page(...args: PageParams) { const [category, name, properties, options, ...rest] = args; const prop = { ...defaultProperties, ...properties }; const opts = { ...defaultOptions, ...options }; logger.info(`Analytics page view: ${name}`, properties); - if (!analytics) return; - if (hasDeclined) return; - if (IS_TEST_ENV) return; if (typeof name === 'string' && isIgnoredPath(name)) return; return analytics.page(category, name, prop, opts, ...rest).catch(logger.error); }, + async track(...args: EventParams) { const [eventName, properties, options, ...rest] = args; const prop = { ...defaultProperties, ...properties }; const opts = { ...defaultOptions, ...options }; logger.info(`Analytics event: ${eventName}`, properties); - if (!analytics) return; - if (hasDeclined) return; - if (IS_TEST_ENV) return; - return analytics.track(eventName, prop, opts, ...rest).catch(logger.error); }, }; - }, [ - currentNetwork.chain.stacks.url, - currentNetwork.name, - location.pathname, - walletType, - hasDeclined, - ]); + }, [currentNetwork.chain.stacks.url, currentNetwork.name, location.pathname, walletType]); } diff --git a/src/app/features/collectibles/components/bitcoin/ordinals.tsx b/src/app/features/collectibles/components/bitcoin/ordinals.tsx index 2f539ab8..9272a600 100644 --- a/src/app/features/collectibles/components/bitcoin/ordinals.tsx +++ b/src/app/features/collectibles/components/bitcoin/ordinals.tsx @@ -15,6 +15,7 @@ export function Ordinals() { void analytics.track('view_collectibles', { ordinals_count: utxos.length, }); + void analytics.identify({ ordinals_count: utxos.length }); } }, [utxos.length, analytics]); diff --git a/src/app/features/collectibles/components/stacks/stacks-crypto-assets.tsx b/src/app/features/collectibles/components/stacks/stacks-crypto-assets.tsx index f4e8695a..6a312264 100644 --- a/src/app/features/collectibles/components/stacks/stacks-crypto-assets.tsx +++ b/src/app/features/collectibles/components/stacks/stacks-crypto-assets.tsx @@ -18,6 +18,7 @@ export function StacksCryptoAssets() { void analytics.track('view_collectibles', { stacks_nfts_count: stacksNftsMetadataResp.length, }); + void analytics.identify({ stacks_nfts_count: stacksNftsMetadataResp.length }); } }, [stacksNftsMetadataResp.length, analytics]); diff --git a/src/app/features/container/container.tsx b/src/app/features/container/container.tsx index 23d51716..f4d29f7b 100644 --- a/src/app/features/container/container.tsx +++ b/src/app/features/container/container.tsx @@ -1,5 +1,6 @@ import { Outlet } from 'react-router-dom'; +import { useInitalizeAnalytics } from '@app/common/hooks/analytics/use-analytics'; import { useRouteHeaderState } from '@app/store/ui/ui.hooks'; import { useRestoreFormState } from '../popup-send-form-restoration/use-restore-form-state'; @@ -10,6 +11,8 @@ export function Container() { useRestoreFormState(); + useInitalizeAnalytics(); + return ( diff --git a/src/shared/utils/analytics.ts b/src/shared/utils/analytics.ts index e7372392..5dd954bc 100644 --- a/src/shared/utils/analytics.ts +++ b/src/shared/utils/analytics.ts @@ -13,10 +13,10 @@ import { persistConfig } from '@shared/storage'; import type { RootState } from '@app/store'; -function initAnalytics() { - if (IS_TEST_ENV || !SEGMENT_WRITE_KEY) return null; +export const analytics = new AnalyticsBrowser(); - return AnalyticsBrowser.load( +export function initAnalytics() { + return analytics.load( { writeKey: SEGMENT_WRITE_KEY }, { integrations: { @@ -33,7 +33,6 @@ function initAnalytics() { } ); } -export const analytics: null | AnalyticsBrowser = initAnalytics(); export function initSentry() { if (IS_TEST_ENV || !SENTRY_DSN) return; diff --git a/yarn.lock b/yarn.lock index f2e366d9..c5b1c48f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3299,22 +3299,22 @@ "@scure/base" "~1.1.0" micro-packed "~0.3.2" -"@segment/analytics-core@1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@segment/analytics-core/-/analytics-core-1.2.1.tgz#6f551b74a6af2331cb86c7e29428487f3d135266" - integrity sha512-FaKE7uIBXsclO4GcA7cEgb4iyQ23aFHRcxqLpxaCGeB5nqIdVQHigmGgL3hAjCZeBqtojLEV6as27ozXHQXCkg== +"@segment/analytics-core@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@segment/analytics-core/-/analytics-core-1.2.4.tgz#a01f0c87246292e0b9790e12c73d2f7e5fceb168" + integrity sha512-M16osD6+z/bQPSVCZdlU+BAhCk968ppi+SGxU2gVa4B196Qr8SEkBPr3NxUCGTSoULo4/T+k8Ea5cF+pXlgf6Q== dependencies: "@lukeed/uuid" "^2.0.0" dset "^3.1.2" tslib "^2.4.1" -"@segment/analytics-next@1.49.2": - version "1.49.2" - resolved "https://registry.yarnpkg.com/@segment/analytics-next/-/analytics-next-1.49.2.tgz#7499f0adbdf8ad5eca840e4e31f3858bd716792a" - integrity sha512-i1Z5OfapDQQkielF9Cz9q8PeLvRTgBMPxHn5SoIx3SZJEzWTzFkvrmg/v98P8TcyjzbSa6hsVySm4E0tVdj8mA== +"@segment/analytics-next@1.51.5": + version "1.51.5" + resolved "https://registry.yarnpkg.com/@segment/analytics-next/-/analytics-next-1.51.5.tgz#2f4558a13cb2ccc0be394f4ad9de253f659a3bba" + integrity sha512-al/8j/GKuTLV7vK4qKrsb2uTfh07Q8ETChPnklIgKfgUMsMZJHJWj/TAjuIgVt7SPmoiqH+ESOrH4yzKT1Wvag== dependencies: "@lukeed/uuid" "^2.0.0" - "@segment/analytics-core" "1.2.1" + "@segment/analytics-core" "1.2.4" "@segment/analytics.js-video-plugins" "^0.2.1" "@segment/facade" "^3.4.9" "@segment/tsub" "1.0.1"