braze-inc / braze-web-sdk

Public repo for the Braze Web SDK
https://www.braze.com
Other
71 stars 25 forks source link

[Bug]: subscribeToContentCardsUpdates's callback doesn't get trigger #159

Closed thuandohoang closed 2 months ago

thuandohoang commented 2 months ago

Braze Web SDK Version

8.3.0

Integration Method

NPM

Browser

Chrome

Steps To Reproduce

Hello, I'm integrating Content Card into our website and having an issue with the subscribeToContentCardsUpdates's callback.

Following is our implementation.

  1. We have a useEffect hook to initialize the session

    useEffect(() => {
    // eslint-disable-next-line immutable/no-let
    let subscribeId = '';
    
    // subscribe to content card updates from requestContentCardsRefresh
    import('@braze/web-sdk').then(
      ({
        initialize,
        subscribeToContentCardsUpdates,
        getCachedContentCards,
        changeUser,
        openSession,
      }) => {
        if (!currentUserUuid) {
          return;
        }
        initialize(getBrazeApiKey(), {
          baseUrl: brazeApiUrl,
          enableLogging: true,
          serviceWorkerLocation: '/braze-service-worker.js',
        });
    
        changeUser(currentUserUuid);
        const cards = getCachedContentCards();
        // eslint-disable-next-line no-console
        console.log('🚀 ~ import ~ cards:', cards);
        const card = cards?.cards?.find(c => c.extras.id === cardId);
        if (card && card instanceof ClassicCard) {
          setContentCard(card);
        }
        subscribeId =
          subscribeToContentCardsUpdates((updatedCards: ContentCards) => {
            const updatedCard = updatedCards.cards.find(
              c => c.extras.id === cardId
            );
            // debug braze listener
            // eslint-disable-next-line no-console
            console.log(
              '🚀 ~ subscribeToContentCardsUpdates ~ updatedCards:',
              updatedCards
            );
            // if updated card is undefined, means the campaign has stopped
            setContentCard(updatedCard as ClassicCard | undefined);
          }) ?? '';
        openSession();
      }
    );
    
    return () => removeSubscription(subscribeId || '');
    }, [cardId, currentUserUuid]);

There is a flaky issue that causes, sometimes, the callback of the subscribeToContentCardsUpdates is not called, even if there is a request to fetch cards.

Here is the output from the console, the very first log is the output of getCachedContentCards. It's also weird that the output is undefined, while the docs say that the method returns ContentCards type only.

image

The image below shows a request calling to braze to get the content cards list.

image

Expected Behavior

  1. The callback of subscribeToContentCardsUpdates should be called.
  2. getCachedContentCards shouldn't return undefined

Actual Incorrect Behavior

  1. The callback of subscribeToContentCardsUpdates wasn't called.
  2. getCachedContentCards returned undefined

Verbose Logs

🚀 ~ import ~ cards: undefined
Braze: Initialization Options: {
  "baseUrl": "sdk.iad-05.braze.com",
  "enableLogging": true,
  "serviceWorkerLocation": "/braze-service-worker.js"
}
Braze: Initialized for the Braze backend at "sdk.iad-05.braze.com" with API key "xyxyxy".
Braze: Generating session start event with time 1720517676304. Will expire 1720519476304
Braze: Invoking new session subscriptions
Braze: Changed user to "xyxyxy".
Braze: Upgrading indexedDB AppboyServiceWorkerAsyncStorage to v6...
Braze: Trigger event open did not match any trigger conditions.

Additional Information

No response

smarshamNBC commented 2 months ago

Hi @thuandohoang,

I think you are making the request to get the content cards before the Braze SDK has completed initialising which is why it is undefined in your logs.

For context we have Braze Web SDK implemented in Google Tag Manager on our website and our content card code is built directly in our website code so we were facing a similar issue when attempting to request the cards too early - see here.

Hope the answer provided there may help you with your issue!

thuandohoang commented 2 months ago

Thanks, @smarshamNBC for pointing out the cause. You saved my day.

As we don't have the isInitialized method at the moment, I tried a hacky way by waiting for 2 seconds before calling getCachedContentCards and subscribeToContentCardsUpdates methods and it works now.

smarshamNBC commented 2 months ago

Glad it helped!

I would still advise implementing some logic to check the initialisation has completed as we had some cases where the SDK can take much longer than 2 seconds to init. For us this meant it prevented our app from loading when we made the getCachedContentCards call before Braze had fully initialised.

thuandohoang commented 2 months ago

agree! 2 seconds is just a random number, we can't ensure that it works 100%, sometime it might take longer than 2 seconds.

I think let's keep this issue open until we have logic to check the initialization for tracking purposes.

davidbielik commented 2 months ago

Hi all - our latest version (5.4.0) now supports an isInitialized() method, and window.addEventListener("braze.initialized", () => {}). Thanks for the feedback!