amplify-js icon indicating copy to clipboard operation
amplify-js copied to clipboard

identifyUser in react and react native on in-app and push notification fail to populate many fields (location, timezone,locale)

Open ericowhadi opened this issue 1 year ago • 4 comments

Before opening, please confirm:

JavaScript Framework

React, React Native

Amplify APIs

Push Notifications

Amplify Version

v6

Amplify Categories

notifications

Backend

Amplify CLI

Environment information

# Put output below this line
  System:
    OS: macOS 13.6.3
    CPU: (8) arm64 Apple M2
    Memory: 32.64 MB / 8.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 20.10.0 - /usr/local/bin/node
    Yarn: 1.22.21 - /usr/local/bin/yarn
    npm: 10.2.3 - /usr/local/bin/npm
    Watchman: 2023.12.04.00 - /opt/homebrew/bin/watchman
  Browsers:
    Chrome: 121.0.6167.160
    Safari: 17.2.1
  npmPackages:
    @aws-amplify/auth: ^6.0.10 => 6.0.15 
    @aws-amplify/auth/cognito:  undefined ()
    @aws-amplify/auth/cognito/server:  undefined ()
    @aws-amplify/auth/enable-oauth-listener:  undefined ()
    @aws-amplify/auth/server:  undefined ()
    @aws-amplify/core: ^6.0.10 => 6.0.15 
    @aws-amplify/core/internals/adapter-core:  undefined ()
    @aws-amplify/core/internals/aws-client-utils:  undefined ()
    @aws-amplify/core/internals/aws-client-utils/composers:  undefined ()
    @aws-amplify/core/internals/aws-clients/cognitoIdentity:  undefined ()
    @aws-amplify/core/internals/aws-clients/pinpoint:  undefined ()
    @aws-amplify/core/internals/providers/pinpoint:  undefined ()
    @aws-amplify/core/internals/utils:  undefined ()
    @aws-amplify/core/server:  undefined ()
    @aws-amplify/ui-react: ^6.0.7 => 6.1.1 
    @aws-amplify/ui-react-internal:  undefined ()
    @aws-amplify/ui-react-notifications: ^2.0.9 => 2.0.9 
    @emotion/react: ^11.11.3 => 11.11.3 
    @emotion/styled: ^11.11.0 => 11.11.0 
    @mui/icons-material: ^5.15.9 => 5.15.9 
    @mui/material: ^5.15.9 => 5.15.9 
    @testing-library/jest-dom: ^5.17.0 => 5.17.0 
    @testing-library/react: ^13.4.0 => 13.4.0 
    @testing-library/user-event: ^13.5.0 => 13.5.0 
    aws-amplify: ^6.0.15 => 6.0.15 
    aws-amplify/adapter-core:  undefined ()
    aws-amplify/analytics:  undefined ()
    aws-amplify/analytics/kinesis:  undefined ()
    aws-amplify/analytics/kinesis-firehose:  undefined ()
    aws-amplify/analytics/personalize:  undefined ()
    aws-amplify/analytics/pinpoint:  undefined ()
    aws-amplify/api:  undefined ()
    aws-amplify/api/server:  undefined ()
    aws-amplify/auth:  undefined ()
    aws-amplify/auth/cognito:  undefined ()
    aws-amplify/auth/cognito/server:  undefined ()
    aws-amplify/auth/enable-oauth-listener:  undefined ()
    aws-amplify/auth/server:  undefined ()
    aws-amplify/datastore:  undefined ()
    aws-amplify/in-app-messaging:  undefined ()
    aws-amplify/in-app-messaging/pinpoint:  undefined ()
    aws-amplify/push-notifications:  undefined ()
    aws-amplify/push-notifications/pinpoint:  undefined ()
    aws-amplify/storage:  undefined ()
    aws-amplify/storage/s3:  undefined ()
    aws-amplify/storage/s3/server:  undefined ()
    aws-amplify/storage/server:  undefined ()
    aws-amplify/utils:  undefined ()
    firebase: ^10.8.0 => 10.8.0 
    firebase/analytics:  undefined ()
    firebase/app:  undefined ()
    firebase/app-check:  undefined ()
    firebase/auth:  undefined ()
    firebase/auth/cordova:  undefined ()
    firebase/auth/web-extension:  undefined ()
    firebase/compat:  undefined ()
    firebase/compat/analytics:  undefined ()
    firebase/compat/app:  undefined ()
    firebase/compat/app-check:  undefined ()
    firebase/compat/auth:  undefined ()
    firebase/compat/database:  undefined ()
    firebase/compat/firestore:  undefined ()
    firebase/compat/functions:  undefined ()
    firebase/compat/installations:  undefined ()
    firebase/compat/messaging:  undefined ()
    firebase/compat/performance:  undefined ()
    firebase/compat/remote-config:  undefined ()
    firebase/compat/storage:  undefined ()
    firebase/database:  undefined ()
    firebase/firestore:  undefined ()
    firebase/firestore/lite:  undefined ()
    firebase/functions:  undefined ()
    firebase/installations:  undefined ()
    firebase/messaging:  undefined ()
    firebase/messaging/sw:  undefined ()
    firebase/performance:  undefined ()
    firebase/remote-config:  undefined ()
    firebase/storage:  undefined ()
    react: ^18.2.0 => 18.2.0 
    react-dom: ^18.2.0 => 18.2.0 
    react-hot-toast: ^2.4.1 => 2.4.1 
    react-scripts: 5.0.1 => 5.0.1 
    uuid: ^9.0.1 => 9.0.1 (8.3.2)
    web-vitals: ^2.1.4 => 2.1.4 
  npmGlobalPackages:
    @aws-amplify/cli: 12.10.0
    http-server: 14.1.1

Describe the bug

I am using both in-app and push notification on a react native and a react webapp. Of course the push notification on react web app is not don eusing amplify since it is not supported, but I wired it manually using firebase and a lamda that proxy a call to pinpoint updateEndpoint API. When using the api of updateUser from aws-amplify/in-app-messaging or from aws-amplify/push-notifications both api even if returning success, fail to internally update pinpoint fields that a direct call to pinpoint updateEndpoint API successfully update. These fields are: demographic.locale demographic.timezone location.latitude location.longitude location.city location.country location.postalCode location.region

Expected behavior

All these field should be correctly populating the Pinpoint internal database. Else not campaign targeting these field will work

Reproduction steps

follow direction to install and configure ether amplify push notification on react native, or in-app notifications in ether react or react-native. Then, invoke identifyUser in ether in-app or push-notifications. make sure you populate the demographic and location that are reported buggy. And then go to pinpoint console, segment, export segment. THen look at the excelsheet, and see that all the boggus fields are indeed blank. I have verified that directly invoking pinpoint updateEndpoint API , I correctly populate these fields and they do show up on the exported endpoints collected as mentioned above via pinpoint console.

Code Snippet

// Put your code below this line.

mport React , {useState,useEffect} from 'react';
import {fetchUserAttributes} from '@aws-amplify/auth'
import { Authenticator, useAuthenticator} from '@aws-amplify/ui-react';
import '@aws-amplify/ui-react/styles.css';
import {syncMessages, identifyUser} from 'aws-amplify/in-app-messaging'
import {withInAppMessaging} from '@aws-amplify/ui-react-notifications'
import Dashboard from './dashboard/Dashboard.js'
import Notification from './components/Notification'
import {v4 as uuidv4} from 'uuid'
import {generateClient} from 'aws-amplify/api'
import {pinpointGateway} from "./graphql/mutations"

const client = generateClient()

function App() {
  const { user } = useAuthenticator((context) => [context.user]);
  const { route } = useAuthenticator((context) => [context.route]);


  console.log("user",user)
  console.log("route", route)


  const [userDetails, setUserDetails] = useState(null);
  const [errorMessage, setErrorMessage] = useState(null)
  const [pushToken, setPushToken] = useState(null)

  useEffect(() => {
    const params = new URLSearchParams(window.location.search);
    const errorDescription = params.get('error_description');
    if (errorDescription) {
      setErrorMessage(errorDescription.startsWith("PreSignUp failed with error . ")?errorDescription.substring(30):errorDescription);
    }
 
  }, []);



  useEffect(() => {
    const fetchUserDetails = async () => {
      try {
        const userData = await fetchUserAttributes();
        setUserDetails(userData);

        // Now userDetails contains more detailed information
      } catch (error) {
        console.error('Error fetching user details', error);
      }
    };

    if (route === "authenticated") fetchUserDetails();
    else setUserDetails(null)
  }, [route]);

  useEffect(()=>{
  const identifyUserInput = async () => {
    let location = {}
    if (navigator.geolocation){
      navigator.geolocation.getCurrentPosition((position)=>{
        location = {latitude: position.coords.latitude,
        longitude: position.coords.longitude
        }
      }, (error)=>{
        console.log("Location permission denied")
      })
    } else{
      console.log("Geolocation is not supported by this browser.")
    }
    return {
    userId: userDetails.sub,
    userProfile: {
      email: userDetails.email,
      name: userDetails.name,
      plan:'myplan',
      customProperties:{
        hobbies: ["paintball", "bridge"] //~~EO todo
      }
  },
  demographic:{
    appVersion: "1.0.0",
    locale: navigator.language.replace("-","_"), //~~EO todo add what we support as filter
    make: navigator.vendor,
    model: navigator.appCodeName,
    modelVersion: navigator.appVersion.substring(0,50),
    platform: navigator.platform,
    platformVersion: "",
    timezone: Intl.DateTimeFormat().resolvedOptions().timeZone

  },
  location: {
    latitude: 10.12345,//location.latitude,
    longitude: -2.12345,//location.longitude,
    city: "Tomball",
    country:"US",
    postalCode:"77377",
    region:"TEXAS",


  },
  metrics:{
    // you app specific metrics  todo
  },
  options:{
    address: userDetails.email, //E.g. A device token or email address
    optOut:"NONE", //Either ALL or NONE
    userAttributes: {
      interests: ['belotte','rami']
    }
  }
  }
  } 

  const dealWithPushNotification = async ()=>{

    const identifiedUserInput =await identifyUserInput()
    console.log("identified user:",identifiedUserInput)
    await identifyUser(identifiedUserInput)

      if (pushToken !== 'error') {

        
        const res= await client.graphql({
          query: pinpointGateway,
          variables:{
            functionName: "updateEndpoint",
            functionParams:JSON.stringify(
              {EndpointId: "test",
              EndpointRequest:{

              Demographic:{
                AppVersion: identifiedUserInput.demographic.appVersion,
                Locale: identifiedUserInput.demographic.locale,
                Make: identifiedUserInput.demographic.make,
                Model: identifiedUserInput.demographic.model,
                ModelVersion: identifiedUserInput.demographic.modelVersion,
                Platform: identifiedUserInput.demographic.platform,
                PlatformVersion: identifiedUserInput.demographic.platformVersion,
                Timezone: identifiedUserInput.demographic.timezone
            
              },
              Location: {
                Latitude: identifiedUserInput.location.latitude,
                Longitude: identifiedUserInput.location.longitude,
                City: identifiedUserInput.location.city,
                Country:identifiedUserInput.location.country,
                PostalCode:identifiedUserInput.location.postalCode,
                Region:identifiedUserInput.location.region,
            
            
              },
              Metrics: identifiedUserInput.metrics,
              Address: pushToken,
              OptOut: "NONE",
              Attributes: {
                  email:[identifiedUserInput.userProfile.email],
                  name: [identifiedUserInput.userProfile.name],
                  plan: [identifiedUserInput.userProfile.plan],
                  ...identifiedUserInput.userProfile.customProperties

              },
              User:{
                UserId: identifiedUserInput.userId,
                UserAttributes: identifiedUserInput.options.userAttributes
                
              },
              RequestId: uuidv4()

            }
          })
          },
          authMode: "iam"
        })
        console.log(res)

      }
      
      syncMessages()
      console.log("DONE")

  }

  if (userDetails && pushToken) dealWithPushNotification()

},[userDetails,pushToken])

  const clearErrorAndRefresh = () => {
    window.location.href = window.location.pathname;
  };

    // If there is an error, display a separate UI
    if (errorMessage) {
      return (
        <div style={{display:"flex", justifyContent:"center", alignItems:"center", height:"100vh", width:"100vw"}}>
        <div className="amplify-flex amplify-alert amplify-alert--error" role="alert" style={{width:"450px", backgroundColor:"#fce9e9"}}>
          <span className="amplify-alert__icon">
            <span className="amplify-icon" aria-hidden="true" style={{width: "1em", height: "1em"}}>
              <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
                <path d="M12 2C6.48 2 2 6.48 2 12C2 17.52 6.48 22 12 22C17.52 22 22 17.52 22 12C22 6.48 17.52 2 12 2ZM13 17H11V15H13V17ZM13 13H11V7H13V13Z" fill="currentColor">
                </path>
              </svg>
            </span>
          </span>
          <div style={{flex: "1 1 0%"}}>
            <div className="amplify-alert__body">{errorMessage}</div>
          </div>
          <button aria-label="Dismiss alert" className="amplify-button amplify-field-group__control amplify-button--link amplify-alert__dismiss" type="button" onClick={clearErrorAndRefresh} >
          <span className="amplify-icon" aria-hidden="true" style={{width: "1em",height: "1em"}}>
            <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
            <path d="M19 6.41L17.59 5L12 10.59L6.41 5L5 6.41L10.59 12L5 17.59L6.41 19L12 13.41L17.59 19L19 17.59L13.41 12L19 6.41Z" fill="currentColor"></path>
            </svg>
          </span>
          </button>
        </div>
        </div>
      );
    }

  return (
    <Authenticator>
       
      {({ signOut, user }) => {
        console.log("user",user)
        console.log("userDetails",userDetails)
        return (<>
          <Notification pushTokenCallback={setPushToken}/>
          <Dashboard signOut={signOut} user={user}/>
      </>)}}
    </Authenticator>
  );
}

export default withInAppMessaging(App);



### Log output

<details>

// Put your logs below this line


</details>


### aws-exports.js

_No response_

### Manual configuration

_No response_

### Additional configuration

_No response_

### Mobile Device

_No response_

### Mobile Operating System

_No response_

### Mobile Browser

_No response_

### Mobile Browser Version

_No response_

### Additional information and screenshots

_No response_

ericowhadi avatar Feb 13 '24 01:02 ericowhadi

Hello, @ericowhadi and sorry to hear your'e running into this. Can you clarify if this is being experienced with Apple Push Notification service (APNs), Firebase Cloud Messaging (FCM), or both? Also, can you double check that the required credentials have been input for your desired service channel within the Pinpoint console? Should be able to verify this under the project > Configure features > Push Notifications > service provider.

cwomack avatar Feb 13 '24 20:02 cwomack

the issue exist on both APNs and FCM and on in-app messaging (both react native and react). The credentials are OK and correct, as all other information provided in identifyUser are making it correctly to pinpoint. only all location info, plus locale and timezone from demographic are not transmitted.

ericowhadi avatar Feb 13 '24 21:02 ericowhadi

note that for APN, I have not yet enabled APNs backend, but the identifyUser workflow is independent of the push notification service provider. Service provider is important to receive the token, and then the identify user update the pinpoint Endpoint with the token in the address field. on Apple, because I don't yet have my DUNS number to create a valid apple developper account that can enable the APN service I have not tested really end to end. However, I know it fails because calling the IdentifyUser with a fake token does correctly update the Endpoint with the fake token, along with many other attributes, except the failed ones.

ericowhadi avatar Feb 13 '24 21:02 ericowhadi

update, actually, after more testing, it is more than I previously said. All the demographic values are wrong (not populated). I saw that looking at android push notification from both emulator and real device pixel 7, none of the data about demographics gets updated, and for both device I am getting the same values in pinpoint: Default values: Demographic.ModelVersion: 34 Demographic.AppVersion: android/34 Demographic.Platform: android

ericowhadi avatar Feb 15 '24 01:02 ericowhadi

Hi @ericowhadi, thanks for providing the code snippet. I notice that the demographic, metrics and location object blocks are outside the userProfile block in your identifyUserInput. Can you move inside and see if you still face the problem?

It should be as shown in the docs: https://docs.amplify.aws/javascript/build-a-backend/more-features/in-app-messaging/identify-user/

For a quick review:

const identifyUserInput = {
  userId: '', // E.g. user-id
  userProfile: {
    email: '', // E.g. [email protected]
    name: '', // E.g. name-of-the-user
    plan: '' // E.g. plan-they-subscribe-to
    customProperties: {
      // E.g. hobbies: ['cooking', 'knitting'],
    },
    demographic: {
      appVersion: '',
      locale: '', // E.g. en_US
      make: '', // E.g. Apple
      model: '', // E.g. iPhone
      modelVersion: '', // E.g. 13
      platform: '', // E.g. iOS
      platformVersion: '', // E.g. 15
      timezone: '' // E.g. Americas/Los_Angeles
    },
    location: {
      city: '', // E.g. Seattle
      country: '', // E.g. US,
      postalCode: '', // E.g. 98121
      region: '', // E.g. WA
      latitude: 0.0,
      longitude: 0.0
    },
    metrics: {
      // E.g. logins: 157
    },
  },
};

Samaritan1011001 avatar Feb 29 '24 01:02 Samaritan1011001

@Samaritan1011001 oops, my bad, I should be more careful following the docs. Sorry again, and thanks for catching my mistake. After correcting it everything works as expected.

ericowhadi avatar Mar 04 '24 17:03 ericowhadi