diff --git a/common/tracking.ts b/common/tracking.ts
index 29a1365c..bf06b6e3 100644
--- a/common/tracking.ts
+++ b/common/tracking.ts
@@ -10,3 +10,9 @@ export type ClickEvent = {
contractId: string
timestamp: number
}
+
+export type LatencyEvent = {
+ type: 'feed' | 'portfolio'
+ latency: number
+ timestamp: number
+}
diff --git a/firestore.rules b/firestore.rules
index 542bd5ec..09d65aac 100644
--- a/firestore.rules
+++ b/firestore.rules
@@ -30,6 +30,10 @@ service cloud.firestore {
allow create: if userId == request.auth.uid;
}
+ match /private-users/{userId}/latency/{loadTimeId} {
+ allow create: if userId == request.auth.uid;
+ }
+
match /contracts/{contractId} {
allow read;
allow update: if request.resource.data.diff(resource.data).affectedKeys()
diff --git a/web/components/bets-list.tsx b/web/components/bets-list.tsx
index 35e0b3d9..63cbfd57 100644
--- a/web/components/bets-list.tsx
+++ b/web/components/bets-list.tsx
@@ -37,6 +37,8 @@ import {
resolvedPayout,
getContractBetNullMetrics,
} from '../../common/calculate'
+import { useTimeSinceFirstRender } from '../hooks/use-time-since-first-render'
+import { trackLatency } from '../lib/firebase/tracking'
type BetSort = 'newest' | 'profit' | 'closeTime' | 'value'
type BetFilter = 'open' | 'closed' | 'resolved' | 'all'
@@ -67,6 +69,14 @@ export function BetsList(props: { user: User }) {
}
}, [bets])
+ const getTime = useTimeSinceFirstRender()
+ useEffect(() => {
+ if (bets && contracts) {
+ trackLatency('portfolio', getTime())
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [!!bets, !!contracts])
+
if (!bets || !contracts) {
return
}
diff --git a/web/hooks/use-algo-feed.ts b/web/hooks/use-algo-feed.ts
index f27a1870..543f484b 100644
--- a/web/hooks/use-algo-feed.ts
+++ b/web/hooks/use-algo-feed.ts
@@ -14,6 +14,8 @@ import {
getOutcomeProbability,
getTopAnswer,
} from '../../common/calculate'
+import { useTimeSinceFirstRender } from './use-time-since-first-render'
+import { trackLatency } from '../lib/firebase/tracking'
const MAX_FEED_CONTRACTS = 75
@@ -35,6 +37,8 @@ export const useAlgoFeed = (
const [algoFeed, setAlgoFeed] = useState([])
+ const getTime = useTimeSinceFirstRender()
+
useEffect(() => {
if (
initialContracts &&
@@ -53,6 +57,7 @@ export const useAlgoFeed = (
seenContracts
)
setAlgoFeed(contracts)
+ trackLatency('feed', getTime())
}
}, [
initialBets,
@@ -60,6 +65,7 @@ export const useAlgoFeed = (
initialContracts,
seenContracts,
yourBetContractIds,
+ getTime,
])
return algoFeed
diff --git a/web/hooks/use-time-since-first-render.ts b/web/hooks/use-time-since-first-render.ts
new file mode 100644
index 00000000..da132146
--- /dev/null
+++ b/web/hooks/use-time-since-first-render.ts
@@ -0,0 +1,13 @@
+import { useCallback, useEffect, useRef } from 'react'
+
+export function useTimeSinceFirstRender() {
+ const startTimeRef = useRef(0)
+ useEffect(() => {
+ startTimeRef.current = Date.now()
+ }, [])
+
+ return useCallback(() => {
+ if (!startTimeRef.current) return 0
+ return Date.now() - startTimeRef.current
+ }, [])
+}
diff --git a/web/lib/firebase/tracking.ts b/web/lib/firebase/tracking.ts
index 4d609f68..034ad09d 100644
--- a/web/lib/firebase/tracking.ts
+++ b/web/lib/firebase/tracking.ts
@@ -2,7 +2,7 @@ import { doc, collection, setDoc } from 'firebase/firestore'
import _ from 'lodash'
import { db } from './init'
-import { ClickEvent, View } from '../../../common/tracking'
+import { ClickEvent, LatencyEvent, View } from '../../../common/tracking'
import { listenForLogin, User } from './users'
let user: User | null = null
@@ -34,3 +34,19 @@ export async function trackClick(contractId: string) {
return await setDoc(ref, clickEvent)
}
+
+export async function trackLatency(
+ type: 'feed' | 'portfolio',
+ latency: number
+) {
+ if (!user) return
+ const ref = doc(collection(db, 'private-users', user.id, 'latency'))
+
+ const latencyEvent: LatencyEvent = {
+ type,
+ latency,
+ timestamp: Date.now(),
+ }
+
+ return await setDoc(ref, latencyEvent)
+}