{"id":936,"date":"2026-04-28T17:00:00","date_gmt":"2026-04-28T22:00:00","guid":{"rendered":"https:\/\/tolinku.com\/blog\/?p=936"},"modified":"2026-03-07T03:48:47","modified_gmt":"2026-03-07T08:48:47","slug":"shopify-app-deep-links","status":"publish","type":"post","link":"https:\/\/tolinku.com\/blog\/shopify-app-deep-links\/","title":{"rendered":"Deep Linking for Shopify Mobile Apps"},"content":{"rendered":"\n<p>If you have a Shopify store and a native mobile app (built with Shopify&#39;s Hydrogen, a custom native app, or a mobile app builder), deep links connect your marketing channels directly to the app&#39;s product pages. Without deep linking, your marketing links send users to the Shopify web store, missing the higher conversion rates and better experience of your native app.<\/p>\n\n\n\n<p>For the broader e-commerce deep linking approach, see <a href=\"https:\/\/tolinku.com\/blog\/deep-linking-ecommerce-apps\/\">Deep Linking for E-Commerce Apps<\/a>. For product page linking, see <a href=\"https:\/\/tolinku.com\/blog\/product-page-deep-links\/\">Product Page Deep Links<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Shopify URL Structure<\/h2>\n\n\n\n<p>Shopify stores use predictable URL patterns:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table>\n<thead>\n<tr>\n<th>Content Type<\/th>\n<th>Shopify Web URL<\/th>\n<th>Deep Link Pattern<\/th>\n<\/tr>\n<\/thead>\n<tbody><tr>\n<td>Product<\/td>\n<td><code>\/products\/running-shoes-v2<\/code><\/td>\n<td><code>\/product\/running-shoes-v2<\/code><\/td>\n<\/tr>\n<tr>\n<td>Collection<\/td>\n<td><code>\/collections\/summer-sale<\/code><\/td>\n<td><code>\/collection\/summer-sale<\/code><\/td>\n<\/tr>\n<tr>\n<td>Cart<\/td>\n<td><code>\/cart<\/code><\/td>\n<td><code>\/cart<\/code><\/td>\n<\/tr>\n<tr>\n<td>Checkout<\/td>\n<td><code>\/checkouts\/...<\/code><\/td>\n<td><code>\/checkout<\/code><\/td>\n<\/tr>\n<tr>\n<td>Page<\/td>\n<td><code>\/pages\/about-us<\/code><\/td>\n<td><code>\/page\/about-us<\/code><\/td>\n<\/tr>\n<tr>\n<td>Blog post<\/td>\n<td><code>\/blogs\/news\/latest-update<\/code><\/td>\n<td><code>\/blog\/latest-update<\/code><\/td>\n<\/tr>\n<tr>\n<td>Account<\/td>\n<td><code>\/account<\/code><\/td>\n<td><code>\/account<\/code><\/td>\n<\/tr>\n<tr>\n<td>Order<\/td>\n<td><code>\/account\/orders\/12345<\/code><\/td>\n<td><code>\/order\/12345<\/code><\/td>\n<\/tr>\n<\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Mapping Shopify URLs to Deep Links<\/h3>\n\n\n\n<p>Your deep links don&#39;t have to mirror Shopify&#39;s URL structure exactly. Create a mapping that makes sense for your app:<\/p>\n\n\n\n<pre><code>Shopify: https:\/\/yourstore.myshopify.com\/products\/running-shoes-v2\nDeep link: https:\/\/go.yourapp.com\/product\/running-shoes-v2\n<\/code><\/pre>\n\n\n\n<p>The key is that the deep link contains enough information to identify the product. Use the Shopify product handle (the URL slug) as the identifier; it&#39;s human-readable and stable.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Setting Up Deep Link Routes<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Product Routes<\/h3>\n\n\n\n<p>Create a dynamic route for products:<\/p>\n\n\n\n<pre><code>Path: \/product\/:handle\nWeb fallback: https:\/\/yourstore.com\/products\/{handle}\n<\/code><\/pre>\n\n\n\n<p>When <code>https:\/\/go.yourapp.com\/product\/running-shoes-v2<\/code> is tapped:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>App installed<\/strong>: Opens the app, fetches product by handle from Shopify&#39;s API, displays it<\/li>\n<li><strong>App not installed<\/strong>: Redirects to <code>https:\/\/yourstore.com\/products\/running-shoes-v2<\/code><\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Collection Routes<\/h3>\n\n\n\n<pre><code>Path: \/collection\/:handle\nWeb fallback: https:\/\/yourstore.com\/collections\/{handle}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Search Routes<\/h3>\n\n\n\n<pre><code>Path: \/search\nQuery parameters: ?q=shoes&amp;sort=price\nWeb fallback: https:\/\/yourstore.com\/search?q={q}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Cart\/Checkout Routes<\/h3>\n\n\n\n<pre><code>Path: \/cart\/add\nQuery parameters: ?items=VARIANT_ID:QTY,VARIANT_ID:QTY\nWeb fallback: https:\/\/yourstore.com\/cart\n<\/code><\/pre>\n\n\n\n<p>Note: Shopify uses variant IDs, not product IDs, for cart operations. Each product variant (size, color combination) has a unique numeric ID.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">App-Side Implementation<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Fetching Products by Handle<\/h3>\n\n\n\n<p>When your app receives a deep link to <code>\/product\/running-shoes-v2<\/code>, it needs to fetch the product from Shopify.<\/p>\n\n\n\n<p><strong>Using Shopify Storefront API (GraphQL):<\/strong><\/p>\n\n\n\n<pre><code class=\"language-graphql\">query ProductByHandle($handle: String!) {\n  product(handle: $handle) {\n    id\n    title\n    description\n    images(first: 5) {\n      edges {\n        node {\n          url\n          altText\n        }\n      }\n    }\n    variants(first: 20) {\n      edges {\n        node {\n          id\n          title\n          price {\n            amount\n            currencyCode\n          }\n          availableForSale\n        }\n      }\n    }\n  }\n}\n<\/code><\/pre>\n\n\n\n<p><strong>React Native example:<\/strong><\/p>\n\n\n\n<pre><code class=\"language-javascript\">function ProductScreen({ route }) {\n  const { handle } = route.params;\n  const [product, setProduct] = useState(null);\n\n  useEffect(() =&gt; {\n    fetchProductByHandle(handle).then(setProduct);\n  }, [handle]);\n\n  if (!product) return &lt;LoadingScreen \/&gt;;\n\n  return &lt;ProductDetail product={product} \/&gt;;\n}\n\nasync function fetchProductByHandle(handle) {\n  const response = await fetch(SHOPIFY_STOREFRONT_URL, {\n    method: &#39;POST&#39;,\n    headers: {\n      &#39;Content-Type&#39;: &#39;application\/json&#39;,\n      &#39;X-Shopify-Storefront-Access-Token&#39;: STOREFRONT_TOKEN,\n    },\n    body: JSON.stringify({\n      query: PRODUCT_BY_HANDLE_QUERY,\n      variables: { handle },\n    }),\n  });\n  const data = await response.json();\n  return data.data.product;\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Adding to Cart via Deep Link<\/h3>\n\n\n\n<p>When a cart deep link arrives:<\/p>\n\n\n\n<pre><code>https:\/\/go.yourapp.com\/cart\/add?items=41234567890:2,41234567891:1\n<\/code><\/pre>\n\n\n\n<p>Parse the variant IDs and quantities, then add to cart:<\/p>\n\n\n\n<pre><code class=\"language-javascript\">function handleCartDeepLink(url) {\n  const parsed = new URL(url);\n  const itemsParam = parsed.searchParams.get(&#39;items&#39;);\n\n  if (itemsParam) {\n    const items = itemsParam.split(&#39;,&#39;).map(item =&gt; {\n      const [variantId, qty] = item.split(&#39;:&#39;);\n      return { variantId, quantity: parseInt(qty, 10) };\n    });\n\n    \/\/ Add each item to Shopify cart\n    for (const item of items) {\n      cartStore.addItem(item.variantId, item.quantity);\n    }\n\n    navigation.navigate(&#39;Cart&#39;);\n  }\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Handling Product Variants in Deep Links<\/h3>\n\n\n\n<p>If a deep link should open a specific variant (size, color):<\/p>\n\n\n\n<pre><code>https:\/\/go.yourapp.com\/product\/running-shoes-v2?variant=41234567890\n<\/code><\/pre>\n\n\n\n<p>Or using human-readable options:<\/p>\n\n\n\n<pre><code>https:\/\/go.yourapp.com\/product\/running-shoes-v2?color=black&amp;size=10\n<\/code><\/pre>\n\n\n\n<p>The app matches the options to the correct variant:<\/p>\n\n\n\n<pre><code class=\"language-javascript\">function findVariant(product, color, size) {\n  return product.variants.find(v =&gt;\n    v.selectedOptions.some(o =&gt; o.name === &#39;Color&#39; &amp;&amp; o.value === color) &amp;&amp;\n    v.selectedOptions.some(o =&gt; o.name === &#39;Size&#39; &amp;&amp; o.value === size)\n  );\n}\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Shopify Mobile App Builders<\/h2>\n\n\n\n<p>If you&#39;re using a Shopify mobile app builder (Tapcart, Shopney, MageNative, etc.), check whether the builder supports:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Custom deep link domains<\/strong>: Can you use <code>go.yourapp.com<\/code> instead of the builder&#39;s domain?<\/li>\n<li><strong>Dynamic routing<\/strong>: Does the app resolve Shopify product handles from URLs?<\/li>\n<li><strong>Deferred deep linking<\/strong>: Do first-time installs get routed to the right product?<\/li>\n<\/ul>\n\n\n\n<p>Most app builders provide some level of deep linking, but the implementation quality varies. If deep linking is a primary use case, verify the builder&#39;s capabilities before committing.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Marketing Channel Integration<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Email Campaigns (Klaviyo, Mailchimp)<\/h3>\n\n\n\n<p>Shopify merchants commonly use Klaviyo or Mailchimp for email marketing. Replace web product URLs with deep links in email templates:<\/p>\n\n\n\n<pre><code>Web URL: https:\/\/yourstore.com\/products\/running-shoes-v2\nDeep link: https:\/\/go.yourapp.com\/product\/running-shoes-v2?utm_source=email&amp;utm_campaign=weekly\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">SMS Marketing (Postscript, Attentive)<\/h3>\n\n\n\n<p>SMS links are tapped directly from the Messages app, which supports Universal Links:<\/p>\n\n\n\n<pre><code>New arrival! Check out our Running Shoes V2:\nhttps:\/\/go.yourapp.com\/product\/running-shoes-v2\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Shopify Abandoned Cart Emails<\/h3>\n\n\n\n<p>Shopify sends automatic abandoned cart emails. By default, these link to the web checkout. To deep link to your app&#39;s cart instead:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Customize the abandoned cart email template in Shopify<\/li>\n<li>Replace the checkout URL with a deep link to your app&#39;s cart<\/li>\n<li>Include the checkout token or cart items in the URL<\/li>\n<\/ol>\n\n\n\n<pre><code>https:\/\/go.yourapp.com\/cart?recover=true&amp;checkout_token=ABC123\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Facebook and Instagram Ads<\/h3>\n\n\n\n<p>When creating ads via Shopify&#39;s marketing tools or Facebook Ads Manager:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Set the destination URL to your deep link<\/li>\n<li>The web fallback should be the Shopify product page<\/li>\n<li>Enable deferred deep linking for app install ads<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">Product Feed Synchronization<\/h2>\n\n\n\n<p>If you generate deep links from your Shopify product catalog, automate the process:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Shopify Webhook Approach<\/h3>\n\n\n\n<p>Listen for Shopify product webhooks to generate deep links:<\/p>\n\n\n\n<pre><code class=\"language-javascript\">\/\/ When a new product is created\napp.post(&#39;\/webhooks\/shopify\/product-create&#39;, (req, res) =&gt; {\n  const product = req.body;\n  const deepLink = `https:\/\/go.yourapp.com\/product\/${product.handle}`;\n\n  \/\/ Create route on your deep linking platform\n  createRoute({\n    path: `\/product\/${product.handle}`,\n    webFallback: `https:\/\/yourstore.com\/products\/${product.handle}`,\n    ogTitle: product.title,\n    ogDescription: product.body_html?.substring(0, 160),\n    ogImage: product.images[0]?.src,\n  });\n\n  res.sendStatus(200);\n});\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Bulk Sync<\/h3>\n\n\n\n<p>For initial setup, sync all existing products:<\/p>\n\n\n\n<pre><code class=\"language-javascript\">async function syncAllProducts() {\n  let products = await shopify.product.list({ limit: 250 });\n\n  while (products.length &gt; 0) {\n    for (const product of products) {\n      await createDeepLinkRoute(product);\n    }\n    products = await shopify.product.list({\n      limit: 250,\n      since_id: products[products.length - 1].id,\n    });\n  }\n}\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Handling Shopify-Specific Edge Cases<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Product Availability<\/h3>\n\n\n\n<p>Shopify products can be:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Active<\/strong>: Available for purchase<\/li>\n<li><strong>Draft<\/strong>: Not published<\/li>\n<li><strong>Archived<\/strong>: Removed from store<\/li>\n<\/ul>\n\n\n\n<p>Your app should handle deep links to unavailable products:<\/p>\n\n\n\n<pre><code class=\"language-javascript\">if (product === null || product.status !== &#39;ACTIVE&#39;) {\n  navigation.navigate(&#39;ProductUnavailable&#39;, {\n    message: &#39;This product is no longer available.&#39;,\n    handle: handle,\n  });\n  return;\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Multi-Currency<\/h3>\n\n\n\n<p>If your Shopify store supports multiple currencies, pass the currency in the deep link:<\/p>\n\n\n\n<pre><code>https:\/\/go.yourapp.com\/product\/running-shoes-v2?currency=EUR\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Shopify Plus Checkout<\/h3>\n\n\n\n<p>Shopify Plus merchants have access to checkout customization. You can create deep links that go directly to a pre-filled checkout:<\/p>\n\n\n\n<pre><code>https:\/\/go.yourapp.com\/checkout?variant=41234567890&amp;qty=1&amp;discount=SUMMER20\n<\/code><\/pre>\n\n\n\n<p>The app creates a Shopify checkout via the Storefront API and navigates to the checkout screen.<\/p>\n\n\n\n<p>For deep linking features, see <a href=\"https:\/\/tolinku.com\/features\/deep-linking\">Tolinku deep linking<\/a>. For marketplace deep linking, see <a href=\"https:\/\/tolinku.com\/blog\/marketplace-app-deep-links\/\">Deep Linking for Marketplace Apps<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Implement deep linking for Shopify mobile apps. Connect your Shopify store to your native app with product, collection, and checkout deep links.<\/p>\n","protected":false},"author":2,"featured_media":935,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"rank_math_title":"Deep Linking for Shopify Mobile Apps","rank_math_description":"Implement deep linking for Shopify mobile apps. Connect your Shopify store to your native app with product, collection, and checkout deep links.","rank_math_focus_keyword":"Shopify app deep links","rank_math_canonical_url":"","rank_math_facebook_title":"","rank_math_facebook_description":"","rank_math_facebook_image":"https:\/\/tolinku.com\/blog\/wp-content\/uploads\/2026\/03\/og-shopify-app-deep-links.png","rank_math_facebook_image_id":"","rank_math_twitter_title":"","rank_math_twitter_description":"","rank_math_twitter_image":"https:\/\/tolinku.com\/blog\/wp-content\/uploads\/2026\/03\/og-shopify-app-deep-links.png","footnotes":""},"categories":[18],"tags":[25,20,58,24,192,69,190,203],"class_list":["post-936","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-use-cases","tag-android","tag-deep-linking","tag-e-commerce","tag-ios","tag-mobile-commerce","tag-mobile-development","tag-product-pages","tag-shopify"],"_links":{"self":[{"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/posts\/936","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/comments?post=936"}],"version-history":[{"count":3,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/posts\/936\/revisions"}],"predecessor-version":[{"id":2530,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/posts\/936\/revisions\/2530"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/media\/935"}],"wp:attachment":[{"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/media?parent=936"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/categories?post=936"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/tags?post=936"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}