PostHog / posthog-js-lite

Reimplementation of posthog-js to be as light and modular as possible.
https://posthog.com/docs/libraries
MIT License
70 stars 36 forks source link

`expo-router` touch events support #171

Open marandaneto opened 10 months ago

marandaneto commented 10 months ago

Description

https://docs.expo.dev/router/installation/#quick-start https://github.com/expo/expo/tree/main/packages/expo-router right now we support @react-navigation/native and react-native-navigation but not yet expo-router which is getting more popular day by day https://results.stateofreactnative.com/navigation/

Screenshot 2024-02-01 at 14 50 52
marandaneto commented 9 months ago

A quick solution would be to adapt the new router integration based on the other integrations such as https://github.com/PostHog/posthog-js-lite/blob/01fff0242a620345614a792379397029cf6cc9f1/posthog-react-native/src/frameworks/wix-navigation.ts and https://github.com/PostHog/posthog-js-lite/blob/01fff0242a620345614a792379397029cf6cc9f1/posthog-react-native/src/hooks/useNavigationTracker.ts

marandaneto commented 9 months ago

https://expo.github.io/router/docs/migration/react-navigation/screen-tracking/ should give a head start.

johnslemmer commented 9 months ago

FYI I just pulled posthog into my expo-router react native app and it captured navigation/screen events without me needing to do anything special. I think because it is built on top of react-navigation 🤷 ?

marandaneto commented 9 months ago

Most likely but there are a few limitations as pointed out here.

AdamDorwart commented 8 months ago

Oh no, I just ran into this. Yes it appears everything related to captureTouches is missing. I see some captureScreens events but not sure how complete it is.

Is this being worked on?

marandaneto commented 8 months ago

@AdamDorwart not at the moment, would you like to take a look and open a draft PR? happy to help out/review.

AdamDorwart commented 8 months ago

I gave myself and hour to see what I could do but unfortunately I couldn't get touch events to work in the existing examples. I ran into some regressions on main that I at least gave a quick fix for https://github.com/PostHog/posthog-js-lite/pull/206

Unfortunately I couldn't get any touch events working in the example_expo_rn_web. My plan was to create a new example off that using expo-router. Before I added expo-router I switched it to use PostHogProvider and instrumented it with debugging but every touch event ended here https://github.com/PostHog/posthog-js-lite/blob/b27cd3fcc061bcf0fab3c4a77992112b371f3abf/posthog-react-native/src/autocapture.tsx#L51

I'm not sure why e._targetInst was null for everything. I even added some more components to the example that I ripped from example-expo:

         <View>
          <Text testID="example-ph-label" ph-label="special-text">
            I have the property "ph-label" which means touching me will be autocaptured with a specific label
          </Text>
        </View>

I ran out of time so I need to move on for now and just use manual event capture.

marandaneto commented 8 months ago

Thanks for checking it out @AdamDorwart Did you check what else e had available? e should be of the type e: GestureResponderEvent, maybe there's something different either because of the expo or because of fabric, the new RN architecture.

AdamDorwart commented 8 months ago

It was always a SyntheticBaseEvent. These are challenging to share in a readable way so here's a screenshot

Screenshot 2024-03-13 at 12 09 24 PM

I'm not familiar with e._targetInst but when I debug React components like this I look for e.target.__reactFiber$* which is there and has memoizedProps, and elementType.

image
marandaneto commented 8 months ago

_targetInst isn't a public property, https://github.com/facebook/react-native/blob/dceda565bdfe24275be0ad5caae7f3d8252aef92/packages/react-native/Libraries/Renderer/implementations/ReactFabric-prod.js#L104

kwong70 commented 7 months ago

With expo-router many of my screens are named index.ts. Which causes a problem with autocapture since it uses the filename to define the Screen Name. So I get a lot of dupes in the PH logs. Would be great if i could change how PH autocapture generates the Screen Name instead of default using the filename.

Any workarounds besides changing the name of all my files away from index.ts.

marandaneto commented 7 months ago

@kwong70 you can try https://expo.github.io/router/docs/migration/react-navigation/screen-tracking/ just call posthog.screen(...) manually, does it get any better?

MartinHarkins commented 5 months ago

Hey, so for our app using expo-router for native & web, we're actually forgetting about $pageview and instead using screen. Thought I'd share.


export const usePostHogNavigationTracker = () => {
  const posthog = usePostHog() || posthogClient
  const pathname = usePathname()
  const params = useGlobalSearchParams()

  let pathAndParams = pathname
  try {
    const strippedParams = { ...params }
    // remove props we don't care about. (screen is redundant, params is not parsable and useless)
    delete strippedParams['screen']
    delete strippedParams['params']

    pathAndParams = pathname + objectToQueryParams(strippedParams)
  } catch (e) {
    l.warn('Could not parse parameters', params, e)
  }

  useEffect(() => {
    posthog?.screen(pathAndParams)
  }, [posthog, pathAndParams])
}

This was at the beginning of the project. The above implementation has downsides:

  1. The urls have dynamic content => useful, but not as easy to aggregate and to identify 1 page
  2. We often have 2 urls for what could be called a same page (1 for mobile, and one for web/wide screen)

We're going to revise our implementation as we're actually interested in all 3 data:

  1. static route name (ie. /(main)/todos/[todoUuid]/edit)
  2. dynamic route name (/todos/my-todo-uuid-1/edit)
  3. page name: Todo Edit Name (ie. matches /(main)/todos/[todoUuid]/edit and /(main)/m/todos/[todoUuid]/edit)
chasem-dev commented 4 months ago

I installed posthog react-native on my expo-router app. The Activity seems to work, it even fires off screen events.

image

The only thing is that it doesn't actually track the user in the analytics section of PostHog. Would firing a custom .screen() fix this?

marandaneto commented 3 months ago

I installed posthog react-native on my expo-router app. The Activity seems to work, it even fires off screen events. image

The only thing is that it doesn't actually track the user in the analytics section of PostHog. Would firing a custom .screen() fix this?

The screen events seems to be working based on your screenshot, if you mean user clicks etc, feel free to capture custom events using the capture method.

erenkulaksiz commented 3 months ago

Hello, i want to add here, i can capture screen events like this in my expo app:

const pathname = usePathname();
const params = useGlobalSearchParams();

useEffect(() => {
  posthog.screen(pathname, {
    ...params,
  });
}, [pathname, params]);

Now, i want to capture screen touches like where users press the most but i think i cannot do it. I only put custom captures on buttons but it would be a nice feature to have.

sudhanshug16 commented 2 months ago

Hi, I want to capture performance marketing parameters like UTMs, gclid, fbclid, etc. I’m using a universal link to open the app, but it seems that the PostHog library doesn’t set properties (e.g., Latest/Initial UTM source) on the user from the universal link, as it does on the web.

How can I achieve this?

darkopia commented 1 month ago

+1 https://posthoghelp.zendesk.com/agent/tickets/18441

elias123tre commented 3 days ago

Hello, i want to add here, i can capture screen events like this in my expo app:

const pathname = usePathname();
const params = useGlobalSearchParams();

useEffect(() => {
  posthog.screen(pathname, {
    ...params,
  });
}, [pathname, params]);

Now, i want to capture screen touches like where users press the most but i think i cannot do it. I only put custom captures on buttons but it would be a nice feature to have.

I settled on using route segments instead so I get screen names like /folder/[id] instead of /folder/123 which fits better for my use case.

const segments = useSegments()
const segmentPath = `/${segments.join("/")}`
const params = useGlobalSearchParams()

useEffect(() => {
  posthog.screen(segmentPath, {
    ...params,
  })
}, [segmentPath, params, posthog])