Shared user session between the shop and a standalone app on a subdomain?

Quick questions: my client wants to add a fancy contest/gallery feature, so I suggested we build a standalone with a custom stack and use the storefront API.

Main shop → farmshop (running on a regular Shopify theme)

Subdomain contest running on a separate stack → contest.farmshop

I know we can manage carts, etc. via → Create and update a cart with the Storefront API

Here’s the setup for my question:

  1. A customer is logged in to the main shop and has products in their cart.
  2. They then jump over and enter the contest.
  3. On the contest site, we offer products related to their entry.
  4. The customer adds a contest product ???

Question → At step 4, how do I identify the customer and their cart without having to authenticate the user again on the contest.farmshop.com ?

Can I access the user session from the main shop via the subdomain?

My client wants this process to be seamless as the user jumps back and forth between the contest.farmshop.com and farmshop.com, and to maintain the cart with its current contents + whatever is added via the contest.

I’ve built complete standalone apps before, but I haven’t tried tying a standalone app to a regular shop, so any insights are appreciated.

Thanks

Hi Justin,

Is the subdomain a hard requirement? Would any of these formats work?

  • farmshop.com/apps/contest
  • farmshop.com/a/contest
  • farmshop.com/community/contest
  • farmshop.com/tools/contest

App proxies fit this use case well if the subdomain isn’t required: About app proxies and dynamic data

Interesting, I didn’t know about that. Thanks.

It’s not a direct Shopify app but a third party HTMX application running on a different server. That’s the only reason I thought subdomain.

I don’t think this case will apply, but I learned something new.

Got it, so a lot less like a theme app extension and more of an actual standalone app on a subdomain. In that case, how do these options sound?

Cart, option 1: Cart permalink

The contest app maintains its own Storefront API cart. When the customer leaves the subdomain, redirect with a cart permalink to add contest items to their existing cart.

Pros:

  • Can direct to storefront instead of checkout.

Cons:

  • Line item properties only apply to the first product in the cart (max 25).
  • URL length cap.

Cart, option 2: Shared cookie + Storefront API cart swap

Store a copy of the shop’s cart items in a cookie on .farmshop.com. The contest app reads the cookie and uses the Storefront API to build a new cart with both shop and contest items. When the customer leaves the subdomain, redirect with the cart’s checkoutUrl. The shop adopts the new cart and moves into checkout.

Pros:

  • Properties can apply to multiple line items.

Cons:

  • The customer goes straight to checkout.
  • Cookie size cap).

Customer identity

If the contest site needs to identify the customer, use the Customer Account API for OAuth.

That’s amazing information, thank you. The cart permalink was my thought as well.

To provide full context, here’s an example of the concept: Community Garden Gallery

Currently, their shop is running on the Liquid theme, but I don’t think Liquid supports a customer-generated community garden entry or data type.

My thoughts are that this functionality is only feasible via:

  1. Hydrogen or Shopify app (probably mapped to a metaobject data or custom data type)

  2. Or a standalone app as I’ve suggested.

Ultimately, the clients would like the community garden integrated with the shop.

I said the only way to do this would be to build a headless Hydrogen application that combines the shop and community gardens into a single application.

Does that sound correct?

I appreciate your help and thank you for your time.

Looking at the concept site, I’m thinking your client’s goal would be better addressed with a theme app extension + app proxy after all. A Liquid theme can definitely power a customer-generated gallery, the issue is that it can only display this content, not accept it. That’s where your app can come in via an app proxy.

  • Metaobjects for the custom data: Image submissions and votes can be tied to the product, so they live in a public context that renders to everyone. A separate customer metaobject then holds the IDs of the submissions and votes that belong to each customer, which ties ownership back to them.
  • Theme app extension: Renders the gallery in Liquid from the metaobjects, and handles lighter interactivity which can stay in Liquid or run client-side.
  • App handles the writes: Liquid can’t accept uploads or write data, so submissions and votes are triggered from the storefront but routed to your app through the proxy. The app saves the photo as a Shopify file and creates the metaobject entries via the Admin API.
  • Add to cart: Use the Cart AJAX API as normal, no permalinks or cross-domain workarounds. Gating to logged-in customers can be a plain Liquid check as well:
{% if customer %}
  <button class="add-to-cart" data-variant-id="{{ variant_id }}">Add to cart</button>
{% else %}
  <a href="{{ routes.storefront_login_url }}">Log in to add to cart</a>
{% endif %}

Ok, I like that idea thanks. The one question regarding this point:

Metaobjects for the custom data: Image submissions and votes can be tied to the product, so they live in a public context that renders to everyone.

When you say tied to the product - do you mean create a separate metaobject data group to save (photos , votes etc):

And tag to products via ID → metaobject.products = productID or IDs?

OR

The data is saved right to the product as additional Metaobject fields?

in this case If the customer tags two or more different plant varieties then both products need to be tagged?

Thanks, again.

I was thinking you could have a product metafield that references metaobject entries from your community garden metaobject.

But really up to you on how you want to structure the data :slight_smile:

Cool idea.

Thanks again for the help! I have a way better understanding of the implementation now. Cheers and good day :-):slightly_smiling_face: