Расширенное подключение через JavaScript API

Расширенное подключение — это способ добавить Servicepipe Widget CAPTCHA на страницу сайта и управлять виджетом из JavaScript-кода.

Особенности подключения:

  • Доступно три варианта появления капчи: виджет уже стоит в нужном месте после загрузки страницы, виджет появляется на странице после определённого события (логику вы задаёте сами), модальное окно открывается после определённого события (логику вы задаёте сами).

  • Для создания и управления виджетом нужно написать JavaScript-код.

  • Виджет настраивается через опции JavaScript API.

  • Токен можно получить через callback-функцию, результат метода SPCaptcha.execute() или скрытое поле.

  • Этот способ подходит, если момент и способ показа капчи должны зависеть от логики вашего приложения.

Если вам достаточно постоянно показывать капчу в заданном месте страницы и настраивать её через HTML-атрибуты, используйте автоматическое подключение через HTML-атрибуты.

Как работает эта интеграция:

  1. Вы подключаете SDK Servicepipe Widget CAPTCHA на страницу и настраиваете запуск проверки через JavaScript API. Доступны два сценария на выбор:

    • Пользователь видит виджет с чекбоксом «Я не робот». Этот виджет может появиться сразу после загрузки страницы либо после заданного действия пользователя (момент настраиваете вы). Когда пользователь установит в чекбоксе флажок, откроется модальное окно.

    • Когда пользователь совершает заданное действие (например, жмёт кнопку «Войти»), откроется модальное окно.

  2. Пользователь открывает вашу страницу, взаимодействует с ней и доходит до открытия модального окна.

  3. Servicepipe рассчитывает bot score пользователя.

    Если bot score пользователя низкий, модальное окно закрывается автоматически. Проверка считается пройденной.

    Если bot score выше порогового значения, в модальном окне появляется задание капчи.

  4. Пользователь проходит капчу.

    Если прошёл неуспешно или поведение было похоже на бота, он получает новое задание. Новая капча может выдаваться бесконечно — это ловушка для ботов, которая заставляет их снова и снова тратить ресурсы на решение, не допуская до защищаемого действия.

    Если прошёл успешно, модальное окно закрывается. Параллельно с этим Servicepipe присылает в браузер токен, который свидетельствует, что капча пройдена человеком.

  5. Ваш JavaScript-код отправляет полученный токен на бекэнд вместе с данными защищаемого действия.

  6. Ваш бекэнд обращается к Servicepipe, чтобы проверить полученный токен. Если с токеном всё в порядке, можно разрешить пользователю выполнить защищаемое действие. Если токен не прошёл проверку, действие лучше отклонить — скорее всего, его выполняет злоумышленник.

Следуя шагам ниже, вы подключите Servicepipe Widget CAPTCHA через JavaScript API, выберете способ показа капчи, настроите обработку полученного токена на бекэнде и протестируете интеграцию.

При работе с этой статьёй вам может пригодиться справочник по интеграции. Откройте ссылки в новой вкладке, чтобы нужная информация всегда была под рукой: Методы управления виджетом, Опции метода SPCaptcha.render(), Опции метода SPCaptcha.execute(), События виджета, Ошибки виджета в браузере, Ошибки при серверной проверке токена.

1. Получите SiteKey и ApiKey

Мы передадим вам два значения:

  • SiteKey — публичный ключ виджета. На следующих шагах вы передадите его в JavaScript API, чтобы SDK узнал ваш сайт и отдал нужную конфигурацию капчи. SiteKey будет виден в коде страницы и не является секретом.

У вас может быть несколько SiteKey. Так бывает, если вы запросили несколько разных конфигураций капчи: например, одну менее сложную для страницы входа и одну более сложную для страницы регистрации. У каждой конфигурации будет свой SiteKey.

  • ApiKey — приватный серверный ключ. Ваш бекэнд использует его, когда обращается к API Servicepipe, чтобы проверить токен пользователя. По этому ключу наша система узнает вас как клиента и выдаст результат проверки.

ApiKey является секретом. Храните его только на бекэнде и не добавляйте его в HTML-код, JavaScript-код страницы и другие файлы, которые загружаются в браузер пользователя.

2. Подключите JavaScript-скрипт на страницу

Есть два варианта подключения скрипта. Выбор зависит от того, как ваш код должен узнать о том, что SDK загрузился и его методы стали доступны.

Вариант 1: когда SDK будет готов, он сам вызовет функцию инициализации капчи (вы создадите её на шаге 3). Функция должна находиться в глобальной области видимости.

Вариант 2: ваш код передаст функцию инициализации капчи (вы создадите её на шаге 3) непосредственно в SDK. Когда SDK будет готов, он вызовет эту функцию.

Если на вашем сайте используется Content Security Policy, браузер может заблокировать загрузку скрипта или iframe с капчей. В этом случае добавьте домен https://captcha.servicepipe.tech в правила script-src и frame-src.

Если вам подходит вариант 1 (SDK сам вызывает функцию инициализации), добавьте скрипт Servicepipe Widget CAPTCHA в тег <head> так:

<script
  src="https://captcha.servicepipe.tech/captcha.js?render=explicit&onload=initCaptcha"
  async
  defer
></script>

Здесь initCaptcha — имя функции инициализации. Вы можете выбрать для неё другое имя.

Если вам подходит вариант 2 (ваш код передаёт функцию инициализации в SDK), подключите SDK и файл с кодом приложения в теге <head>. Оба скрипта должны иметь атрибут defer, а файл приложения должен находиться после SDK:

<script
  src="https://captcha.servicepipe.tech/captcha.js?render=explicit"
  defer
></script>

<script src="/js/captcha-init.js" defer></script>

Браузер выполнит defer-скрипты в порядке их расположения: сначала SDK, затем captcha-init.js. Не добавляйте атрибут async, поскольку он не гарантирует порядок выполнения скриптов.

Параметры в URL выполняют следующие задачи:

Параметр Что делает

render=explicit

Отключает автоматическое создание виджета по HTML-атрибутам. Вы сами создадите виджет через JavaScript API.

onload=initCaptcha

Указывает функцию инициализации капчи, которую SDK вызовет, когда будет готов к работе.

3. Настройте показ капчи

На этом шаге вы выберете способ показа капчи, создадите функцию инициализации с нужной логикой и свяжете её со скриптом, подключённым на шаге 2.

JavaScript API поддерживает два сценария:

Способ Как работает

SPCaptcha.render(container, options)

Создаёт капчу в определённом месте страницы. Капчу можно показать сразу после загрузки SDK или после действия пользователя.

SPCaptcha.execute(options)

Открывает капчу в модальном окне.

Выберите подходящий сценарий. Дальше даём подробную инструкцию для каждого.

Сценарий 1. Показать капчу на странице через SPCaptcha.render()

1. Добавьте контейнер

Вставьте пустой контейнер в место страницы, где должна появиться капча:

<div id="signup-captcha"></div>

2. Напишите функцию инициализации

Создайте функцию инициализации — для примера назовём её initCaptcha(). Внутри вы:

  • подготовите опции виджета;

  • создадите виджет через SPCaptcha.render();

  • при необходимости добавите функции для обработки результата, ошибок и истечения токена;

  • сможете использовать методы управления виджетом;

  • при необходимости подпишетесь на события виджета.

Общая структура функции будет выглядеть так:

function initCaptcha() {
  let widget;

  const options = {
    // Опции виджета
  };

  widget = SPCaptcha.render("#signup-captcha", options);

  // Здесь можно подписаться на события виджета
}

Добавьте вызов SPCaptcha.render()

Для создания виджета вызовите внутри initCaptcha() метод:

SPCaptcha.render(container, options);

Метод принимает два аргумента:

  • container — контейнер, внутри которого появится капча;

  • options — объект с опциями виджета.

Контейнер можно передать как CSS-селектор:

"#signup-captcha"

Или как DOM-элемент:

document.querySelector("#signup-captcha")

Например:

function initCaptcha() {
  const widget = SPCaptcha.render("#signup-captcha", options);
}

Метод создаст капчу внутри контейнера и вернёт объект виджета.

Подготовьте объект с опциями

Передайте вторым аргументом SPCaptcha.render() объект с нужными опциями.

Опция Значение Что делает Обязательна

siteKey

Значение SiteKey, полученное вами от Servicepipe, например, O4FUxStKtioH1seP

Передаёт публичный ключ виджета. По этому ключу Servicepipe определяет, к какой интеграции относится виджет и какие настройки капчи нужно применить.

Да

language

ru или en.

По умолчанию: ru

Задаёт язык интерфейса капчи. Доступны два значения: ru (русский) и en (английский).

Если опция не указана, капча будет на русском.

Нет

callback

Ваша функция, принимающая токен

Задаёт функцию, которую SDK вызовет, если капча пройдена успешно. В эту функцию SDK передаст токен.

Функцию вы напишете далее.

Нет.

Но токен всё равно должен быть получен. Сделать это можно одним из способов: через опцию callback либо responseField, событие success или метод SPCaptcha.getResponse.

onError

Ваша функция, принимающая объект ошибки

Задаёт функцию, которую SDK вызовет, если при работе виджета возникнет ошибка в браузере. В эту функцию SDK передаст объект с error.code и error.message.

Функцию вы напишете далее.

Нет

onExpired

Ваша функция без аргументов

Задаёт функцию, которую SDK вызовет, когда срок действия уже полученного токена истечёт.

Функцию вы напишете далее.

Нет

onReady

Ваша функция без аргументов

Задаёт функцию, которую SDK вызовет после создания виджета и его перехода в состояние готовности.

Функцию вы напишете далее.

Нет

onChallengeVisible

Ваша функция без аргументов

Задаёт функцию, которую SDK вызовет, когда задание капчи станет видно пользователю.

Функцию вы напишете далее.

Нет

onChallengeHidden

Ваша функция без аргументов

Задаёт функцию, которую SDK вызовет при скрытии задания капчи: например, после успешного прохождения, ошибки или закрытия модального окна пользователем.

Функцию вы напишете далее.

Нет

responseField

true или false. Если опция не указана, поле не создаётся

Создаёт скрытое поле для токена внутри HTML-элемента виджета.

Если пользователь успешно пройдёт капчу, SDK запишет токен в это поле.

Нет.

Но токен всё равно должен быть получен. Сделать это можно одним из способов: через опцию callback либо responseField, событие success или метод SPCaptcha.getResponse.

responseFieldName

Имя поля, например sp-captcha-token.

По умолчанию: captcha-token

Задаёт имя скрытого поля с токеном, которое вы включили через responseField.

Если опция не указана, SDK создаст поле с именем по умолчанию — captcha-token.

Нет

Например, внутри initCaptcha() можно подготовить такой объект:

function initCaptcha() {
  const options = {
    siteKey: "<SITE_KEY>",
    language: "ru",
    responseField: true,
    responseFieldName: "sp-captcha-token"
  };

  const widget = SPCaptcha.render("#signup-captcha", options);
}

В этом объекте вы:

  • передали публичный ключ виджета через siteKey;

  • выбрали русский язык через language;

  • включили создание скрытого поля через responseField — в него SDK запишет токен, если пользователь успешно пройдёт капчу;

  • задали этому полю имя sp-captcha-token через responseFieldName.

Добавьте функции, которые вы указали в опциях

В качестве значения callback, onError, onExpired или другой callback-опции вы передали функцию. Её можно написать прямо внутри объекта options:

const options = {
  siteKey: "<SITE_KEY>",

  onExpired() {
    submitButton.disabled = true;
    status.textContent = "Пройдите проверку ещё раз.";
  }
};

Другой вариант — объявить функцию отдельно внутри initCaptcha() и передать ссылку на неё:

function handleExpired() {
  submitButton.disabled = true;
  status.textContent = "Пройдите проверку ещё раз.";
}

const options = {
  siteKey: "<SITE_KEY>",
  onExpired: handleExpired
};

Здесь handleExpired — функция, которую SDK вызовет после истечения срока действия токена.

Внутри функций, переданных в options, можно использовать методы управления виджетом, предусмотренные SDK. Для этого сохраните объект, который вернул SPCaptcha.render():

let widget;

widget = SPCaptcha.render("#signup-captcha", options);

В свойстве widget.id находится идентификатор созданного виджета:

const widgetId = widget.id;

Передавайте этот идентификатор методам управления, чтобы SDK понимал, с каким виджетом выполнить действие.

Если у вас на странице всего одна капча, эти методы можно вызывать без аргумента — SDK и так поймёт, что вы обращаетесь к единственному виджету.

Метод Что делает Когда пригодится

SPCaptcha.getResponse(widgetId)

Возвращает текущий токен. Если токен ещё не получен либо уже истёк, вернёт пустую строку.

Когда токен нужно прочитать позднее, а не обрабатывать сразу через callback или событие.

SPCaptcha.reset(widgetId)

Очищает токен и возвращает виджет в исходное состояние.

Важно: после истечения срока действия токена SDK очищает его автоматически. Дополнительно вызывать reset() только из-за истечения токена не требуется. reset() нужен для других случаев: например, если пользователь сбросил форму.

Когда пользователь начинает новое защищаемое действие или предыдущий сценарий нужно запустить заново.

SPCaptcha.destroy(widgetId)

Удаляет содержимое, обработчики и таймеры виджета. Сам внешний контейнер остаётся на странице.

При удалении компонента со страницы, переходе между экранами SPA или полной замене виджета.

Например, передадим в опцию onError функцию handleError. Если при работе капчи возникнет ошибка, эта функция удалит текущий виджет через SPCaptcha.destroy() и покажет пользователю кнопку для повторной загрузки виджета:

function initCaptcha() {
  const status = document.querySelector("#captcha-status");
  const retryButton = document.querySelector("#captcha-retry");
  let widget;
  function handleError(error) {
    console.error("CAPTCHA error:", error.code, error.message);
    if (widget) {
      SPCaptcha.destroy(widget.id);
      widget = undefined;
    }
    status.textContent =
    "Не удалось загрузить антибот-проверку. Нажмите «Повторить».";
    retryButton.hidden = false;
  }
  const options = {
    siteKey: "<SITE_KEY>",
    onError: handleError
  };
  function renderCaptcha() {
    widget = SPCaptcha.render("#signup-captcha", options);
  }
  retryButton.addEventListener("click", function() {
      retryButton.hidden = true;
      status.textContent = "";
      renderCaptcha();
  });
  renderCaptcha();
}

В этом примере:

  • handleError указана как значение опции onError;

  • SDK вызывает handleError, если при работе виджета возникает ошибка;

  • внутри handleError метод SPCaptcha.destroy() удаляет текущий виджет по идентификатору widget.id;

  • после удаления виджета функция показывает сообщение и кнопку «Повторить»;

  • обработчик кнопки скрывает её, очищает сообщение и повторно вызывает renderCaptcha();

  • renderCaptcha() создаёт новый виджет в том же контейнере.

Подпишитесь на события виджета (опционально)

Сначала создайте виджет и получите его объект. Затем вызовите метод subscribe():

const widget = SPCaptcha.render("#signup-captcha", options);

const unsubscribe = widget.subscribe(eventName, handler);

Передайте методу два аргумента:

  • eventName — название события;

  • handler — функция, которую SDK вызовет при наступлении события.

Метод вернёт функцию unsubscribe. Вызовите её, когда подписка больше не нужна.

Доступны следующие события:

Событие Когда возникает Что получает обработчик

ready

Виджет создан и готов к работе. Событие отправляется асинхронно после render().

Без данных

challenge-visible

Задание капчи стало видно пользователю.

Без данных

challenge-hidden

Задание начинает скрываться после успешной проверки, ошибки или отмены.

Без данных

success

SDK получил токен, записал его в скрытое поле, если оно включено, и запустил отсчёт срока действия токена.

Объект с event.token

expired

Срок действия токена истёк. Перед отправкой события SDK очищает токен.

Без данных

error

При работе виджета или iframe произошла ошибка.

Объект с event.code и event.message

closed

Модальное окно полностью закрылось. Событие возникает после challenge-hidden.

Без данных

reset

Для виджета вызван reset(). SDK очистил токен и вернул виджет в исходное состояние.

Без данных

destroy

Для виджета вызван destroy(). SDK удалил содержимое, обработчики и таймеры виджета.

Без данных

Например, так можно отправить событие об успешно пройденной капче в аналитику:

const widget = SPCaptcha.render("#signup-captcha", options);

const unsubscribeSuccess = widget.subscribe(
  "success",
  function(event) {
    window.analytics?.track("captcha_success");
  }
);

Если вы уже обрабатываете состояние через callback, onError и другие опции render(), дублировать ту же логику через события не нужно.

Выберите момент создания виджета

Если капча должна появиться сразу после готовности SDK, вызовите функцию создания виджета внутри initCaptcha():

function initCaptcha() {
  function renderCaptcha() {
    widget = SPCaptcha.render("#signup-captcha", options);
  }

  renderCaptcha();
}

Если капча должна появиться после действия пользователя, вызовите renderCaptcha() в обработчике этого действия:

function initCaptcha() {
  const showButton = document.querySelector("#show-captcha");

  function renderCaptcha() {
    widget = SPCaptcha.render("#signup-captcha", options);
  }

  showButton.addEventListener("click", renderCaptcha);
}

Пример полной функции инициализации

Ниже показана функция initCaptcha(), которая объединяет описанные выше действия. В примере капча появляется сразу после готовности SDK. Также настроены обработка ошибок, истечение токена, повторное создание виджета и необязательная подписка на события.

function initCaptcha() {
  const submitButton = document.querySelector("#signup-submit");
  const status = document.querySelector("#captcha-status");
  const retryButton = document.querySelector("#captcha-retry");
  let widget;
  let subscriptions = [];
  function removeSubscriptions() {
    subscriptions.forEach(function(unsubscribe) {
        unsubscribe();
    });
    subscriptions = [];
  }
  function handleError(error) {
    console.error("CAPTCHA error:", error.code, error.message);
    if (widget) {
      removeSubscriptions();
      SPCaptcha.destroy(widget.id);
      widget = undefined;
    }
    submitButton.disabled = true;
    status.textContent =
    "Не удалось загрузить антибот-проверку. Нажмите «Повторить».";
    retryButton.hidden = false;
  }
  function handleExpired() {
    submitButton.disabled = true;
    status.textContent = "Пройдите проверку ещё раз.";
  }
  const options = {
    siteKey: "<SITE_KEY>",
    language: "ru",
    responseField: true,
    responseFieldName: "sp-captcha-token",
    onError: handleError,
    onExpired: handleExpired
  };
  function subscribeToEvents(currentWidget) {
    subscriptions = [
      currentWidget.subscribe("success", function() {
          submitButton.disabled = false;
          status.textContent = "";
          retryButton.hidden = true;
          window.analytics?.track("captcha_success");
      }),
      currentWidget.subscribe("error", function(event) {
          window.analytics?.track("captcha_error", {
              code: event.code
          });
      }),
      currentWidget.subscribe("expired", function() {
          window.analytics?.track("captcha_expired");
      })
    ];
  }
  function renderCaptcha() {
    widget = SPCaptcha.render("#signup-captcha", options);
    subscribeToEvents(widget);
  }
  function retryCaptcha() {
    retryButton.hidden = true;
    status.textContent = "";
    if (widget) {
      removeSubscriptions();
      SPCaptcha.destroy(widget.id);
      widget = undefined;
    }
    renderCaptcha();
  }
  retryButton.addEventListener("click", retryCaptcha);
  renderCaptcha();
}

В этом примере:

  • initCaptcha() получает элементы интерфейса и создаёт переменные для хранения виджета и подписок;

  • объект options задаёт ключ, язык, скрытое поле и функции обработки;

  • handleError() и handleExpired() передаются в SDK через опции onError и onExpired;

  • renderCaptcha() создаёт виджет через SPCaptcha.render(), сохраняет его объект в переменной widget и добавляет подписки;

  • если возникает ошибка, handleError() отменяет подписки, удаляет текущий виджет через SPCaptcha.destroy(), отключает отправку формы и показывает кнопку «Повторить»;

  • subscribeToEvents() подписывается на события success, error и expired;

  • после успешной проверки обработчик события success включает кнопку отправки формы;

  • retryButton.addEventListener() связывает кнопку «Повторить» с функцией retryCaptcha();

  • после нажатия «Повторить» функция скрывает кнопку, очищает сообщение, удаляет оставшийся виджет, если он ещё существует, и вызывает renderCaptcha() повторно;

  • новый виджет создаётся в том же контейнере. Контейнер и остальные элементы формы не перезагружаются, поэтому введённые пользователем данные сохраняются;

  • последний вызов renderCaptcha() создаёт первый виджет сразу после выполнения initCaptcha().

3. Свяжите функцию инициализации со скриптом

Используйте вариант, который соответствует способу подключения скрипта, выбранному вами на шаге 2.

Если SDK должен сам вызвать функцию инициализации, сделайте её глобальной:

window.initCaptcha = initCaptcha;

Имя initCaptcha должно совпадать со значением параметра onload в URL скрипта.

Если код приложения подключён отдельным defer-скриптом после SDK, вызовите в этом файле SPCaptcha.ready(). Метод дождётся готовности SDK и DOM, а затем вызовет функцию инициализации:

SPCaptcha.ready(initCaptcha);

Сценарий 2. Открыть капчу в модальном окне через SPCaptcha.execute()

1. Подготовьте опции

Метод SPCaptcha.execute() открывает модальное окно с капчей и возвращает Promise. После успешного прохождения капчи результатом Promise будет токен:

const token = await SPCaptcha.execute(options);

Метод принимает следующие опции:

Опция Значение Что делает Обязательная

siteKey

Значение SiteKey, полученное от Servicepipe

Передаёт публичный ключ виджета. По нему Servicepipe определяет интеграцию и настройки капчи.

Да

language

ru или en.

По умолчанию: ru

Задаёт язык интерфейса капчи. Доступны два значения: ru (русский) и en (английский).

Если опция не указана, капча будет на русском.

Нет

callback

Ваша функция, принимающая токен

Вызывается после успешного прохождения капчи и получает токен. Её можно использовать вместо результата await.

Нет

Например:

const options = {
  siteKey: "<SITE_KEY>",
  language: "ru"
};

2. Создайте функцию инициализации

Создайте функцию инициализации — для примера назовём её initCaptcha(). Внутри найдите нужные элементы страницы и добавьте обработчик действия, после которого должна открыться капча.

Например, чтобы запускать проверку при отправке формы, можно написать такую функцию:

function initCaptcha() {
  const form = document.querySelector("#signup-form");

  form.addEventListener("submit", async function(event) {
    event.preventDefault();

    const token = await SPCaptcha.execute(options);
  });
}

Обработчик останавливает стандартную отправку формы и вызывает SPCaptcha.execute().

3. Обработайте результат проверки

При использовании await поместите вызов SPCaptcha.execute() в try…​catch:

try {
  const token = await SPCaptcha.execute(options);

  // Добавьте токен в запрос к своему бекэнду.
} catch (error) {
  // Обработайте отмену или ошибку проверки.
}

Если пользователь успешно пройдёт капчу, токен будет сохранён в переменной token.

Если пользователь закроет модальное окно, Promise будет отклонён с ошибкой execution-cancelled. Другие ошибки также попадут в блок catch.

Полный список ошибок виджета в браузере
Код ошибки Сообщение

container-not-found

Контейнер CAPTCHA не найден.

configuration-error

siteKey обязателен.

configuration-error

Не удалось определить адрес поставщика из URL SDK-скрипта.

configuration-error

CAPTCHA сообщила об ошибке.

iframe-load-failed

Не удалось загрузить iframe CAPTCHA.

iframe-load-failed

Не удалось загрузить iframe CAPTCHA за отведённое время.

token-expired

Срок действия токена CAPTCHA истёк.

execution-cancelled

Проверка CAPTCHA была отменена: пользователь закрыл модальное окно, оно закрылось автоматически или был вызван reset() или destroy().

widget-destroyed

Виджет был уничтожен. Например, вызвали execute() после destroy().

unknown-widget

Нет доступного виджета CAPTCHA для выполнения проверки. Например, вызвали execute() без widgetId, но на странице нет созданных виджетов.

Если вы используете опцию callback, SDK передаст токен в эту функцию.

Не обрабатывайте один и тот же результат одновременно через await и callback.

4. Добавьте возможность повторить проверку (опционально)

Если пользователь закрыл модальное окно или при проверке произошла ошибка, можно показать кнопку «Повторить». Её обработчик должен повторно вызвать функцию, внутри которой выполняется SPCaptcha.execute().

Страницу при этом перезагружать не нужно, поэтому введённые пользователем данные сохранятся.

5. Свяжите функцию инициализации со скриптом

Используйте вариант, который соответствует способу подключения скрипта, выбранному вами на шаге 2.

Если SDK должен сам вызвать функцию инициализации, сделайте её глобальной:

window.initCaptcha = initCaptcha;

Если код приложения подключён отдельным defer-скриптом после SDK, вызовите в этом файле SPCaptcha.ready(). Метод дождётся готовности SDK и DOM, а затем вызовет функцию инициализации:

SPCaptcha.ready(initCaptcha);

Пример полного подключения через SPCaptcha.execute()

Ниже показан весь процесс на примере формы регистрации. Пример включает защиту от повторного запуска проверки, обработку отмены и ошибок, кнопку повторной попытки и отправку токена на бекэнд.

Добавляем форму:

<form id="signup-form" action="/signup" method="post">
  <input type="email" name="email">
  <input type="password" name="password">

  <button id="signup-submit" type="submit">
    Зарегистрироваться
  </button>

  <p id="captcha-status"></p>

  <button id="captcha-retry" type="button" hidden>
    Повторить
  </button>
</form>

Создаём функцию инициализации:

function initCaptcha() {
  const form = document.querySelector("#signup-form");
  const submitButton = document.querySelector("#signup-submit");
  const status = document.querySelector("#captcha-status");
  const retryButton = document.querySelector("#captcha-retry");

  const options = {
    siteKey: "<SITE_KEY>",
    language: "ru"
  };

  let isChecking = false;

  async function submitWithCaptcha() {
    if (isChecking) {
      return;
    }

    isChecking = true;
    submitButton.disabled = true;
    retryButton.hidden = true;
    status.textContent = "Проверяем, что вы не бот...";

    try {
      let token;

      try {
        token = await SPCaptcha.execute(options);
      } catch (error) {
        retryButton.hidden = false;

        if (error.code === "execution-cancelled") {
          status.textContent =
            "Проверка отменена. Нажмите «Повторить», чтобы продолжить.";
          return;
        }

        console.error("CAPTCHA error:", error.code, error.message);
        status.textContent =
          "Не удалось пройти проверку. Нажмите «Повторить».";
        return;
      }

      status.textContent = "Отправляем данные...";

      const formData = new FormData(form);
      formData.set("sp-captcha-token", token);

      const response = await fetch(form.action, {
        method: form.method,
        body: formData
      });

      if (!response.ok) {
        throw new Error(
          `Form submission failed with status ${response.status}`
        );
      }

      status.textContent = "";
    } catch (error) {
      console.error("Form submission error:", error);
      status.textContent =
        "Не удалось отправить форму. Нажмите «Зарегистрироваться» ещё раз.";
    } finally {
      isChecking = false;
      submitButton.disabled = false;
    }
  }

  form.addEventListener("submit", function(event) {
    event.preventDefault();
    submitWithCaptcha();
  });

  retryButton.addEventListener("click", submitWithCaptcha);
}

Связываем функцию со скриптом одним из способов:

window.initCaptcha = initCaptcha;

Или:

SPCaptcha.ready(initCaptcha);

В этом примере:

  • Обработчик submit останавливает стандартную отправку формы и вызывает submitWithCaptcha().

  • Переменная isChecking не позволяет одновременно запустить несколько проверок.

  • SPCaptcha.execute() открывает модальное окно и ожидает прохождения капчи.

  • После успешной проверки await сохраняет полученный токен в переменной token.

  • Код добавляет токен в FormData под именем sp-captcha-token и отправляет форму на бекэнд.

  • Если пользователь закрыл модальное окно или произошла ошибка, код показывает сообщение и кнопку «Повторить».

  • После нажатия «Повторить» функция submitWithCaptcha() запускается снова. Страница не перезагружается, поэтому введённые данные сохраняются.

  • Ошибки отправки формы обрабатываются отдельно от ошибок капчи.

  • Блок finally завершает текущую попытку и снова включает кнопку отправки.

4. Отправьте токен на бэкенд

Это обязательный шаг.

Получив токен на бэкенде, далее вы проверите, действительно ли:

  • токен выдан сервисом Servicepipe;

  • токен относится к вашему SiteKey;

  • срок действия токена не истёк;

  • токен не был использован повторно.

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

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

Если вы создали виджет через SPCaptcha.render(), получить и передать токен можно несколькими способами:

  • Если включена опция responseField, SDK запишет токен в скрытое поле. Когда контейнер виджета находится внутри формы, это поле попадёт в данные формы при отправке. Имя поля задаётся через responseFieldName. По умолчанию используется имя captcha-token.

  • Если токен получен через callback или событие success, добавьте его в запрос самостоятельно.

  • Чтобы получить текущий токен позднее, вызовите SPCaptcha.getResponse(widgetId). Метод вернёт токен либо пустую строку, если токен ещё не получен или уже истёк.

Если вы открыли капчу через SPCaptcha.execute(), добавьте в запрос токен, который метод вернул через await или передал в callback.

Настройте бекэнд на получение поля, в котором вы передаёте токен. Например, если токен отправляется в поле sp-captcha-token, бекэнд должен считывать значение поля с этим именем.

5. Проверьте токен через серверный API

Чтобы проверить токен, отправьте с бекэнда такой запрос:

curl -H "X-Api-Key: <API_KEY>" \
  "https://captcha.servicepipe.tech/<SITE_KEY>/verify?jwt=<TOKEN>"

Замените значения:

  • <API_KEY> — на приватный ключ, который мы передали вам на шаге 1;

  • <SITE_KEY> — на публичный ключ виджета, который мы передали вам на шаге 1;

  • <TOKEN> — на токен, который получил ваш бекэнд.

Если ваш бекэнд может определить IP пользователя, также передайте его в параметре ip:

curl -H "X-Api-Key: <API_KEY>" \
  "https://captcha.servicepipe.tech/<SITE_KEY>/verify?jwt=<TOKEN>&ip=<USER_IP>"

Параметр ip необязательный, но рекомендуем передавать его, если это возможно. Если капчу прошли в одном окружении, а токен используют в другом (так часто работают фермы по прохождению капчи), параметр IP поможет это выявить. В этом случае наша система покажет, что проверка токена провалена, и вы не допустите злоумышленника до защищаемого действия.

6. Обработайте ответ проверки

Если токен прошёл проверку, Servicepipe вернёт ответ с success: true:

{
  "success": true,
  "request_id": "...",
  "site_key": "<SITE_KEY>"
}

Это значит, всё в порядке — капчу правда решил человек. В этом случае продолжайте обработку защищаемого действия. Например, если капча защищала страницу входа в ваш сервис, можно дать пользователю войти.

Если токен не прошёл проверку, Servicepipe вернёт success: false и поле error — объяснение, что было не так. Также может вернуть дополнительные диагностические поля, например, validation_check — информацию, истёк срок действия токена или ещё нет на момент проверки.

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

{
  "success": false,
  "error": "invalid_jwt",
  "validation_check": "expired"
}
Список возможных значений error
Значение поля error Описание

missing_required_params

Отсутствуют обязательные параметры. Например, не передан jwt в query-параметре.

invalid_jwt

Токен не прошёл проверку. Например, токен повреждён, просрочен, уже использован повторно или содержит некорректные iat или exp.

invalid_jwt_request_id

В JWT отсутствует или пустой requestId. Например, claim requestId не передан.

invalid_jwt_site_key

В JWT отсутствует или пустой siteKey. Например, claim siteKey не передан.

path_mismatch

siteKey из JWT не соответствует пути запроса /{site_key}/verify. Например, JWT предназначен для другого site_key.

storage_error

Временная ошибка серверного хранилища.

При success: false, не выполняйте защищаемое действие автоматически.

Если токен повреждён, просрочен, уже использован или содержит некорректные iat или exp, попросите пользователя пройти капчу повторно и отправьте новый токен на проверку.

Ошибки missing_required_params, invalid_jwt_request_id, invalid_jwt_site_key и path_mismatch могут указывать на неправильную настройку интеграции или некорректно сформированный запрос. Повторное прохождение капчи обычно их не устранит. Запишите ошибку в журнал и проверьте обязательные параметры, передаваемый токен и соответствие SiteKey в URL и токене.

Отдельный случай: результат проверки не удалось получить из-за временной ошибки Servicepipe. К таким ситуациям относятся storage_error, недоступность API, тайм-аут, сетевая ошибка или ответ HTTP 5xx. Повторное прохождение капчи не устранит причину ошибки. В этом случае можно использовать один из двух подходов:

  • Fail-closed: не выполнять защищаемое действие, пока токен не удастся проверить. Этот подход обеспечивает более строгую защиту и подходит для атакуемых или дорогостоящих операций, например отправки SMS или регистрации аккаунта.

  • Fail-open: разрешить защищаемое действие без подтверждённого результата проверки, если API временно недоступен. Этот подход сохраняет доступность сервиса, но снижает защиту от ботов. Используйте его только там, где такой риск допустим.

7. Проверьте интеграцию

Настройка закончена. Теперь рекомендуем пройти весь сценарий на тестовой странице:

  1. Откройте страницу, где подключён SDK.

  2. Убедитесь, что функция инициализации была вызвана после готовности SDK.

  3. Если вы используете SPCaptcha.render(), проверьте, что виджет появился в нужном месте страницы.

    Если вы используете SPCaptcha.execute(), выполните защищаемое действие и убедитесь, что модальное окно открылось в нужный момент.

  4. Пройдите капчу.

  5. Выполните защищаемое действие.

  6. Проверьте, что бекэнд получил токен.

  7. Проверьте, что бекэнд отправил токен в Servicepipe и получил success: true.

  8. Убедитесь, что защищаемое действие выполняется только после успешной серверной проверки.

  9. Проверьте сценарий с закрытием модального окна или истечением токена. Защищаемое действие не должно выполняться без нового действующего токена.

Если виджет не появился или модальное окно не открылось, проверьте, что:

  • скрипт загружается без ошибок;

  • значение siteKey указано верно;

  • для варианта с onload функция инициализации доступна в глобальной области видимости и её имя совпадает со значением параметра в URL;

  • для варианта с SPCaptcha.ready() код приложения выполняется после скрипта SDK;

  • контейнер, переданный в SPCaptcha.render(), существует на странице;

  • правила Content Security Policy не блокируют домен https://captcha.servicepipe.tech.

8. Интеграция закончена

Поздравляем, вы подключили Servicepipe Widget CAPTCHA! Теперь важные действия в вашем сервисе надёжно защищены от ботов.