Senior Frontend Architect, 10+ років досвіду побудови production-проєктів на Next.js. Contentful Certified Professional (2024). Спеціалізація: React Server Components, headless eCommerce, інженерія Core Web Vitals.
Headless Shopify на Next.js став основною архітектурою для швидкої електронної комерції у 2026 році - не тому що він простіший, а тому що відв'язує шар рендерингу і SEO від обмежень платформи Shopify так, що це дає вимірно кращі Core Web Vitals і конверсію. У цьому гайді я розбираю три речі, які більшість туторіалів пропускає: повну поверхню API Shopify - усі три рівні (Storefront API, Admin API, Customer Account API), їхні моделі автентифікації, ліміти запитів і контракти пагінації; шар даних Next.js App Router - як RSC, Data Cache і generateStaticParams прибирають клієнтські водоспади запитів на каталожних сторінках; і модель меж стану - що належить серверним компонентам, чому потрібен 'use client' і які саме механізми (зберігання кошика в куці, OAuth PKCE, оптимістичні оновлення) змушують інтерактивний шар працювати. Усе це спирається на продакшен-патерни з міжнародних eCommerce-проєктів, включно з мультивітринними розгортаннями Shopify Plus.
Частина I - Поверхня API Shopify: три рівні, три різні контракти
Найчастіша архітектурна помилка в headless-проєктах на Shopify - вважати Storefront API «тим самим API Shopify» і повністю ігнорувати Admin API та новіший Customer Account API. Для коректної продакшен-архітектури треба розуміти всі три.
- Storefront API (GraphQL, публічний): Ендпоінт
https://{shop}.myshopify.com/api/{version}/graphql.json. Автентифікація через заголовокX-Shopify-Storefront-Access-Token- токен із правами на читання вітрини. Ліміти вартісні: кожне поле GraphQL має свою вагу; бюджет одного запиту - 1000 одиниць вартості; кошик лімітів на рівні магазину поповнюється на 500 одиниць за секунду. Запит 250 вузлів товарів по 4 поля кожен коштує рівно 1000 одиниць - максимум за раз. Це змушує використовувати курсорну пагінацію (first: N,after: $cursor), а не зміщення. Shopify фіксує версії API:2024-10,2025-01,2025-04- квартальні релізи. Кожна версія підтримується 12 місяців, ламкі зміни з'являються лише в нових. Версію треба фіксувати явно:unstableдля продакшену не годиться. - Admin API (GraphQL і REST, приватний): Повне керування магазином: залишки, відвантаження замовлень, запис даних покупців, метаполя, вебхуки. Автентифікація через
X-Shopify-Access-Token(приватний застосунок) або сесійний токен OAuth (кастомний застосунок). Ніколи не віддавайте облікові дані Admin API у браузер. Admin API живе виключно в Route Handlers Next.js або в серверних утилітах заimport 'server-only'. Ліміти: дірявий кошик, 40 запитів за секунду на застосунок для REST; 1000 одиниць вартості на запит для GraphQL із поповненням 500 за секунду - пропускна здатність вища, ніж у Storefront API за того самого розміру кошика. - Customer Account API (OAuth 2.0, з 2024): У середині 2024 року Shopify оголосив застарілими попередні мутації покупців у Storefront API (
customerCreate,customerAccessTokenCreate,customerRecover). Заміна - Customer Account API, окремий сервіс OAuth 2.0 за адресоюshopify.com/authentication/{shop-id}. Він використовує потік PKCE (Proof Key for Code Exchange, RFC 7636) для публічних клієнтів, включно з браузером і SSR, видає короткоживучі токени доступу (година) з refresh-токенами (скоуп офлайн-доступу) і відкриває окремі GraphQL-запити для замовлень, адрес і керування акаунтом. Будь-яка нова headless-реалізація у 2026 році зобов'язана використовувати саме його: старі мутації вимкнені.
Фіксація версії API на практиці: У шарі даних версія задається однією константою і використовується всюди: const SHOPIFY_API_VERSION = '2025-01'. Вона підставляється сегментом шляху в кожен виклик. Коли Shopify випускає нову квартальну версію, ви запускаєте npx @shopify/api-codegen@latest проти її схеми, переглядаєте діфи згенерованих типів TypeScript, оновлюєте константу і перевіряєте на стенді. Це правильна церемонія оновлення. unstable у продакшені неприпустимий: між щоденними збірками там бувають ламкі зміни.
Частина II - Шар даних: типізований GraphQL із кодогенерацією
Голі виклики fetch із рядками GraphQL просто в коді - друга за частотою архітектурна помилка в headless-проєктах на Shopify. Проблема не в ергономіці, а в коректності. Відповіді GraphQL не типізовані; зміна в API Shopify, яка перейменує поле чи змінить тип, мовчки дасть undefined у продакшені без жодного сигналу на етапі компіляції. Правильна архітектура генерує типи TypeScript зі схеми Shopify.
- Інструменти:
@graphql-codegen/cliплюс@graphql-codegen/typescript,@graphql-codegen/typescript-operationsі@shopify/api-codegen-preset. Пресет завантажує схему Storefront API для вашої зафіксованої версії й генерує типи для всіх файлів операцій.graphql. Командаnpm run codegenу CI - і типи завжди збігаються із заявленою версією схеми. - Стратегія фрагментів: Опишіть перевикористовні фрагменти під форми даних, які споживають компоненти:
fragment ProductCardFields on Product { id handle title featuredImage { url altText } priceRange { minVariantPrice { amount currencyCode } } }. Запити картки товару збираються з цього фрагмента плюс розширені поля. Так ви уникаєте розповзання запитів, коли PDP і PLP незалежно описують трохи різні форми товару, а пропси компонентів починають розходитися. - Шар даних лише для сервера: Усі функції звернення до Shopify живуть у
lib/shopify/зimport 'server-only'на початку індексного файлу. Це не дає випадково затягнути серверні утиліти з ключами API в клієнтські компоненти: TypeScript уронить збірку на будь-якому порушенні межі імпорту. - Токен приватного застосунку і змінні оточення:
process.env.SHOPIFY_STOREFRONT_ACCESS_TOKEN- єдине місце, де живе токен. В App Router змінні оточення без префіксаNEXT_PUBLIC_серверні: у клієнтський JS вони не потрапляють ніколи. Це межа безпеки, яку фреймворк забезпечує на рівні збирача, а не домовленістю.
Частина III - Архітектура каталогу: generateStaticParams та ISR
Каталог - сторінки товарів (PDP) і сторінки колекцій (PLP) - найвідвідуваніша і найчутливіша до швидкості поверхня будь-якої вітрини. У headless-реалізації на App Router правильна архітектура пререндерить усі каталожні сторінки на збірці через generateStaticParams, а свіжість забезпечує ISR (інкрементальна статична регенерація). Це прибирає серверний round-trip на кожен перегляд, віддає готовий HTML прямо з краю CDN і стабільно дає LCP нижче 1,2 секунди на p75 для сторінок із кешу.
- generateStaticParams для PDP:
export async function generateStaticParams() { const products = await getAllProductHandles(); return products.map((handle) => ({ handle })); }. ФункціяgetAllProductHandles()гортає Storefront API курсорною пагінацією:products(first: 250, after: $cursor) { edges { node { handle } } pageInfo { hasNextPage endCursor } }. Для каталогу на 5000 товарів це 20 запитів - один раз на збірці, а не на кожен показ сторінки. - Налаштування ISR:
export const revalidate = 3600;на рівні сегмента маршруту перегенерує сторінку у фоні, коли закешована відповідь старша за годину. Зміни ціни й залишків у Shopify доїжджають протягом години. Для сторінок, критичних за залишками (флешрозпродажі, обмежені партії), знижуйте доrevalidate = 300і додавайте ревалідацію на вимогу: вебхук → Route Handler →revalidateTag('product-' + handle). - Патерн RSC для PDP: Компонент сторінки асинхронний. Дані запитуються прямо в тілі компонента:
const product = await getProduct(params.handle);. Назва, опис, картинки й характеристики рендеряться як вивід серверного компонента - нуль байтів цього коду йде в клієнтський бандл. Клієнтськими лишаються тільки<AddToCartButton>і<VariantSelector>. Модель RSC повністю прибирає водоспадuseEffect → fetch → setState → умовний рендер, який був стандартом у реалізаціях PDP на Pages Router. dynamicParams = true(за замовчуванням): Товари, додані в Shopify після останньої збірки, уgenerateStaticParamsне потрапили. ЗаdynamicParams = trueзапит невідомого хендла запускає серверний рендер на першому візиті, а далі сторінка кешується. Так нові товари доступні одразу, без повного перезбирання.
Механіка пагінації колекцій: API колекцій Shopify курсорний: products(first: 24, after: $cursor). У реалізації на Next.js кожна «сторінка» колекції - окремий статичний маршрут: app/collections/[handle]/page/[page]/page.tsx. Курсор сторінки N зберігається рядком у base64 і передається параметром запиту в посилання на наступну. Така архітектура кешується на CDN, бо в кожної сторінки унікальний стабільний URL, на відміну від клієнтського нескінченного прокручування, яке дає один некешовний маршрут.
Частина IV - Стан кошика: зберігання в куці та оптимістичні оновлення
Кошик - найскладніша частина клієнтського стану в headless-реалізації на Shopify, бо він має бути доступний і на сервері (лічильник у шапці рендериться серверним компонентом), і на клієнті (інтерактивне додавання та видалення). Правильне рішення - зберігати ідентифікатор кошика в куці й читати його на сервері.
- Cart API проти Checkout API: У Shopify два API навколо кошика. Checkout API (застарілий) створює об'єкт чекауту з URL; Cart API (актуальний, з 2022) створює кошик з окремою властивістю
checkoutUrl. Для всіх мутацій кошика беріть Cart API: це поточний стандарт і він узгоджений з Headless Channel. Ключові мутації:cartCreate(створює кошик, повертаєcart.id),cartLinesAdd(додає позиції),cartLinesUpdate(змінює кількість),cartLinesRemove(видаляє позицію),cartBuyerIdentityUpdate(прив'язує покупця після входу). - Зберігання ідентифікатора кошика в куці:
cartCreateповертаєcart.id- глобально унікальний ідентифікатор у форматі GID (gid://shopify/Cart/{random}). Він має переживати переходи між сторінками й серверні рендери. Кука тут єдиний вірний варіант:localStorageнедоступний у серверних компонентах, аsessionStorageне переживає закриття вкладки. Ставте куку зhttpOnly: false(клієнтському JS треба її читати для мутацій),sameSite: 'lax',path: '/',maxAge: 30 * 24 * 60 * 60- тридцять днів, як TTL кошика в Shopify. На сервері читайте черезcookies()у серверному компоненті або Route Handler, щоб відмалювати лічильник у шапці без клієнтського запиту. - Межа
'use client':<CartProvider>- контекст React, який тримає стан кошика і функції мутацій, - клієнтський компонент. Його імпортуєapp/layout.tsx(серверний компонент), створюючи для нього Client Reference Object. Піддерево всередині<CartProvider>рендериться на клієнті.<AddToCartButton>- клієнтський компонент, який викликаєcartLinesAddчерез Route Handler (/api/cart/lines/add). Ніколи не викликайте мутації Shopify прямо з браузера: токен Storefront API опиниться в мережевих запитах. Route Handlers проксують мутації на сервері. - Оптимістичні оновлення через
useOptimistic(React 19):useOptimisticдає миттєву реакцію інтерфейсу до підтвердження мутації сервером. Патерн:const [optimisticCart, addOptimistic] = useOptimistic(cart, (state, newLine) => ({ ...state, lines: [...state.lines, newLine] }));. ВикличтеaddOptimisticсинхронно по кліку «У кошик», потім дочекайтеся відповіді Route Handler. Якщо мутація впаде, React сам відкотить стан до серверного. Це прибирає спінер на 200–400 мс під час додавання в кошик.
Частина V - Автентифікація покупців: потік OAuth у Customer Account API
Попередні мутації покупців у Storefront API (customerCreate, customerAccessTokenCreate) оголошені застарілими починаючи з версії API 2024-04. Будь-яка headless-реалізація, що стартує з 2025 року, зобов'язана впроваджувати Customer Account API з потоком OAuth 2.0 PKCE. Це суттєвий архітектурний зсув від простого обміну токенами, до якого розробники звикли.
- Механіка потоку PKCE (RFC 7636): (1) Згенеруйте криптографічно випадковий
code_verifier- рядок ASCII довжиною 43–128 символів. (2) Порахуйтеcode_challenge = BASE64URL(SHA-256(code_verifier)). (3) Відправте користувача наhttps://shopify.com/authentication/{shop-id}/oauth/authorize?client_id={id}&scope=openid+email+customer-account-api:full&redirect_uri={uri}&response_type=code&code_challenge={challenge}&code_challenge_method=S256&state={random}. (4) Після автентифікації Shopify повертає наredirect_uri?code={code}&state={state}. (5) Обміняйтеcodeразом ізcode_verifierна токени в token-ендпоінті. Потік PKCE застосовується тому, що client_secret не можна безпечно зберігати в браузерному застосунку: доказом особи виступаєcode_verifier. - Робота з токенами в Next.js:
code_verifierгенерується в Route Handler (app/api/auth/shopify/route.ts), кладеться в кукуhttpOnly(клієнтському JS недоступна) і зчитується назад під час обміну на токени. Токени доступу (TTL година) і refresh-токени зберігаються в сесійних кукахhttpOnly. Сесія покупця читається на сервері черезcookies()у серверних компонентах - працювати з токенами на клієнті не потрібно взагалі. - Патерн адаптера Auth.js v5: Auth.js (next-auth) v5 підтримує кастомних OAuth-провайдерів. Customer Account API налаштовується як провайдер з
authorization.url,token.urlіuserinfo.url, що вказують на відповідні ендпоінти. Auth.js бере на себе оновлення токенів, серіалізацію сесії й життєвий цикл PKCE-верифікатора. Реалізація зводиться до конфігурації провайдера, а не до написання скінченного автомата OAuth. cartBuyerIdentityUpdateпісля входу: Коли гість набрав кошик і потім авторизувався, кошик треба прив'язати до його акаунта. ВикличтеcartBuyerIdentityUpdate, передавши токен доступу покупця як buyer identity. Це вмикає історію замовлень, збережені адреси й нарахування балів лояльності за раніше анонімну активність.
Частина VI - SEO-архітектура: схема товару і канонікал варіантів
У SEO headless-вітрини на Shopify є дві особливості, яких немає у звичайного застосунку на Next.js: розмітка товарів і колекцій, яка має точно відображати модель даних Shopify, і канонізація URL варіантів, яка не дає системі параметрів Shopify наплодити дублі в промислових масштабах.
- Розмітка товару: Кожна PDP віддає схему
ProductзOffer(поточна ціна, валюта, наявність ізproduct.variants.availableForSale),AggregateRating(якщо підключені відгуки - Yotpo, Judge.me тощо) іBreadcrumbList. ВластивістьProduct.urlзобов'язана бути канонічним URL без параметра?variant=.Offer.priceCurrencyбереться з поляprice.currencyCodeStorefront API за ISO 4217 - хардкодити не можна.Offer.availabilityмапиться так:availableForSale: true→InStock;availableForSale: falseзаtotalInventory > 0→PreOrder; інакше →OutOfStock. - Канонізація URL варіантів: Вибір варіанта в Shopify додає до URL
?variant={variantId}. Без явної канонізації кожен такий URL - індексований дубль базової сторінки товару. УgenerateMetadata()завжди повертайтеalternates: { canonical: '/products/' + params.handle }і ніколи не включайте параметр варіанта в канонікал. Так усі сигнали варіантів сходяться на базовий URL, а не розмазуються по сотнях сполучень. - Канонікал пагінації колекцій: У другої сторінки колекції (
/collections/shirts?cursor=abc) канонікал має вказувати на саму себе, а не на першу сторінку: це різний вміст. Підказкиrel=prevіrel=next(Google відмовився від них у 2019, але Bing використовує, і як підказка обходу вони корисні) можна додати тегами<link>у<head>. Важливіше інше: у кожної сторінки має бути унікальний стабільний URL. Курсорна пагінація це забезпечує, а пагінація за зміщенням (?page=2) - ні, якщо порядок товарів змінюється. - hreflang для мультирегіональних вітрин: Shopify Markets дозволяє тримати кілька сполучень країни й валюти на одному магазині. Локаль кожного ринку (en-US, en-GB, fr-FR) відповідає хендлу ринку в Shopify. У
generateMetadata()полеalternates.languagesзаповнюється з конфігурації Markets, і URL кожного ринку веде на правильний шлях локалі. Це стандартна зв'язкаnext-intlіgenerateMetadata- докладний розбір у гайді з міграції на App Router.
Частина VII - Інженерія продуктивності: межі бандла і конвеєр картинок
Перевага headless Shopify перед темами Shopify (Liquid плюс їхній CDN) не з'являється сама: вона потребує свідомих архітектурних рішень. Критичних вимірів два - розмір клієнтського бандла (задається розстановкою меж 'use client') і доставка зображень (задається роботою з URL-параметрами CDN Shopify).
- Поверхня
'use client'на PDP: Інтерактивних компонентів на сторінці товару рівно три:<VariantSelector>(змінює обраний варіант і разом із ним ціну й наявність),<AddToCartButton>(запускає мутацію кошика) і<ImageGallery>(перемикання за мініатюрами, за бажання рендериться на сервері з прогресивним покращенням). Усе інше - назва, опис, характеристики, блок відгуків, хлібні крихти, схожі товари - серверні компоненти. Сумарна клієнтська поверхня: приблизно 15–25 КБ gzip. Загальний бандл грамотно зібраної PDP: 80–120 КБ gzip проти 350–500 КБ у типової теми на Liquid з Alpine.js або в наївної клієнтської реалізації на React. Як це скорочення перекладається в покращення INP, докладно розібрано в гайді з архітектури вебпродуктивності. - Робота з URL картинок у CDN Shopify: Shopify віддає зображення товарів із
cdn.shopify.com. CDN уміє перетворення на льоту через параметри URL:?width=800&height=800&crop=center&format=avif&quality=80. Зовнішній CDN картинок чи окремий обробник дляnext/imageне потрібні. Уnext.config.tsдодайтеimages.remotePatternsдляcdn.shopify.com, а в компонентах передавайте URL картинки Shopify прямо вnext/image- він запитає потрібний розмір через рядок запиту. Для AVIF додайте&format=avif: Shopify згенерує варіант при першому запиті й закешує назавжди. - Preconnect до CDN Shopify:
<link rel='preconnect' href='https://cdn.shopify.com' />вapp/layout.tsx. Це знімає затримку резолву DNS і TLS-рукостискання (близько 150–200 мс) на першому запиті картинки з боку Shopify. На PDP із шістьма зображеннями це помітно покращує LCP: запит hero-картинки стартує одразу після розбору HTML. - Семантика кешування на краю: Сторінки колекцій і товарів віддають
Cache-Control: public, s-maxage=3600, stale-while-revalidate=86400. Директиваs-maxageвелить краєвим вузлам CDN (Vercel Edge Network, Cloudflare) віддавати кеш годину, аstale-while-revalidateдозволяє віддавати застарілу копію ще добу, поки у фоні йде регенерація. Route Handlers мутацій кошика (/api/cart/*) зобов'язані явно ставитиCache-Control: no-store: відповіді кошика персональні й на CDN кешуватися не повинні ніколи.
Частина VIII - Продакшен-архітектура: патерни з проєктів
Архітектурні патерни з цього гайду взяті з продакшен-реалізацій headless Shopify. Два показові проєкти з портфоліо показують, де теорія зустрічається з продакшен-обмеженнями.
- Міжнародний магазин товарів для дому (гібрид Shopify Plus і Magento 2): Проєкт із мультивітринною архітектурою Shopify Plus, що обслуговує B2B і B2C у 12 країнах, плюс каталог Magento 2 для оптового каналу. Headless-фронтенд на Next.js споживав і Storefront API Shopify, і GraphQL API Magento через єдиний шар даних: ті самі React-компоненти малювали товари незалежно від комерційного бекенду. Абстракція - типізований інтерфейс
Product, який повертали іgetShopifyProduct(), іgetMagentoProduct(). Це композовна headless-архітектура у найвимогливішій формі: два бекенди, одне дерево компонентів, однакова продуктивність на обох. - Ритейл під сплесками навантаження: Тут вітрина мала витримувати сплески на флешрозпродажах (десятикратний трафік у вікні 60 секунд) без деградації TTFB і без падіння мутацій кошика. Рішення:
generateStaticParamsпререндерить усі PDP і PLP на збірці, і сплеск цілком приймає край CDN, взагалі не звертаючись до origin за вмістом сторінок. В origin під час сплеску йдуть лише мутації кошика через/api/cart/*, а вони проксуються в Cart API Shopify, у якого свої ліміти й черга. Ліміти Storefront API (1000 одиниць на запит, поповнення 500 за секунду) вузьким місцем не стали, бо на статичних сторінках вітрина не робила до Shopify жодного запиту. Просунуті патерни корпоративної комерції - в послузі enterprise eCommerce. - Схема вибору архітектури: Беріть цей підхід, коли: (1) каталог великий, від 500 товарів, - пререндер через
generateStaticParamsокупається; (2) потрібні вітрини в кількох регіонах - зв'язка Shopify Markets та i18n у Next.js тут вірна; (3) дизайн-система має бути повністю власною - теми на Liquid довільну фронтенд-архітектуру не потягнуть. Беріть Shopify Hydrogen, коли: (1) Shopify - єдиний бекенд, і нативна інтеграція прибирає весь шаблонний код шару даних; (2) команді ближчі патерни Remix; (3) Oxygen (хостинг Shopify на V8-ізолятах) вписується у ваші обмеження щодо деплою. Повне порівняння обох архітектур - у розборі Shopify Hydrogen проти Next.js Commerce.
Висновок
Продакшен-вітрина headless Shopify на App Router зачіпає чотири інженерні області, і кожну треба зробити правильно: поверхню API Shopify (три рівні, фіксація версії, вартісні ліміти), модель даних App Router (RSC для каталогу, 'use client' лише для інтерактивного стану), потік OAuth 2.0 PKCE у Customer Account API й роботу над продуктивністю, яка тримає клієнтський бандл малим, а влучання в кеш CDN високим.
Команди, які підходять до задачі як до «смикнути API Shopify і відмалювати дані», стабільно отримують вітрину повільнішу за тему на Liquid, баги сесії в кошику й авторизації та проблеми з позиціями через дублі URL варіантів. Архітектура з цього гайду - типізований шар даних, каталог через generateStaticParams, кошик у куці, авторизація за PKCE, 'use client' на листках дерева - саме від цього й захищає. Той самий headless-інстинкт працює і поза комерцією: коли бекендом контенту виступає WordPress, а не Shopify, хід той самий - перейти на нативну для Next.js альтернативу на кшталт Payload CMS.
Скоупінг архітектури, впровадження або аудит наявної headless-вітрини на Shopify - послуга композовної headless-архітектури | кейси | обговорити проєкт.
Часті питання
- Потрібна власна реалізація на Next.js чи краще взяти Shopify Hydrogen? Hydrogen вірний, коли Shopify - ваш єдиний комерційний бекенд і вам комфортно з архітектурою Remix і Vite. Власна реалізація на Next.js виграє, коли бекендів кілька (Shopify плюс Magento або Shopify плюс власний PIM), коли дизайн-система і бібліотека компонентів уже на React і Next.js або коли вимоги до хостингу виключають Oxygen. Фреймворк вибору - у повному порівнянні.
- Чому не можна просто тримати ідентифікатор кошика в
localStorage?localStorage- браузерне API: воно недоступне в серверних компонентах, під час SSR і в middleware. А лічильник товарів у шапці має рендеритися на сервері, бо він потрапляє у вихідний HTML. Кука - єдиний механізм, доступний і серверу (cookies()у Next.js), і клієнту. Правильний варіант зберігання - кука зhttpOnly: falseіsameSite: 'lax'. - Як жити з лімітами Storefront API на масштабі? Вартісна система (1000 одиниць на запит, поповнення 500 за секунду) означає, що один застосунок на Next.js може нескінченно робити близько 1,7 запиту за секунду за 500 одиниць на запит. Для збірки каталогу від 5000 товарів потрібен білд-тайм конвеєр, який гортає товари на максимально допустимій швидкості, а не запит на кожен показ. У реальному трафіку патерн ISR означає, що на закешованих сторінках сервер узагалі не ходить у Storefront API, і ліміти стосуються лише фонової регенерації.
- Як зробити ревалідацію ISR на вимогу, коли товар оновили в Shopify? Налаштуйте вебхук Shopify на подію
products/updateз адресою Route Handler у Next.js. Обробник перевіряє HMAC-підпис вебхука, дістає хендл товару і викликаєrevalidateTag('product-' + handle). Наступний запит цієї PDP запустить регенерацію. Обробник має бути відкритий для доставки вебхуків Shopify, але захищений перевіркою HMAC. - Як правильно поводитися з параметром
?variant=для SEO? Канонікал завжди вказує на базовий URL товару без параметра варіанта:alternates: { canonical: '/products/' + handle }уgenerateMetadata(). Сам вибір варіанта можна тримати в URL параметром запиту заради можливості поділитися посиланням - на SEO це не впливає, бо Google поважає канонікал і зводить сигнали до базового URL. У карту сайту URL з?variant=не включайте ніколи.
Джерела
- Shopify. «Storefront API Reference»
- Shopify. «Customer Account API»
- Shopify. «Shopify API Rate Limits»
- Shopify. «Shopify Markets»
- RFC 7636. «Proof Key for Code Exchange by OAuth Public Clients»
- Next.js Team. «generateStaticParams»
- Next.js Team. «Data Fetching and Caching»
- Next.js Team. «Incremental Static Regeneration»
- GraphQL Code Generator. «TypeScript Operations Plugin»
- Auth.js. «Custom OAuth Providers»
- Shopify. «Storefront API changelog 2025-01»
- HTTP Archive. «Web Almanac 2025 - eCommerce»
Будувати самому чи стартувати з production-темплейта?
Стартуйте з темплейта, якщо тільки сама вітрина не є вашим продуктом. Цей гайд показує повну збірку, бо розуміти, що у вас працює, ви зобов'язані. Але наново писати всю обв'язку більшості команд не потрібно. Production-темплейт уже везе вітрину, адаптери, тести й CI: ви підключаєте свій бекенд і кастомізуєте, а не перезбираєте кошик, чекаут, пошук і SEO з нуля.
| Вимір | Збірка з нуля | Production-темплейт |
|---|---|---|
| Вітрина, кошик, чекаут | Будуєте самі | Уже всередині |
| CMS для контенту і пошук | Підключаєте самі | Sanity/Contentful/Payload/AEM плюс Algolia або вбудований |
| Тести і доступність | Заводите самі | 460+ тестів, WCAG 2.2 AA, гейт Lighthouse |
| Час до продакшену | Тижні й місяці | Дні й тижні |
| Подальша підтримка | Цілком на вас | Підтримуване ядро, яке ви розширюєте |
Скільки часу займає збірка headless-магазину на Shopify?
З нуля продакшен-вітрина headless Shopify зазвичай займає від кількох тижнів до кількох місяців залежно від розміру каталогу та інтеграцій. Старт із перевіреного темплейта скорочує це до днів і тижнів, бо кошик, чекаут, пошук, контент і CI вже готові, а вам лишається підключити бекенд і накласти свій бренд.
Який найшвидший шлях до продакшен-вітрини headless Shopify?
Стартувати з перевіреної основи, а не з порожнього репозиторію. Headless Commerce Template - це вітрина, описана в цьому гайді, уже зібрана: Shopify або Magento позаду, контент, пошук, лояльність і подарункові картки в коробці, і CI, який не пропустить мердж із просіданням доступності чи швидкості. Наводьте на свій бекенд, виходьте за тижні, код лишається у вас.
