Перейти к содержанию

Справочник по виджету

Виджет Ziex Try-On — один скрипт, который добавляет на страницу товара окно примерки. Он рисует кнопку-launcher, окно с шагами загрузки, прогресса и результата и необязательную галерею «Мои образы». С API Ziex Try-On виджет общается сам; ваша страница только настраивает его и слушает его события.

Первую работающую страницу покажет быстрый старт на HTML. Если CMS-модуль загружает виджет по требованию, прочитайте Отложенную загрузку и подхват. Магазину с Content-Security-Policy нужны директивы со страницы CSP.

Подключение

<script src="https://api.ziex-tryon.com/embed/tryon-embed.js"></script>
<script>
  window.TryOn.init({ apiKey: 'pk_YOUR_PUBLISHABLE_KEY' });
</script>
  • Скрипт — один адрес для всех магазинов. Версия определяется свойством TryOn.version, а не адресом.
  • На публичной странице используйте публикуемый ключ (pk_…). Секретный ключ (tryon_…) в исходном коде страницы держать нельзя: он ещё и открывает вход в клиентский портал. Публикуемый ключ работает только с домена, к которому он привязан.
  • Ключ, который начинается с pk_test_ (или tryon_test_), — тестовый: в шапке окна появляется значок «ТЕСТ», а на примерку отвечает картинка-заглушка, без списаний.
  • Виджет обращается к тому адресу, с которого загружен. Опцию apiUrl задавайте, только если отдаёте скрипт с другого адреса.

TryOn.init(options)

init() запускает виджет. Обязателен только apiKey: без него виджет пишет ошибку в консоль и ничего не делает. Повторный init() целиком заменяет конфигурацию, от прошлого вызова ничего не переносится (для частичного изменения есть update()). Исключение — уже отправленная примерка: она сохраняет ключ, адрес API и товар, с которыми была отправлена.

Подключение и товар

Опция Тип По умолчанию Описание
apiKey строка – (обязательна) Публикуемый ключ вашего магазина.
apiUrl строка origin из src скрипта Базовый URL API. Завершающий слэш убирается.
productImage строка определяется по странице Картинка вещи: URL https:// или data: URI. Если не задана, берётся из разметки товара на странице (JSON-LD Product, og:image, затем первое крупное изображение).
productTitle строка определяется по странице Название товара. Если не задано, берётся из JSON-LD, og:title, микроразметки товара или <h1>.
productUrl строка адрес самой страницы Ссылка на товар. Сохраняется вместе с примеркой и показывается вам рядом с заданием. В значении по умолчанию отбрасываются трекинговые параметры. Сохраняются только ссылки http(s).
productSku строка определяется по странице Артикул товара. Принимается для совместимости; окно сейчас его не показывает.
productPrice строка определяется по странице Цена товара в том виде, как задана. Принимается для совместимости; окно сейчас её не показывает.
modelImage строка нет URL или data: URI готового фото модели. Покупатель может заменить его своим. С публикуемым ключом фото всегда отправляется как загрузка, поэтому URL должен читаться кросс-доменно (CORS).
category строка tops Категория вещи: tops, outerwear, bottoms, one-pieces или auto. Старое значение dresses читается как one-pieces. Покупатель видит категории, которые поддерживает ваш аккаунт.
lockCategory boolean false Вместе с заданной category прячет выбор категории и использует её как есть.
mode строка quality quality или balanced. Любое другое значение превращается в quality. Покупателя об этом не спрашивают.
integration строка widget/<TryOn.version> Кто управляет виджетом, в виде имя/версия (например shop-theme/2.3). Имя в нижнем регистре, всё значение не длиннее 64 символов. Всё остальное заменяется значением по умолчанию. Метка сохраняется в задании, чтобы нам было проще помочь, когда что-то идёт не так.

Внешний вид и поведение

Опция Тип По умолчанию Описание
lang строка из <html lang> ru или en. ru, если язык страницы начинается с ru, иначе en.
launcher boolean true false — без плавающей кнопки и без запросов при init(); окно открывает ваша страница через TryOn.open().
launcherPosition строка right right или left.
theme строка light light, dark или auto. auto ориентируется на яркость body страницы (затем html) при каждом открытии окна; нечитаемый фон считается светлым.
accent строка «чернильный» (#18181B) Любой CSS-цвет. Красит главную кнопку, полосу прогресса и фокус. Цвет текста на нём подбирается для читаемого контраста. Недопустимое значение игнорируется.
container строка body CSS-селектор элемента, в который монтируется виджет. Если ничего не найдено, используется body.
cabinet boolean false true включает «Мои образы» и «Запомнить это фото»: результаты и, только если покупатель отметил галочку, его фото хранятся в браузере покупателя (IndexedDB) до 30 дней. При false виджет не хранит в браузере ничего, кроме записи об идущей примерке (см. Примерка переживает своё окно).
debug boolean false Пишет в консоль диагностические строки с префиксом [TryOn].

Ограничения по времени

Все значения — положительное число миллисекунд (числовая строка преобразуется). Всё остальное в init() заменяется значением по умолчанию, а в update() игнорируется.

Опция По умолчанию Что ограничивает
submitTimeoutMs 30000 Ожидание ответа на отправку примерки и заголовков сохраняемой картинки результата.
pollTimeoutMs 15000 Каждый запрос статуса.
bodyTimeoutMs 15000 Чтение небольшого JSON-ответа после получения заголовков.
resultImageTimeoutMs 120000 Загрузка картинки результата для копии в «Моих образах».
attemptMaxMs 2700000 (45 мин) Как долго отправленная примерка отслеживается, считая с момента отправки. Потом попытка заканчивается событием error с code равным TIMEOUT.
lookupGraceMs 120000 (2 мин) Сколько времени ответ «не найдено» ещё не считается окончательным, когда виджет ищет примерку с потерянным ответом, и сколько он ждёт хоть какого-то ответа сервера, прежде чем сообщить о потере соединения.
overloadedWindowMs 60000 Окно, в котором отклонённая примерка отправляется повторно (см. Сервер занят).

Менять их приходится редко. attemptMaxMs соответствует самому долгому времени жизни задания на нашей стороне.

Пример

<script src="https://api.ziex-tryon.com/embed/tryon-embed.js"></script>
<script>
  window.TryOn.init({
    apiKey: 'pk_YOUR_PUBLISHABLE_KEY',
    productImage: 'https://shop.example/img/blue-jacket.jpg',
    productTitle: 'Синяя куртка',
    productUrl: 'https://shop.example/blue-jacket',
    category: 'outerwear',
    lockCategory: true,
    lang: 'ru',
    theme: 'auto',
    accent: '#0F766E',
    cabinet: true
  });
</script>

Методы и свойства

Член Описание
TryOn.init(options) Запускает виджет. См. выше.
TryOn.open() Открывает окно. До init() ничего не делает. Так окно открывают при launcher: false.
TryOn.close() Закрывает окно. Уже отправленная примерка продолжает работать (см. ниже).
TryOn.update(options) Меняет работающую конфигурацию без перерисовки. Принимает опции init(); меняются только переданные ключи. Если вызвать до init(), работает как init().
TryOn.destroy() Убирает виджет со страницы и завершает отправленную примерку. Также снимает все слушатели событий.
TryOn.on(event, fn) Подписка на событие. Одна и та же функция подписывается один раз.
TryOn.off(event, fn) Отписка. Без fn снимает все слушатели этого события.
TryOn.version Версия виджета строкой в формате semver (например 1.2.0). Читается до init().

update() или destroy()

update() и destroy() не взаимозаменяемы.

  • update() только меняет конфигурацию. Ничего не перерисовывается, а уже отправленная примерка сохраняет ключ, адрес API и товар и доходит до конца. Новые значения применяются при следующем открытии или отправке. В открытом окне новая картинка вещи показывается сразу.
  • destroy() завершает отправленную примерку. Её задание уже создано и оплачено, поэтому результат теряется, а запись, которую виджет ведёт для неё, удаляется. Следующий init() ничего не подхватит.

Одностраничные сайты

Когда покупатель переключает товар или вариант или меняется маршрут, вызывайте TryOn.update({ … }). Не вызывайте destroy() с последующим init() и не вызывайте destroy() из слушателя closed. И то и другое выбрасывает примерку, за которую покупатель уже заплатил.

// Переключён вариант на одностраничной странице товара:
window.TryOn.update({
  productImage: variant.imageUrl,
  productTitle: variant.title,
  productUrl: variant.url
});

События

window.TryOn.on('result', function (data) {
  console.log(data.result_url, data.job_id, data.processing_time_ms, data.background);
});
window.TryOn.on('error', function (err) {
  console.warn(err.code, err.message, err.detail, err.background);
});
Событие Данные Когда
opened нет Окно открыто.
closed нет Окно закрыто.
upload_started нет Покупатель нажал «Примерить», виджет начал отправку. Один раз на примерку.
upload_completed статус завершённого задания Задание успешно завершено. Приходит вместе с result.
result { result_url, job_id, processing_time_ms } Результат готов.
error объект Error Примерка не удалась или время ожидания вышло.
ready { job_id, kind, background } Исход ждёт следующего открытия окна. См. ниже.

Подробности:

  • result: result_url — адрес картинки. Считайте его временным и не стройте на нём собственное хранилище. processing_time_ms — время обработки задания.
  • error — объект Error. err.message — текст, который сам виджет показывает покупателю на языке страницы. err.code равен TIMEOUT, когда время ожидания вышло, OVERLOADED, когда сервер оставался занятым во всех повторах, а в остальных случаях — коду неудавшегося задания. err.detail содержит сырой текст сервера только для ваших логов: покупателям его показывать нельзя.
  • background: true. Отправленная примерка отслеживается и при закрытом окне. События, пришедшие в этот момент, несут в данных background: true (err.background для error). При открытом окне флага нет, поэтому слушатели, написанные без учёта флага, продолжают работать.
  • ready. Исход (результат или ошибка) пришёл при закрытом окне или на более ранней странице той же вкладки. kind — result или error; background всегда true. Событие приходит после собственных событий исхода (upload_completed, result или error), поэтому страница, которая открывает окно в слушателе ready, не получит этих событий с флагом фона для исхода, который уже на экране. Следующая страница вкладки повторно его не отправляет.
  • Тайминг. Если задание завершилось при открытом окне, result приходит через доли секунды после финального статуса, а при медленной загрузке картинки — до 5 секунд спустя.

Исключения, брошенные слушателем, перехватываются и на виджет не влияют.

Примерка переживает своё окно

С момента отправки примерки задание существует на нашей стороне и оплачено. Поэтому виджет не отменяет ничего, когда покупатель закрывает окно:

  • Виджет продолжает следить за заданием в фоне. События upload_completed, result и error по-прежнему приходят, с background: true.
  • Исход показывается при следующем открытии окна. Если включена галерея «Мои образы», результат сохраняется туда как обычно.
  • Фото, которые ещё готовятся, — другое дело: ничего не отправлено, поэтому закрытие окна отменяет такую попытку и ничего не отправляет.
  • Одновременно идёт только одна примерка. Пока она выполняется, повторное нажатие «Примерить» отклоняется.

Она переживает смену страницы в той же вкладке. Перед отправкой виджет записывает небольшую запись в sessionStorage вкладки: ключ идемпотентности, номер задания, когда оно известно, время отправки, оценку времени, категорию и товар. Фото, ключа API и адреса API в записи нет. Следующая страница сайта, которая вызывает TryOn.init() с тем же ключом, подхватывает запись и продолжает следить за заданием. Подходят перезагрузка страницы, переход на другую страницу товара и навигация внутри одностраничного сайта. Закрытая вкладка теряет запись; тогда результат виден только в клиентском портале и в истории заданий.

Пока исход ждёт, виджет:

  • ставит значок на launcher и меняет его доступное название;
  • выставляет на элементе <html> атрибут data-tryon-ready: result или error;
  • отправляет ready (один раз, на странице, где пришёл исход).
/* Отметьте свою кнопку при launcher: false или с собственным триггером */
html[data-tryon-ready] .my-tryon-button::after {
  content: "";
  display: inline-block;
  width: 8px;
  height: 8px;
  margin-left: 6px;
  border-radius: 50%;
  background: #16a34a;
}
html[data-tryon-ready="error"] .my-tryon-button::after { background: #dc2626; }

Флаг остаётся выставленным на каждой следующей странице вкладки, пока покупатель не откроет окно и не увидит исход. События исхода уходят один раз, на странице, где он пришёл; следующие страницы лишь показывают значок и флаг.

Если ответ на отправку потерялся (ошибка прокси, оборванное соединение, таймаут), виджет не сообщает о сбое, а ищет примерку по её ключу идемпотентности: одно нажатие не превращается в два списания, и результат не пропадает. Если сервер вообще недоступен в течение lookupGraceMs, виджет сообщает о потере соединения.

Сервер занят

Когда все слоты обработки изображений на сервере заняты, API отклоняет примерку ответом 503 с кодом OVERLOADED. Ничего не создаётся и не списывается, поэтому виджет отправляет тот же запрос с тем же ключом идемпотентности после паузы Retry-After (не меньше 1 секунды, не больше 30, а при отсутствии заголовка — 5 секунд). Повторов не больше 3, и только пока повтор укладывается в 60 секунд от первой отправки (overloadedWindowMs). Во время ожидания окно сообщает, что сейчас много примерок, не показывает проценты и просит остаться на странице. Если повторы исчерпаны, попытка завершается событием error с code равным OVERLOADED и кнопкой повтора. Закрытие окна повторы не останавливает; destroy() останавливает.

Тестовые ключи

Ключ, начинающийся с pk_test_ или tryon_test_, добавляет в шапку окна значок «ТЕСТ». Примерка с тестовым ключом не уходит в модель и не списывается; результат — фиксированная картинка-заглушка. Значок следует за ключом, с которым отправлена текущая примерка, поэтому update({ apiKey }) показывает или убирает его в открытом окне сразу. tryon_test без завершающего подчёркивания — обычный ключ.

Оформление

По умолчанию окно светлое и рисуется только из CSS-переменных. Виджет ставит на свой хост-элемент класс ziex-tryon-host. Задавайте переменные на этом классе в собственной таблице стилей:

.ziex-tryon-host {
  --tryon-accent: #0F766E;
  --tryon-radius: 8px;
  --tryon-font: "Inter", system-ui, sans-serif;
  --tryon-launcher-bottom: 96px;
}
Переменная Что задаёт
--tryon-accent, --tryon-accent-fg Главная кнопка, полоса прогресса, фокус и цвет текста на них. Опция accent задаёт обе; если вы задаёте в CSS только --tryon-accent, задайте и --tryon-accent-fg (на светлой теме по умолчанию белый).
--tryon-bg, --tryon-surface, --tryon-fg, --tryon-muted, --tryon-border Фон окна, панели, текст, второстепенный текст, линии.
--tryon-danger, --tryon-success Цвета ошибки и успеха.
--tryon-font Семейство шрифта.
--tryon-radius Радиус скругления окна и его элементов.
--tryon-scrim Цвет затемнения страницы за окном.
--tryon-shadow-window, --tryon-shadow-launcher Тени.
--tryon-launcher-bottom, --tryon-launcher-side Отступ launcher от края страницы.

Заданные вами цветовые переменные действуют в обеих темах, поэтому проверяйте контраст в той теме, которую видят ваши покупатели. Надёжнее опция accent: она ещё и подбирает читаемый цвет текста.

На телефоне (480 px и уже) окно становится листом на всю высоту, а страница за ним не прокручивается, пока окно открыто.

Совместимость

TryOn.version следует семантическому версионированию. В пределах мажорной версии опции и события только добавляются: могут появиться новые необязательные опции и события, существующие сохраняют смысл. Запись подхвата, флаг html[data-tryon-ready], событие ready и интерфейс лоадера заморожены для версии 1; см. Отложенную загрузку и подхват.