@@ -39,6 +39,7 @@ export type GravityAdState = {
3939export const useGravityAd = ( ) : GravityAdState => {
4040 const [ ad , setAd ] = useState < AdResponse | null > ( null )
4141 const [ isLoading , setIsLoading ] = useState ( false )
42+ const [ shouldShowAd , setShouldShowAd ] = useState ( false )
4243 const impressionFiredRef = useRef < Set < string > > ( new Set ( ) )
4344
4445 // Pre-fetched next ad ready to display
@@ -58,8 +59,9 @@ export const useGravityAd = (): GravityAdState => {
5859 const isStartedRef = useRef < boolean > ( false )
5960
6061 // Fire impression via web API when ad changes (grants credits)
62+ // Only fire impressions when ad is actually being shown
6163 useEffect ( ( ) => {
62- if ( ad ?. impUrl && ! impressionFiredRef . current . has ( ad . impUrl ) ) {
64+ if ( shouldShowAd && ad ?. impUrl && ! impressionFiredRef . current . has ( ad . impUrl ) ) {
6365 const currentImpUrl = ad . impUrl
6466 impressionFiredRef . current . add ( currentImpUrl )
6567 logger . info (
@@ -104,7 +106,7 @@ export const useGravityAd = (): GravityAdState => {
104106 logger . debug ( { err } , '[gravity] Failed to record ad impression' )
105107 } )
106108 }
107- } , [ ad ] )
109+ } , [ ad , shouldShowAd ] )
108110
109111 // Clear all timers
110112 const clearTimers = useCallback ( ( ) => {
@@ -250,10 +252,40 @@ export const useGravityAd = (): GravityAdState => {
250252 }
251253 } , [ fetchAdAsync , scheduleNextCycle ] )
252254
255+ // Subscribe to UI messages to detect first user message
256+ // Only show ads after the user has sent at least one message (clean startup UX)
257+ // We use UI messages instead of runState.messageHistory because UI messages
258+ // update immediately when the user sends a message
259+ useEffect ( ( ) => {
260+ if ( shouldShowAd || ! getAdsEnabled ( ) ) {
261+ return
262+ }
263+
264+ // Check initial state
265+ const initialMessages = useChatStore . getState ( ) . messages
266+ if ( initialMessages . some ( ( msg ) => msg . variant === 'user' ) ) {
267+ setShouldShowAd ( true )
268+ return
269+ }
270+
271+ const unsubscribe = useChatStore . subscribe ( ( state ) => {
272+ const hasUserMessage = state . messages . some ( ( msg ) => msg . variant === 'user' )
273+
274+ if ( hasUserMessage ) {
275+ unsubscribe ( )
276+ logger . info ( '[gravity] First user message detected, showing ads' )
277+ setShouldShowAd ( true )
278+ }
279+ } )
280+
281+ return unsubscribe
282+ } , [ shouldShowAd ] )
283+
253284 // Clear timers only on unmount
254285 useEffect ( ( ) => {
255286 return ( ) => clearTimers ( )
256287 } , [ clearTimers ] )
257288
258- return { ad, isLoading, reportActivity }
289+ // Only return the ad if we should show it (after first user message)
290+ return { ad : shouldShowAd ? ad : null , isLoading, reportActivity }
259291}
0 commit comments