Перейти к основному содержимому

Мини-плеер и live-виджет

Мини-плеер и live-виджет поддерживаются в двух форматах:

  1. Web SDK (рекомендуемый и простой путь) — копипастой скрипта в HTML-шаблон.
  2. Public API (дополнительный путь) — для кастомного UI, диагностики и серверного мониторинга.
Как читать эту страницу
  • Нужен mini-player на web PDP: читайте раздел про shopstory-pip в шаблоне карточки товара.
  • Нужен mini-player в mobile, где карточка товара уже открывается в WebView: читайте сценарий A.
  • Нужен mini-player в mobile с нативной карточкой товара: читайте сценарий B и Deep links.
  • Строите кастомный UI или backend-диагностику: API reference начинается только во второй половине страницы и нужен не всем.

Веб: mini-player в шаблоне карточки товара

Для большинства клиентов mini-player и live-виджет подключаются без ручной API-интеграции. Достаточно вставить shopstory-pip в HTML-шаблон карточки товара (или в общий шаблон страниц, где нужен виджет):

<!-- Вставляем в конец тега <body> -->
<script
id="shopstory-pip"
type="application/javascript"
src="https://app.shopstory.live/sdk/shopstory-pip-sdk/shopstory-pip-sdk-v1.x.min.js"
crossorigin="anonymous"
charset="utf-8"
async
></script>

Что это даёт:

  • скрипт подключает два виджета сразу: mini-player и live-виджет;
  • mini-player появляется в карточке товара, если у товара есть стрим/запись;
  • при наличии startTime в ответе API воспроизведение стартует с релевантного момента по товару;
  • live-виджет показывается только во время активного эфира;
  • скрипт можно размещать на всех страницах, кроме корзины/checkout (рекомендация);
  • один из виджетов можно отключить через менеджера/поддержку;
  • скрипт загружается async, без блокировки рендера страницы.
Что проверяет API, а что проверяет виджет

Успешный ответ /v2/mini-player/stream подтверждает, что backend нашёл релевантный стрим по товару. Он не подтверждает, что mini-player уже выведен в шаблоне карточки товара.

Для web-интеграции ShopStory отдельно включает mini-player под вашу верстку карточки товара: какой идентификатор товара использовать и куда вставлять виджет. Если API отвечает 200, а mini-player не появляется, проблема обычно в настройке под шаблон карточки товара, а не в Public API.

Минимальный web-flow:

  1. Вставьте shopstory-pip в HTML-шаблон карточки товара.
  2. Убедитесь, что идентификатор товара на странице стабилен и совпадает с данными товарного фида.
  3. Проверьте, что по этому товару /v2/mini-player/stream возвращает 200.
  4. После включения mini-player под ваш шаблон карточки товара виджет появится на PDP автоматически.

Mini-player встраивается в карточку товара, открывает релевантный фрагмент эфира и может сопровождать пользователя до покупки

Когда нужен API-путь

API нужен не для базового SDK-сценария, а для:

  • кастомной frontend-интеграции (без встроенных SDK-виджетов);
  • технической проверки, почему виджет не появился;
  • серверного мониторинга live/записей.
Итог по выбору формата

Если задача — быстро добавить mini-player в карточки товара и live-виджет на сайт, используйте только SDK-скрипт. API-путь нужен, когда вы сознательно строите свой интерфейс поверх ShopStory API.

Мобильные приложения: как добавить mini-player

Для мобильного приложения есть два корректных сценария.

Сценарий A. Карточка товара открывается как WebView вашей обычной PDP

Отдельная mobile-интеграция mini-player не нужна. Достаточно один раз встроить shopstory-pip в веб-шаблон карточки товара, и iOS/Android-приложение будет видеть тот же mini-player внутри WebView этой страницы.

Это самый быстрый путь, если продуктовая карточка в приложении уже рендерится через WebView.

Сценарий B. Карточка товара нативная

В этом случае mini-player как web-виджет в нативный экран не встраивается. Правильный сценарий:

  1. Ваш backend вызывает /v2/mini-player/stream по feedProductId или productCode.
  2. Мобильное приложение получает от вашего backend только результат проверки: есть ли релевантный стрим, streamId, startTime.
  3. Если стрим найден, приложение показывает компактный CTA рядом с товаром: например, «Смотреть эфир».
  4. По тапу приложение открывает ShopStory player в WebView по контракту из Deep links.
Безопасность mobile-интеграции

Не вызывайте Public API mini-player напрямую из iOS/Android-клиента с публичным applicationId. Для production-сценария используйте свой backend/proxy.

iOS (Swift)

Пример загрузки доступности mini-player через ваш backend:

load-mini-player.swift
struct ShopStoryMiniPlayerEnvelope: Decodable {
let status: Int
let body: Body?

struct Body: Decodable {
let streamId: String
let startTime: Int?
let playbackLink: String
}
}

func loadMiniPlayer(feedProductId: String) async throws -> ShopStoryMiniPlayerEnvelope.Body? {
let url = URL(string: "https://api.example.ru/shopstory/mini-player?feedProductId=\(feedProductId)")!
let (data, response) = try await URLSession.shared.data(from: url)

guard let http = response as? HTTPURLResponse, http.statusCode == 200 else {
return nil
}

let payload = try JSONDecoder().decode(ShopStoryMiniPlayerEnvelope.self, from: data)
return payload.status == 200 ? payload.body : nil
}

Если streamId найден, покажите CTA на нативной карточке товара и откройте WebView-плеер:

open-mini-player.swift
let streamUrl = "https://example.ru/live/?wv=1#/translation/\(streamId)"
let controller = ShopstoryWebViewController(streamUrl: streamUrl)
present(controller, animated: true)

Полный WKWebView-контроллер и bridge-события: Deep links.

Android (Kotlin)

Пример той же проверки через backend:

load-mini-player.kt
@Serializable
data class ShopStoryMiniPlayerEnvelope(
val status: Int,
val body: Body? = null,
) {
@Serializable
data class Body(
val streamId: String,
val startTime: Int? = null,
val playbackLink: String,
)
}

suspend fun loadMiniPlayer(feedProductId: String): ShopStoryMiniPlayerEnvelope.Body? {
val request = Request.Builder()
.url("https://api.example.ru/shopstory/mini-player?feedProductId=$feedProductId")
.build()

OkHttpClient().newCall(request).execute().use { response ->
if (!response.isSuccessful) return null

val raw = response.body?.string() ?: return null
val payload = Json.decodeFromString<ShopStoryMiniPlayerEnvelope>(raw)
return if (payload.status == 200) payload.body else null
}
}

Если streamId найден, откройте WebView-плеер:

open-mini-player.kt
val streamUrl = "https://example.ru/live/?wv=1#/translation/$streamId"
startActivity(
Intent(this, ShopstoryWebViewActivity::class.java)
.putExtra("streamUrl", streamUrl)
)

Полный WebView-экран и bridge-события: Deep links.

Optional: API reference и диагностика

Эту часть можно пропустить

Если вы используете shopstory-pip на web или backend/proxy + WebView в mobile, вам не нужно вызывать эти эндпоинты прямо из клиентского приложения.

Ниже — reference для кастомного frontend/UI, backend-диагностики и серверного мониторинга. Для iOS/Android production-сценария запросы к mini-player должны идти через ваш backend/proxy.

Мини-плеер по товару — GET /v2/mini-player/stream

GET https://app.shopstory.live/v2/mini-player/stream?application=<appId>&productCode=<sku>

Параметры:

ПараметрОбязательноОписание
applicationИдентификатор приложения
productCodeНетSKU/артикул товара
feedProductIdНетID товара из фида (используйте либо productCode, либо feedProductId)
feedProductGroupIdНетГруппа товара из фида (опционально для уточнения)

Примеры запросов:

GET /v2/mini-player/stream?application=<app-alias>&productCode=<sku>
GET /v2/mini-player/stream?application=<app-alias>&feedProductId=<feed-product-id>

Пример ответа:

{
"serverTime": "<timestamp>",
"status": 200,
"body": {
"streamId": "<stream-id>",
"streamStatus": "completed",
"productId": "<shopstory-product-id>",
"playbackLink": "https://cdn.example.com/path/to/playlist.m3u8",
"feedProductId": "<feed-product-id>"
}
}

playbackLink используйте для открытия плеера, streamStatus показывает состояние найденного стрима (online или completed). Поле startTime (если присутствует) задаёт смещение в секундах для старта VOD с нужного момента. На практике это смещение считается от старта трансляции до момента, когда товар был показан в эфире, поэтому запись открывается сразу на релевантном эпизоде.

Реальные варианты ответа:

  • HTTP 200 + status: 200, когда стрим найден.
  • HTTP 400 + status: 400, если не передан ни productCode, ни feedProductId.
  • HTTP 404 + status: 404, если для товара нет подходящего стрима.

Любой live — GET /v2/mini-player/online

Получить любую актуальную live-трансляцию для виджета «Сейчас в эфире»:

GET https://app.shopstory.live/v2/mini-player/online?application=<appId>

Если live-стрим есть, в body.online приходит объект трансляции. Если live нет, API возвращает пустой body.

{
"serverTime": "<timestamp>",
"status": 200,
"body": {}
}

Быстрый статус — GET /v3/translation/quick-state

Используйте для дешёвого поллинга UI:

GET https://app.shopstory.live/v3/translation/quick-state?translationId=<streamId>

Ответ:

{
"status": 200,
"serverTime": "<timestamp>",
"body": {
"translationState": "completed",
"translationId": "<stream-id>",
"expires": "<expires-at>"
}
}

translationState может принимать значения: draft, confirmed, online, completed, ''.

Аутентификация

Эндпоинт quick-state публичный, поэтому applicationId не требуется. Если вы участвуете в бете токенов, можно добавить заголовок Authorization: Bearer ... — клиент автоматически сопоставится.

Как интерпретировать диагностику

НаблюдениеЧто это значитСледующее действие
/v2/mini-player/stream возвращает HTTP 404Для товара нет связанного стрима или SKU/feedProductId не совпадает с фидомПроверьте связку товара со стримом и значения в XML/YML
/v2/mini-player/stream возвращает HTTP 200, но виджета на PDP нетBackend здоров, но mini-player ещё не включён под ваш шаблон карточки товара или шаблон был изменёнСверьте шаблон карточки товара и обратитесь в поддержку ShopStory
/v2/mini-player/online возвращает 200 с пустым bodyПрямо сейчас live-эфира нетТестируйте completed/VOD сценарий или дождитесь live
quick-state возвращает completedДля live-widget это уже не live, но запись доступна для мини-плеера/VOD-сценарияИспользуйте playbackLink и startTime из /v2/mini-player/stream

Чек-лист проверки mini-player и live-виджета

  1. На странице товара подключён shopstory-pip и отсутствуют блокирующие оверлеи.
  2. SKU/ID в карточке товара совпадает с тем, что приходит в XML/YML фиде.
  3. Запрос /v2/mini-player/stream по этому SKU/ID возвращает status: 200 и body.playbackLink.
  4. Если API отвечает 200, но mini-player на PDP нет, значит mini-player ещё не включён под ваш шаблон карточки товара или шаблон был изменён.
  5. Во время реального эфира /v2/mini-player/online отдаёт body.online, и виджет появляется на странице.
  6. Для мобильного сценария WebView события add-product и open-product обрабатываются нативным слоем.

Далее: