Have your say in Community Polls: What was/is your greatest motivation to start your own business?
Our Partner & Developer boards on the community are moving to a brand new home: the .dev community forums! While you can still access past discussions here, for all your future app and storefront building questions, head over to the new forums.

Issue with Embedded POS app - AppBridge Cart not fetching data

Solved

Issue with Embedded POS app - AppBridge Cart not fetching data

runTimeZero
Shopify Partner
20 0 0

In my embedded POS application, I am creating a Cart object (on cart page).

However when I perform any actions on the cart I get no response back.

I did verify that I have permissions to access the cart.

 

const AppBridge = window['app-bridge'];
const actions = window['app-bridge'].actions;
const createApp = AppBridge.createApp;
const Cart = actions.Cart;

const app = createApp({
  apiKey: 'foo',  
  shopOrigin: 'foobar.myshopify.com'
});

// Verify that you have permissions to the cart
app.getState().then((state) => {
     console.info('App State: %o', state)
}).catch(error => {
    alert(error);
});

// The above returns this data. Hence I know that I have access to Cart
{
..
Cart: { UPDATE: {Subscribe: true, Dispatch: true}, FETCH: {Subscribe: true, Dispatch: true} .....
}


const cart = Cart.create(app);
cart.subscribe(Cart.Action.FETCH, function (payload) {
   // ---> This callback never executes
      $("#container2").html(JSON.stringify(payload));
});

cart.subscribe(Cart.Action.UPDATE, function (payload) {
   // ---> This callback never executes too
     // do something here
});

// ok let's try this
app.featuresAvailable(Group.Cart).then(function (state) {
  --> this call back doesn't fire too... 
});
cart.dispatch(Cart.Action.FETCH);




I feel like there's something very basic that I am missing. Can someone pls assist.

Accepted Solutions (2)
Henry_Tao
Shopify Staff
91 28 15

This is an accepted solution.

Hi @runTimeZero 

 

Can you try this snippet?

 

const AppBridge = window['app-bridge'];
const actions = window['app-bridge'].actions;
const createApp = AppBridge.createApp;
const Cart = actions.Cart;

const app = createApp({
  apiKey: 'foo',  
  shopOrigin: 'foobar.myshopify.com'
});

const unsubscribe = app.subscribe(Features.ActionType.UPDATE, function () {
app.featuresAvailable(Group.Cart).then((features) => {
const hasFetchCart = features.Cart[Cart.Action.FETCH];
if (hasFetchCart) {
unsubscribe();
const cart = Cart.create(app); 
cart.subscribe(AppBridge.Cart.Action.UPDATE, payload => {
console.log({cart: { payload }});
});
cart.dispatch(Cart.Action.FETCH);
}
});
});

Henry | Social Care @ Shopify 
 - Was my reply helpful? Click Like to let me know! 
 - Was your question answered? Mark it as an Accepted Solution
 - To learn more visit the Shopify Help Center or the Shopify Blog

View solution in original post

Henry_Tao
Shopify Staff
91 28 15

This is an accepted solution.

For context, due to the async loading of all javascript in the page, there is a race condition where the app subscribe to feature update too late. Therefore, it doesn't receive any callback. To solve this, you need to call `featureAvailable` first, check for cart feature, then call subscribe to feature update when necessary. You can try the code below.

 

const isCartEnabled = () => {
  return new Promise((resolve) => {
    const checkCartFeature = () => {
      return app.featuresAvailable(Group.Cart).then((features) => {
        return features.Cart[Cart.Action.FETCH].Dispatch;
      });
    };
    checkCartFeature().then((isEnabled) => {
      if (isEnabled) {
        resolve(true);
      } else {
        const unsubscribe = app.subscribe(
          Features.ActionType.UPDATE,
          function () {
            checkCartFeature().then((isEnabled) => {
              if (isEnabled) {
                resolve(true);
                unsubscribe();
              }
            });
          },
        );
      }
    });
  });
};
isCartEnabled().then((enabled) => {
  if (!enabled) {
    return;
  }
  const cart = Cart.create(app);
  var unsubscriber = cart.subscribe(Cart.Action.UPDATE, function (payload) {
    console.log('cart payload', payload);
    unsubscriber();
  });
  cart.dispatch(Cart.Action.FETCH);
});

 

 

Henry | Social Care @ Shopify 
 - Was my reply helpful? Click Like to let me know! 
 - Was your question answered? Mark it as an Accepted Solution
 - To learn more visit the Shopify Help Center or the Shopify Blog

View solution in original post

Replies 13 (13)

hannachen
Shopify Staff
54 8 17

👋Hi runTimeZero, thanks for sharing this. The code you posted looks to be correct, so I'm unsure why you're not seeing any data being returned.

 

The only thing that looks off to me is when subscribing to `app.featuresAvailable`, I don't see `Group` defined in your code sample, so in this case, you might need something like `actions.Group.Cart` instead for that part to work.

 

Aside from that, I was wondering how you're checking the data that is returned from the cart update events? Are you testing your app using the POS Mobile app? What do you use to inspect the output from console.log()?

Hanna | Shopify 
 - Was my reply helpful? Click Like to let me know! 
 - Was your question answered? Mark it as an Accepted Solution
 - To learn more visit the Shopify Help Center or the Shopify Blog

runTimeZero
Shopify Partner
20 0 0

The way I verify is below:

 

// in my html
<div id="container">

//in my javascript 
app.getState().then((state) => {
    $("#container").html(JSON.stringify(state));
}).catch(error => {
   alert(error);
});

So using actions.Group.Cart  I was able to retrieve information as below:

 

{"Cart":{"UPDATE":{"Subscribe":true,"Dispatch":true},"REMOVE_LINE_ITEM_DISCOUNT":{"Subscribe":true,"Dispatch":true},"FETCH":{"Subscribe":true,"Dispatch":true},"REMOVE_PROPERTIES":{"Subscribe":true,"Dispatch":true},"ADD_LINE_ITEM":{"Subscribe":true,"Dispatch":true},"REMOVE_LINE_ITEM_PROPERTIES":{"Subscribe":true,"Dispatch":true},"REMOVE_DISCOUNT":{"Subscribe":true,"Dispatch":true},"REMOVE_LINE_ITEM":{"Subscribe":true,"Dispatch":true},"SET_LINE_ITEM_PROPERTIES":{"Subscribe":true,"Dispatch":true},"ADD_CUSTOMER_ADDRESS":{"Subscribe":true,"Dispatch":true},"CLEAR":{"Subscribe":true,"Dispatch":true},"SET_DISCOUNT":{"Subscribe":true,"Dispatch":true},"SET_PROPERTIES":{"Subscribe":true,"Dispatch":true},"UPDATE_LINE_ITEM":{"Subscribe":true,"Dispatch":true},"SET_CUSTOMER":{"Subscribe":true,"Dispatch":true},"REMOVE_CUSTOMER":{"Subscribe":true,"Dispatch":true},"SET_LINE_ITEM_DISCOUNT":{"Subscribe":true,"Dispatch":true},"UPDATE_CUSTOMER_ADDRESS":{"Subscribe":true,"Dispatch":true}}}

From my understanding, it seems I do have permissions to access Cart data. However I am still lost as to why none of the callbacks fire.

The below still won't work

 

const cart = Cart.create(app);
cart.subscribe(Cart.Action.FETCH, function (payload) {
$("#container2").html(JSON.stringify(payload));
});
cart.dispatch(Cart.Action.FETCH);

Could you please assist ?

 

 

hannachen
Shopify Staff
54 8 17

That's very curious indeed, because your code looks to be correct. Just to confirm, there's an app link from the POS checkout screen to your app, right? And you're viewing this page after following the link?

 

I tried out your code in my own test app and I had similar issues getting the cart action subscriptions to work at first. But after a few refreshes and app restarts, it seems to be working consistently now. I'm wondering if you might be experiencing something similar? Could you please try refreshing the page from within the POS app by pulling down on the page?

 

Simulator Screen Shot - iPad Air 2 - 2019-09-07 at 14.14.12.png

Hanna | Shopify 
 - Was my reply helpful? Click Like to let me know! 
 - Was your question answered? Mark it as an Accepted Solution
 - To learn more visit the Shopify Help Center or the Shopify Blog

Henry_Tao
Shopify Staff
91 28 15

This is an accepted solution.

Hi @runTimeZero 

 

Can you try this snippet?

 

const AppBridge = window['app-bridge'];
const actions = window['app-bridge'].actions;
const createApp = AppBridge.createApp;
const Cart = actions.Cart;

const app = createApp({
  apiKey: 'foo',  
  shopOrigin: 'foobar.myshopify.com'
});

const unsubscribe = app.subscribe(Features.ActionType.UPDATE, function () {
app.featuresAvailable(Group.Cart).then((features) => {
const hasFetchCart = features.Cart[Cart.Action.FETCH];
if (hasFetchCart) {
unsubscribe();
const cart = Cart.create(app); 
cart.subscribe(AppBridge.Cart.Action.UPDATE, payload => {
console.log({cart: { payload }});
});
cart.dispatch(Cart.Action.FETCH);
}
});
});

Henry | Social Care @ Shopify 
 - Was my reply helpful? Click Like to let me know! 
 - Was your question answered? Mark it as an Accepted Solution
 - To learn more visit the Shopify Help Center or the Shopify Blog

policenauts1
Trailblazer
174 13 40

Hi @Henry_Tao 

 

The code snippet you provided below works when I run it on Android Shopify POS (3.50.0), but it doesn't work when I run it on iOS in the new Shopify POS (iPhone 8, iOS 13, Shopify POS 6.5.0) - hasFetchCart returns false.

 

For iOS, the documented snippet does work (https://shopify.dev/tools/app-bridge/actions/cart), but I can't get it work on Android (Pixel 1, Android 10 running 3.50.0). 

 

Is this a known issue? 

Henry_Tao
Shopify Staff
91 28 15

Hi @policenauts1 I will find someone to help with your question. 

Henry | Social Care @ Shopify 
 - Was my reply helpful? Click Like to let me know! 
 - Was your question answered? Mark it as an Accepted Solution
 - To learn more visit the Shopify Help Center or the Shopify Blog

policenauts1
Trailblazer
174 13 40

Thanks @Henry_Tao. This wouldn't be a big deal if I could detect the device and route accordingly, but I'm also having trouble there (see: https://community.shopify.com/c/Shopify-APIs-SDKs/App-Bridge-Pos-app-getState-pos-device-is-returnin...)

policenauts1
Trailblazer
174 13 40

Hi @Henry_Tao thanks for your help, it looks like your snippet for Cart functions is now working for both iOS and Android.

Henry_Tao
Shopify Staff
91 28 15

FYI, the other issue https://community.shopify.com/c/Shopify-APIs-SDKs/App-Bridge-Pos-app-getState-pos-device-is-returnin... still need to be fixed. I log a ticket for it. 

Henry | Social Care @ Shopify 
 - Was my reply helpful? Click Like to let me know! 
 - Was your question answered? Mark it as an Accepted Solution
 - To learn more visit the Shopify Help Center or the Shopify Blog

SriVathson
Shopify Partner
7 0 1

We also face a similar issue related to this. On our page, the hasFetchCart dispatch object holds the value false. We have used the below code for checking the cart permission.

<body>
	<div id="container2"></div>
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
	<script src="https://unpkg.com/@shopify/app-bridge"></script>
	<script>
		const AppBridge = window['app-bridge'];
		const actions = window['app-bridge'].actions;
		const createApp = AppBridge.createApp;
		const Cart = actions.Cart;
		const Group = actions.Group;
		const Features = actions.Features;
		
		$("#container2").append("<br></br> Start APP <br></br>");

		const app = createApp({
		  apiKey: 'api_key',  
		  shopOrigin: 'shop_origin'
		});

		const unsubscribe = app.subscribe(Features.ActionType.UPDATE, function () { 
			app.featuresAvailable(Group.Cart).then((features) => { 
				$("#container2").append("<br></br> features <br></br>");
				$("#container2").append(JSON.stringify(features));

				const hasFetchCart = features.Cart[Cart.Action.FETCH]; 
				$("#container2").append("<br></br> hasFetchCart <br></br>");
				$("#container2").append(JSON.stringify(hasFetchCart));		
				if (hasFetchCart) { 
					//unsubscribe(); 
					$("#container2").append("<br></br> unsubscribe fetch cart<br></br>");
					// Do something 
					const cart = Cart.create(app); 
					$("#container2").append("<br></br> cart created<br></br>");
					$("#container2").append(JSON.stringify(cart));
					var unsubscriber = cart.subscribe(Cart.Action.UPDATE, function (payload) {
						$("#container2").append("<br></br> unsubscriber<br></br>");
						$("#container2").append(SON.stringify(payload));
						unsubscriber();
					});
					cart.dispatch(Cart.Action.FETCH);
					$("#container2").append("<br></br> unsubscriber after<br></br>");
				} 
			}); 
		});


		$("#container2").append("<br></br>Start END");*/
	</script>
 </body>

 

Then we are getting Output like below

logs.jpeg

What do we need to do to enable the dispatch value to true? Kindly let us know if we are missing anything on our side.

Thanks.

SriVathson
Shopify Partner
7 0 1

Hi @Henry_Tao,

We are still facing problem to get Cart data from our POS embedded app. We have added our app URL using extensions POS Links. Our cart object related Dispatch is false. It looks some thing clear we have missed some access settings. Do we need to get read_all_orders access for access the cart data? As per the documentation read_all_orders access is used to access past 60 days orders. Can you help me with access related issue. Thanks in advance

Henry_Tao
Shopify Staff
91 28 15

Hi @SriVathson 

Your code looks good to me. You don't need `read_all_orders` permission. Either `read_orders` or `write_orders` is fine. Cart feature can only be used in POS Cart screen. It isn't available in other screens like apps list or order detail. Can you send me your app API_KEY or any link that I can verify for you? (DM me if you want). 

Thanks,

Henry | Social Care @ Shopify 
 - Was my reply helpful? Click Like to let me know! 
 - Was your question answered? Mark it as an Accepted Solution
 - To learn more visit the Shopify Help Center or the Shopify Blog

Henry_Tao
Shopify Staff
91 28 15

This is an accepted solution.

For context, due to the async loading of all javascript in the page, there is a race condition where the app subscribe to feature update too late. Therefore, it doesn't receive any callback. To solve this, you need to call `featureAvailable` first, check for cart feature, then call subscribe to feature update when necessary. You can try the code below.

 

const isCartEnabled = () => {
  return new Promise((resolve) => {
    const checkCartFeature = () => {
      return app.featuresAvailable(Group.Cart).then((features) => {
        return features.Cart[Cart.Action.FETCH].Dispatch;
      });
    };
    checkCartFeature().then((isEnabled) => {
      if (isEnabled) {
        resolve(true);
      } else {
        const unsubscribe = app.subscribe(
          Features.ActionType.UPDATE,
          function () {
            checkCartFeature().then((isEnabled) => {
              if (isEnabled) {
                resolve(true);
                unsubscribe();
              }
            });
          },
        );
      }
    });
  });
};
isCartEnabled().then((enabled) => {
  if (!enabled) {
    return;
  }
  const cart = Cart.create(app);
  var unsubscriber = cart.subscribe(Cart.Action.UPDATE, function (payload) {
    console.log('cart payload', payload);
    unsubscriber();
  });
  cart.dispatch(Cart.Action.FETCH);
});

 

 

Henry | Social Care @ Shopify 
 - Was my reply helpful? Click Like to let me know! 
 - Was your question answered? Mark it as an Accepted Solution
 - To learn more visit the Shopify Help Center or the Shopify Blog