Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

setPersonPropertiesForFlags not called automatically when updating person properties in RN #235

Open
1 of 4 tasks
itsramiel opened this issue Jun 6, 2024 · 4 comments
Open
1 of 4 tasks
Labels
bug Something isn't working react-native Survey

Comments

@itsramiel
Copy link

Bug description

I am using using user properties to match surveys to a specific user. For example i setup a survey to be shown only if survey_shown/{survey_id} is not set as a property on the user.

The issue is that when I set the user property as I capture an event like so:

      posthog.capture('survey shown', {
        $survey_id: survey.id,
        $set: {
          [`survey_shown/${survey.id}`]: true,
        },
      });

and flush the events with await posthog.flush(); the feature flags are not immediately correct and the survey matching is incorrect as a result. It takes some time(second or two) for the feature flags to become correct and correctly match the surveys. This leads to issues where I show the survey multiple times or I dont show a survey that was dependent on the previous survey.

How to reproduce

  1. Create an api survey and set the condition to be survey_shown/{survey if of created survey} is not set
  2. call the following function twice while awaiting each call to ensure flushing occurred:
  const getSurveysAndMarkAsShown = async () => {
    const response = await fetch(`${HOST_URL}/api/surveys?token=${API_KEY}`);
    const json = (await response.json()) as TGetPosthogSurveysResponse;

    const featureFlags = await posthog.reloadFeatureFlagsAsync();
    if (!featureFlags) return;

    const matchingSurveys = getMatchingSurveys(json.surveys, featureFlags);
    console.log('matchingSurveys', matchingSurveys);
    matchingSurveys.forEach(survey => {
      posthog.capture('survey shown', {
        $survey_id: survey.id,
        $set: {
          [`survey_shown/${survey.id}`]: true,
        },
      });
    });

    await posthog.flush();
  };
  
  // ......

  await getSurveysAndMarkAsShown();
  await getSurveysAndMarkAsShown();
  1. Notice that even though in the first call we are setting the user property that we are matching against and we are waiting for the events to be flushed, the same survey is returned in the subsequent call. However in a second or two the survey will no longer be matching(matching took effect)

Related sub-libraries

  • All of them
  • posthog-web
  • posthog-node
  • posthog-react-native

Additional context

Complete App:

import {usePostHog, PostHogProvider} from 'posthog-react-native';
import {Button, StyleSheet, View} from 'react-native';

const HOST_URL = 'your-host';
const API_KEY = 'your-api-key';

function App() {
  return (
    <PostHogProvider
      apiKey={API_KEY}
      options={{
        // usually 'https://us.i.posthog.com' or 'https://eu.i.posthog.com'
        host: HOST_URL, // host is optional if you use https://us.i.posthog.com
      }}>
      <MyComponent />
    </PostHogProvider>
  );
}

export default App;

type TPosthogSurvey = {
  id: string;
  linked_flag_key: string | null;
  targeting_flag_key: string | null;
  questions: Array<{
    type: string;
    choices: Array<string>;
    question: string;
    description?: string;
  }>;
  conditions: {
    selector?: string;
    seenSurveyWaitPeriodInDays?: number;
  } | null;
  start_date: string | null;
  end_date: string | null;
};

function getMatchingSurveys(
  surveys: Array<TPosthogSurvey>,
  featureFlags: {[key: string]: string | boolean},
) {
  return surveys.filter(survey => {
    const isActive =
      typeof survey.start_date === 'string' &&
      typeof survey.end_date !== 'string';
    if (!isActive) return false;

    const linkedFlagCheck = survey.linked_flag_key
      ? !!featureFlags[survey.linked_flag_key]
      : true;

    const targetingFlagCheck = survey.targeting_flag_key
      ? !!featureFlags[survey.targeting_flag_key]
      : true;

    return linkedFlagCheck && targetingFlagCheck;
  });
}

type TGetPosthogSurveysResponse = {
  surveys: Array<TPosthogSurvey>;
};

const MyComponent = () => {
  const posthog = usePostHog();

  const getSurveysAndMarkAsShown = async () => {
    const response = await fetch(`${HOST_URL}/api/surveys?token=${API_KEY}`);
    const json = (await response.json()) as TGetPosthogSurveysResponse;

    const featureFlags = await posthog.reloadFeatureFlagsAsync();
    if (!featureFlags) return;

    const matchingSurveys = getMatchingSurveys(json.surveys, featureFlags);
    console.log('matchingSurveys', matchingSurveys);
    matchingSurveys.forEach(survey => {
      posthog.capture('survey shown', {
        $survey_id: survey.id,
        $set: {
          [`survey_shown/${survey.id}`]: true,
        },
      });
    });

    await posthog.flush();
  };

  const onPress = async () => {
    await getSurveysAndMarkAsShown();
    await getSurveysAndMarkAsShown();
  };

  return (
    <View style={styles.screen}>
      <Button title="get surveys" onPress={onPress} />
    </View>
  );
};

const styles = StyleSheet.create({
  screen: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
});
@itsramiel itsramiel added the bug Something isn't working label Jun 6, 2024
@marandaneto
Copy link
Member

cc @PostHog/team-feature-success

@neilkakkar
Copy link
Contributor

Hi @itsramiel thanks for flagging - it seems like we don't yet handle automatically updating flag props in RN yet.

For now, you can get around this by calling setPersonPropertiesForFlags manually whenever you're adding $set to events - this will keep them in sync properly.

@itsramiel
Copy link
Author

Hey @neilkakkar

That seems to do the job. Do I still need to call flush now or do I drop that from my implementation? It seems to work without it, but interested in knowing what you think

@neilkakkar
Copy link
Contributor

You don't need to flush, but since this is running on the client, I'd recommend flushing anyway (no need to await it though) so you're not losing events for whatever reason (like force quit, etc. etc.). One other reason can be syncing across devices - if the user shows up on both say ios/android/web, and you don't want the survey to show again everywhere, the faster the event makes it in, the faster things will be in sync.

But if this is not a concern, you're all good 👌 .

I'll keep this ticket open anyway for now to implement this bit automatically.

@neilkakkar neilkakkar changed the title Flushing events are not immediately reflected in survey matching setPersonPropertiesForFlags not called automatically when updating person properties in RN Jun 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working react-native Survey
Projects
None yet
Development

No branches or pull requests

3 participants