Интеграция Web SDK
Web SDK добавляет готовые интерфейсы ShopStory на сайт. Подключение состоит из настройки проекта со стороны ShopStory, установки скриптов и совместной проверки на домене клиента.
Если интерфейс полностью реализует клиент, используйте Public API. Для нативного приложения используйте Mobile SDK.
Что доступно
- каталог прямых эфиров и записей;
- полноразмерный плеер;
- product mini-player на согласованных товарных страницах;
- уведомление об активном эфире, если оно включено для проекта;
- переход в карточку товара или согласованное действие корзины.
Доступные виджеты ShopStory включает в конфигурации проекта.
Контуры Web SDK
| Поверхность | Подключение | Commerce-действие |
|---|---|---|
| Каталог и плеер внутри страницы клиента | Основной bundle и один вызов ShopStorySDK.show() | В экземпляр show() можно передать actions и cartUrl |
| Product mini-player и live-уведомление на PDP | Отдельный auto-init PiP bundle и настройка PDP со стороны ShopStory | Базовый путь открывает плеер и URL товара; direct cart для этого пути согласуется отдельно |
| Собственный список эфиров | Public API и UI клиента | Реализуется кодом клиента |
Основной и PiP bundles имеют разные bootstrap-контракты. Не подключайте их на одной странице без схемы из integration handoff.
До установки
Передайте команде ShopStory:
- Точные production- и test-домены.
- URL страницы каталога эфиров.
- Товарный фид и единый строковый
feedProductIdтовара. - Примеры PDP, включая все используемые шаблоны.
- Требуемое поведение кнопки «Купить».
- Действующую CSP сайта и список целевых браузеров.
ShopStory регистрирует домены и origins, связывает их с applicationId, готовит конфигурацию и согласует способ определения товара на PDP. Проверку SDK на домене начинайте после подтверждения этой конфигурации.
Основной SDK получает clientId в вызове show() и сверяет проект с зарегистрированным hostname. Секрет в HTML для этого не требуется. Каждый новый hostname нужно заранее передать ShopStory.
Каталог эфиров
Создайте контейнер:
<div id="shopstory"></div>
Подключите основной bundle и вызовите show() после его загрузки:
<script
src="https://app.shopstory.live/sdk/shopstory-sdk/shopstory-sdk-v1.x.min.js"
crossorigin="anonymous"
charset="utf-8"
></script>
<script>
const container = document.getElementById('shopstory');
if (window.ShopStorySDK && container) {
window.ShopStorySDK.show({
containerElement: container,
config: { clientId: 'assigned-application-id' },
});
}
</script>
v1.x — буквальная часть опубликованного имени web-bundle. Используйте этот URL без замены x и не конструируйте соседние адреса.
Этот URL является управляемым ShopStory release channel в рамках контракта v1, а не immutable client tag. Не копируйте bundle на свой CDN. ShopStory отвечает за выпуск и server-side rollback bundle; клиент должен уметь отключить loader своим feature flag или возвратом шаблона к состоянию без SDK. Контакт для уведомлений об изменениях и окно проверки фиксируются в integration handoff проекта.
Не добавляйте async или defer к основному bundle, если инициализация идёт следующим inline-скриптом. При отложенной загрузке вызывайте show() из собственного обработчика load.
Если script-src запрещает inline JavaScript, перенесите вызов show() в разрешённый same-origin файл либо используйте действующий nonce/hash сайта. Не добавляйте 'unsafe-inline' в script-src ради этого примера.
Как загружаются каталог и плеер
После выполнения основного bundle в window появляется ShopStorySDK. Вызов show() монтирует интерфейс в переданный контейнер. Затем SDK инициализируется, самостоятельно запрашивает каталог и товары и показывает результат. Клиенту не нужно повторять эти запросы через Public API.
При выборе эфира SDK загружает его данные и открывает плеер в том же интерфейсе. Ниже показан сценарий с настроенным actions.addProductToCartById. Без обработчика корзины кнопка «Купить» открывает URL товара.
addProductToCartById получает feedProductId, выполняет запрос к корзине и возвращает результат в SDK.Схема показывает успешную загрузку каталога и эфира. При отсутствии контента или сбое путь до плеера прерывается. Запросы SDK к ShopStory обслуживает сам SDK; их внутренние адреса не входят в контракт ручной интеграции.
Методы основного SDK
Параметр SDK clientId принимает тот же идентификатор проекта, который в Public API называется applicationId. Используйте значение, выданное ShopStory, без преобразований. Общие правила: Идентификаторы.
show(options)
Монтирует каталог в контейнер сайта. Возвращает undefined (тип void), не предоставляет Promise загрузки каталога.
| Параметр | Обязательно | Назначение |
|---|---|---|
containerElement | Да | Существующий DOM-элемент, который сайт сохраняет на время работы SDK |
config.clientId | Да | Строковый идентификатор проекта, выданный ShopStory |
actions | Нет | Обработчики добавления товара в корзину и проверки наличия для этого экземпляра |
cartUrl | Нет | Адрес корзины для повторного клика по состоянию «В корзине»; относительный путь разрешается от origin сайта |
await ShopStorySDK.show(...) не ждёт каталог. Ограничения повторной инициализации описаны в разделе SPA и lifecycle.
showPlayer(params)
Открывает указанную трансляцию в собственном контейнере в document.body. При первом вызове SDK создаёт контейнер, при следующих использует его повторно. Оба параметра обязательны:
| Параметр | Тип | Назначение |
|---|---|---|
clientId | string | Идентификатор проекта |
streamId | string | Идентификатор трансляции из API |
Возвращает Promise<void>. Promise завершается после внутренней инициализации SDK, ещё до подтверждения загрузки данных эфира и воспроизведения видео. Использовать его как сигнал «видео готово» нельзя.
async function openShopStoryPlayer(streamId) {
const sdk = window.ShopStorySDK;
if (!sdk) {
console.error('Основной bundle ShopStory не загружен');
return;
}
try {
await sdk.showPlayer({
clientId: 'assigned-application-id',
streamId,
});
} catch (error) {
console.error('Не удалось вызвать плеер ShopStory', error);
}
}
Передавайте идентификаторы строками. Список трансляций для собственного интерфейса получайте через GET /v3/streams.
showPlayer() не принимает actions и cartUrl и не наследует их из ранее вызванного show(). Для прямой корзины используйте плеер внутри каталога, созданного через show({ actions, ... }), либо согласованный commerce-контракт.
Готовность и ошибки
У основного SDK нет публичных событий или параметров onReady / onError для загрузки каталога и плеера. Событие load у <script> позволяет начать инициализацию; готовность каталога или видео оно не подтверждает.
| Что произошло | Что получает код сайта |
|---|---|
| Основной bundle не загрузился или не выполнился | window.ShopStorySDK отсутствует; проверьте загрузку скрипта до вызова методов |
show() вернулся | Только завершение вызова монтирования; данные загружаются отдельно |
showPlayer() завершил Promise | Внутренняя инициализация завершена; данные эфира и видео ещё могут загружаться |
| Вызов метода выбросил исключение или его Promise отклонён | Исключение можно обработать через try/catch |
| Ошибка обработана внутри SDK при загрузке или отрисовке | Публичного callback для сайта нет; возможны сообщение внутри SDK или отсутствие его интерфейса |
try/catch в примере не перехватывает все ошибки загрузки и воспроизведения. При сбое до завершения инициализации Promise showPlayer() может остаться незавершённым. Не связывайте с ним разблокировку страницы, корзины или других функций сайта.
Состояние страницы без SDK и отключение loader через feature flag остаются на стороне клиента. Если вашему интерфейсу нужны собственные состояния загрузки, пустой выдачи и ошибки каталога, используйте Public API.
Типы для TypeScript
Для подключения через <script> добавьте локальный файл деклараций в каталог, включённый в tsconfig.json. Он описывает поддерживаемые на этой странице методы и параметры; сам SDK по-прежнему загружается скриптом.
type ProductAvailabilityMap = Record<string, boolean>;
type ClientActions = {
addProductToCartById?: (
feedProductId: string,
callback: (success: boolean) => void,
) => void;
addProductToCart?: (
vendorCode: string,
callback: (success: boolean) => void,
) => void;
resolveProductsAvailability?: (
feedProductIds: string[],
callback: (availability: ProductAvailabilityMap) => void,
) => void;
};
type ShopStoryShowOptions = {
containerElement: Element;
config: { clientId: string };
actions?: ClientActions;
cartUrl?: string;
};
type ShopStoryPlayerParams = {
clientId: string;
streamId: string;
};
declare global {
interface Window {
ShopStorySDK?: {
show(options: ShopStoryShowOptions): void;
showPlayer(params: ShopStoryPlayerParams): Promise<void>;
refreshProductsAvailability?(): void;
};
}
}
export {};
Поле ShopStorySDK намеренно необязательное: до выполнения bundle объекта нет. По той же причине необязателен refreshProductsAvailability — вызывайте его только через проверку существования. Результат корзины и приоритет обработчиков описаны в разделе Добавление в корзину, карта наличия — в разделе Наличие и остатки.
Product mini-player и live-уведомление
Для согласованных страниц подключите отдельный bundle перед закрывающим </body>:
<script
id="shopstory-pip"
src="https://app.shopstory.live/sdk/shopstory-pip-sdk/shopstory-pip-sdk-v1.x.min.js"
crossorigin="anonymous"
charset="utf-8"
async
></script>
Bundle запускает только компоненты, включённые для проекта. Для product mini-player ShopStory заранее фиксирует:
- какие страницы считаются PDP;
- где находится тот же
feedProductId, что передан в товарном фиде; - положение виджета и отступы от элементов сайта;
- профиль превью, условие показа после прокрутки, включение Live в PiP и Continuous Video;
- на каких страницах виджет должен быть отключён;
- какое действие выполняет кнопка «Купить».
Контейнер PiP скрипт создаёт сам и добавляет в document.body; отдельный <div> для виджета не требуется. Клиент обеспечивает доступность товарного ID в согласованном месте. ShopStory может использовать существующую разметку или другой согласованный источник ID; если подходящего источника нет, потребуется добавить его на PDP. Универсального обязательного data-* атрибута для всех сайтов нет.
PiP проверяет контент асинхронно и запрашивает товарное медиа только после положительного ответа API. При прямом входе на PDP это короткое превью записи или текущий live; при включённом Continuous Video переход из полного плеера позволяет продолжить просмотр на PDP. Профиль WebM с субтитрами, измеренные размеры файлов, режимы PiP, условия продолжения и ограничения autoplay описаны в режимах PiP на PDP. Порядок запросов и поведение без связанного эфира — в загрузке на PDP.
Standalone PiP bundle инициализируется без объекта actions из основного ShopStorySDK.show(). Вызов show() на другой странице не подключает callback к player, открытому из PiP. Для нового проекта такой player открывает URL товара; direct cart на этом пути требует отдельного commerce-контракта. Не загружайте основной и PiP bundles вместе на одной странице без явно проверенной схемы от ShopStory.
Ответ active от mini-player API означает, что сервер нашёл подходящий live или запись. В ручной API-интеграции открывайте body.stream.playerUrl без изменения и не собирайте его из данных видеопровайдера. Показ виджета на странице отдельно зависит от настройки DOM-шаблона PDP.
Покупательское действие
Базовый вариант открывает URL товара. Добавление без перехода требует callback, который возвращает фактический результат клиентской корзины: Добавление в корзину.
Состояние кнопки до клика задаёт наличие. По умолчанию оно берётся из снимка фида; для остатка выбранного магазина в тот же объект actions передаётся обработчик наличия, а метод refreshProductsAvailability() обновляет карточки при смене магазина: Наличие и остатки.
Оба обработчика необязательны и независимы. Без них кнопка «Купить» открывает URL товара, а наличие остаётся по фиду.
SPA и lifecycle
Текущий публичный контракт основного SDK рассчитан на один вызов show() для одного стабильного container. Публичного destroy() нет. В SPA сохраняйте container между route transitions и не вызывайте show() из каждого render/effect без собственной защиты от повторной инициализации.
PiP bundle читает согласованный PDP-шаблон и идентификатор товара во время своего lifecycle. До оценки SPA-интеграции передайте ShopStory используемый router, список PDP routes, способ смены SKU и момент замены DOM. Проверка должна охватывать прямой вход, client-side переход между товарами, back/forward и уход с PDP.
Что включить в оценку
| Work package | Работа клиента | Нужный вход |
|---|---|---|
| Bootstrap | Подключить нужный bundle; для основного SDK передать clientId; исключить повторную инициализацию | Выбранная поверхность, MPA/SPA topology и routes |
| Каталог | Создать стабильный container и состояние страницы без SDK | URL каталога и test applicationId |
| Product PDP | Сохранить строковый feedProductId в согласованном месте | Все PDP/SKU templates и test products |
| Commerce | Выбрать переход на PDP, callback основного SDK или custom PiP flow | Cart API, variant/store context и fallback |
| Наличие | Реализовать обработчик наличия и вызывать refreshProductsAvailability() при смене магазина | Пакетный stock API, источник выбранного магазина и семантика available в фиде |
| Security | Обновить действующую CSP и проверить registered origins | CSP, media origins и browser matrix |
| Release | Добавить feature flag, acceptance и client-side rollback | Test/live/VOD fixtures и порядок включения |
Если неизвестны SPA lifecycle, целевые браузеры или cart contract, оценка этих частей остаётся discovery scope. Базовый MPA-каталог с переходом на PDP можно оценивать отдельно.
Mobile
В приложении ритейлера подключите Mobile SDK. Он принимает тот же feedProductId, управляет нативным video entrypoint и плеером, а действие с товаром передаёт router или cart-команде приложения.
Web-скрипты из этого раздела нельзя переносить в произвольный WebView. Доступ к пакету, точная совместимая версия, callbacks и приёмка передаются в integration handoff конкретного проекта.
Проверка перед production
- ShopStory подтвердил точные домены,
applicationIdи включённые компоненты. - Основной bundle загружается,
window.ShopStorySDKопределён до вызоваshow(). - Каталог отображает контент нужного проекта.
- Тестовый
feedProductIdточно совпадает со строковым значением в последней принятой версии фида. - Mini-player появляется только на согласованных PDP и не перекрывает критичные элементы.
- Live-уведомление отображается только если оно включено и есть активный эфир.
- Callback корзины показывает успех или ошибку из фактического ответа commerce-системы.
- Страница остаётся работоспособной при сетевой ошибке ShopStory.
- CSP разрешает согласованные ресурсы: CSP.
- Проверены desktop и mobile web в целевых браузерах клиента.
Диагностика
| Симптом | Проверка |
|---|---|
ShopStorySDK не определён | Проверьте загрузку и выполнение bundle, CSP и отсутствие async при последовательной inline-инициализации |
Запрос bundle заблокирован, например ERR_BLOCKED_BY_CLIENT | Проверьте блокировщики рекламы и трекеров, расширения и настройки защиты браузера |
await showPlayer() завершился, но видео ещё нет | Promise подтверждает только инициализацию; проверьте запросы данных эфира и медиаресурсов в Network |
| Отображается неверный проект | Сверьте текущий hostname с доменами, переданными ShopStory |
| Каталог пуст | Проверьте публикацию эфира или записи и applicationId проекта |
Mini-player API возвращает active, но виджета нет | Передайте ShopStory URL PDP и название используемого шаблона |
| Mini-player не находит товар | Сравните ID на странице со значением из принятого фида без числового преобразования |
| Браузер блокирует ресурс | Сверьте console и Network с CSP и зарегистрированным origin |
| Кнопка «Купить» показывает неверный результат | Проверьте callback и ответ API корзины клиента |
При обращении в поддержку передайте URL страницы, время возникновения проблемы, браузер, applicationId и фрагмент Console/Network без cookies, токенов и персональных данных.