Shopify Integration

CMS Assets has first-class support for Shopify. It proxies and caches your Shopify storefront asset URLs and provides a response transformer that rewrites them in your Storefront API responses.


Supported URL patterns

Shopify serves assets from your store domain under the /cdn/ path prefix:

Product images and files:

https://cdn.shopify.com/s/files/1/0123/4567/8901/files/product.jpg
https://your-store.myshopify.com/cdn/shop/files/product.jpg

With image transformations:

https://cdn.shopify.com/s/files/1/0123/4567/8901/files/product.jpg?v=123&width=1920

These are rewritten to:

https://your-tenant.cmsassets.com/cdn/shop/files/product.jpg

Tenant setup

When creating your tenant, select Shopify as the CMS type and provide your store domain:

FieldValue
CMSShopify
Store domainyour-store.myshopify.com
Website domainyour-site.com

The origin is automatically configured from your store domain:

  • Origin: https://your-store.myshopify.com

You can also use a custom Shopify domain (e.g. shop.your-brand.com) as the store domain.


Bandwidth pricing

Shopify does not charge for CDN bandwidth, so the CMS bandwidth overage rate for Shopify tenants is $0/GB. You still benefit from edge caching and the unified asset domain that CMS Assets provides.


Response transformer

Install the response transformer to automatically rewrite Shopify asset URLs in your Storefront API responses:

npm install @synchronized-studio/response-transformer

Basic usage

import { transformShopifyAssetUrls } from "@synchronized-studio/response-transformer"

const response = await fetch(
  `https://${storeDomain}/api/2024-01/graphql.json`,
  {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-Shopify-Storefront-Access-Token": storefrontToken
    },
    body: JSON.stringify({
      query: `{ products(first: 10) { edges { node { title featuredImage { url } } } } }`
    })
  }
)
const data = await response.json()

const transformed = transformShopifyAssetUrls(data, {
  storeDomain: "your-store.myshopify.com",
  cmsAssetsUrl: "https://your-tenant.cmsassets.com"
})

What gets transformed

The transformer processes the entire JSON response and rewrites all matching URLs. This includes:

  • Product images
  • Collection images
  • Variant images
  • Metafield file references
  • Any URL matching your Shopify store domain's CDN paths

Query parameters (like Shopify's ?width=800&height=600) are stripped during rewriting.

Using an environment variable

Set CMS_ASSETS_URL in your environment and omit the cmsAssetsUrl option:

CMS_ASSETS_URL=https://your-tenant.cmsassets.com
const transformed = transformShopifyAssetUrls(data, {
  storeDomain: "your-store.myshopify.com"
})

Nuxt / SSR integration

For Nuxt or other SSR frameworks, wrap your Shopify Storefront API calls:

// composables/useShopifyData.ts
import { transformShopifyAssetUrls } from "@synchronized-studio/response-transformer"

export async function useShopifyProducts() {
  const data = await shopifyClient.request(productsQuery)

  return transformShopifyAssetUrls(data, {
    storeDomain: "your-store.myshopify.com",
    cmsAssetsUrl: useRuntimeConfig().public.cmsAssetsUrl
  })
}

Using the generic transformer

You can also use the unified transformCmsAssetUrls function:

import { transformCmsAssetUrls } from "@synchronized-studio/response-transformer"

const transformed = transformCmsAssetUrls(data, {
  cms: "shopify",
  storeDomain: "your-store.myshopify.com",
  cmsAssetsUrl: "https://your-tenant.cmsassets.com"
})

Shopify Image Transformations

Shopify's CDN supports on-the-fly image transformations via query parameters like ?width=800&height=600&crop=center. When assets are proxied through CMS Assets:

  • The edge cache strips query parameters from the cache key for image types
  • This means all image transformation variants share the same cache entry
  • If you rely on Shopify's CDN transformations, the first cached version will be served for all variants

If you need different image sizes, apply transformations on the client side or serve each size from a different path.


Advanced options

Custom transformers

Add additional transformers that run after the default Shopify ones:

const transformed = transformShopifyAssetUrls(data, {
  storeDomain: "your-store.myshopify.com",
  transformers: [
    (jsonStr, { base }) => {
      return jsonStr.replaceAll("old-pattern", "new-pattern")
    }
  ]
})

Post-transform hook

Run a function on the parsed result after all URL replacements:

const transformed = transformShopifyAssetUrls(data, {
  storeDomain: "your-store.myshopify.com",
  postTransform: (data) => {
    return data
  }
})

Error handling

By default, transform errors are logged as warnings and the original data is returned unchanged. You can provide a custom error handler:

const transformed = transformShopifyAssetUrls(data, {
  storeDomain: "your-store.myshopify.com",
  onError: (error) => {
    Sentry.captureException(error)
  }
})
Need help understanding this?Ask CMS Assets Copilot about features, setup, or integrations.
Ask Copilot →