Proud lock by Flickr user Holly Norval

Working with embedded content in iframes is always tricky, especially when data sharing is required. We recently had to find solutions to some unforeseen gotchas that we’d like to share here. Hopefully we can help other developers avoid running into these same problems.

Over the past several months, we’ve been building a pair of cannabis apps for a client. The customer-facing app gives users the ability to see real-time inventory at local stores and place orders, while the business-facing app allows those stores to process orders and manage inventory. In the course of onboarding stores for the business app, we found that many had no means of displaying a live menu on their own websites and asked if we could build an embeddable version of the menu from our customer app. While it would be relatively simple to show a non-interactive menu, we knew we could create a much better experience if we allowed users to build carts within the embedded menu and proceed to the customer app at checkout time.

We decided to build the embeddable menu within the existing customer app, which allowed us to reuse the existing functionality for displaying menus, searching for products, and building carts. The app allows users to build carts without creating accounts; carts are kept in local storage and only transmitted to the server once the user tries to check out, at which point they are required to verify their age and create an account. It didn’t make sense to force users to create accounts while using the embedded menu, so we added a ‘continue to checkout’ button that linked to the cart page of the customer app. The challenge was to ensure that the cart would be available for checkout once they clicked through to the customer app.

We hoped that because the embedded menu shared the same domain as the customer app, a cart made within an iframe at a store website would be available in local storage in the customer app. We tested this on desktop Chrome and Safari, and everything worked just as expected. The embedded cart was available in local storage once the user clicked through to the customer app, and the entire checkout flow succeeded. When we tried it on mobile devices, however, the cart was nowhere to be found. Although both desktop browsers allow sharing of local storage for ‘www.myapp.com’, neither does on mobile. Any value saved to the local storage of ‘www.myapp.com’ inside an iframe will not be accessible in mobile browsers. After realizing this, we tried storing the cart in a cookie using document.cookie and found the same problem. Both desktop Chrome and Safari handled setting the cookie in the iframe and getting it in the customer app with no trouble, but neither mobile browser would read it in the customer app. Although we specified the ‘path’ and ‘domain’ attributes for the cookie, the mobile browsers would not recognize a cookie set in the embedded app as having the correct ‘path’, and therefore could not access the cookie.

Ultimately, we were able to solve the problem by converting a minimal representation of the cart into a query string and linking from the embedded menu to ‘www.myapp.com/cart?cart=”{“stringified cart”}”’. Once the customer app loaded, we parsed the query string and processed it just as we would with a cart created in the customer app. A typical cart for our app can be represented with about 100 - 200 characters and modern browsers allow very long URLs, so space is not an issue. All browsers support consistent parsing of query strings, to this turned out to be an effective solution. We hope this helps you next time you’re in a similar situation.

Main image from Flickr user Holly Norval.