JavaScript Tag
Install
Insert the following tag in the <head> of your HTML file before your main script:
1
2
3
<script>
(()=>{"use strict";let e;var t={};t.d=(e,r,n)=>{var i=(r,n)=>{for(var i in r)t.o(r,i)&&!t.o(e,i)&&Object.defineProperty(e,i,{enumerable:!0,[n]:r[i]})};i(r,"get"),i(n,"value")},t.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),t.r=e=>{"u">typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var r={};t.r(r),t.d(r,{factory:()=>j,initChallenges:()=>O,initPhishing:()=>_,runChallenge:()=>T,setUserId:()=>U});let n={integration:{type:"UNKNOWN",version:"0.0.0"}},i={getCatcher:()=>{let e=document.createElement("div");return e.style.width="0px",e.style.height="0px",e.style.display="none",e}},o=e=>{"function"==typeof(null==e?void 0:e.unref)&&e.unref()},l=(e,t)=>{e.nativeId=t,e.isUnreffed&&o(t)},a=(e,t,r)=>{let n=Math.max(t-Date.now(),0);l(e,setTimeout(n>0x7fffffff?()=>a(e,t,r):r,Math.min(n,0x7fffffff)))},s=e=>new Promise(t=>(function(e,t=0,...r){let n,i=()=>e(...r),s={nativeId:void 0,isUnreffed:!1,isCancelled:!1};return t>0x7fffffff?a(s,Date.now()+t,i):l(s,setTimeout(i,t)),n=clearTimeout,{cancel:()=>{s.isCancelled=!0,n(s.nativeId)},unref:()=>{s.isUnreffed=!0,o(s.nativeId)}}})(t,e)),u=()=>void 0;function c(e,t,r,n,i,o,l){try{var a=e[o](l),s=a.value}catch(e){r(e);return}a.done?t(s):Promise.resolve(s).then(n,i)}function d(e){return function(){var t=this,r=arguments;return new Promise(function(n,i){var o=e.apply(t,r);function l(e){c(o,n,i,l,a,"next",e)}function a(e){c(o,n,i,l,a,"throw",e)}l(void 0)})}}let f="__prt__",h=f+"preload__runners_controller",p=Symbol("timeout"),y=function(e){return new Promise(function(t,r){let n=0;e.forEach(i=>{i.then(t).catch(function(t){++n===e.length&&r(t)})})})};function v(){let e=u,t=u;return{promise:new Promise((r,n)=>{e=r,t=n}),resolve:e,reject:t}}let m=()=>{let e=v(),t=e.resolve,r=e.reject,n=()=>{t=null,r=null},i={current:e.promise,busy:()=>{t||(i.current=(e=v()).promise,t=e.resolve,r=e.reject)},ready:e=>{t&&t(e),n()},failed:()=>{r&&r(),n()}};return i},g=e=>({then:t=>{if(t){let r=t(e);return r&&"function"==typeof r.then?r:g(r)}return g(e)}});function w(e,t,r,n,i,o,l){try{var a=e[o](l),s=a.value}catch(e){r(e);return}a.done?t(s):Promise.resolve(s).then(n,i)}function P(){return(P=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e}).apply(this,arguments)}let b=(e={},t=>{let r,n,i,o;if(e[t])return e[t];let l=(n=f+(r=String(Math.random()).replace("0.","")),window[n]={},(i=document.createElement("script")).src=t,i.dataset.id=r,i.async=!0,document.head.append(i),o=()=>{i.remove(),delete window[n]},new Promise((e,t)=>{i.onload=()=>{if(!window[n].r||"function"!=typeof window[n].r){t(Error("Not valid script loaded")),o();return}e(window[n].r),o()},i.onerror=()=>{o(),t(Error("Script load error"))}}));return e[t]=l,l.catch(()=>{delete e[t]}),l}),C="https://verify.botbye.com",j=e=>{var t;let r,o,l,a,c,f,v,j,O,T,U,_,E,{initChallenges:I,runChallenge:S,setUserId:x,initPhishing:N}=(t=e||C,r=Date.now(),o={api:m(),load:m(),init:m()},a=(l=e=>()=>o[e].current)("api"),c=l("init"),f=l("load"),v=()=>f().then(a),j=!1,O=!1,T=e=>{var n,l,c;let f;if(j)return;j=!0;let h={url:e.url,reload:O};(f=0,n=()=>{var e;return(e=function*(){++f;let e=Date.now();return(yield b((t||h.url)+"/client/v1.js")).bind(null,{s:e,r:f,i:r})},function(){var t=this,r=arguments;return new Promise(function(n,i){var o=e.apply(t,r);function l(e){w(o,n,i,l,a,"next",e)}function a(e){w(o,n,i,l,a,"throw",e)}l(void 0)})})()},l=O?1:5,c="Timeout",d(function*(){let e=[];for(let t=0;t<l;t++)try{return e.push(n()),yield function(e,t){return d(function*(){let r=null,n=new Promise(e=>{r=setTimeout(()=>{setTimeout(()=>{e(p)},100)},3e3)}),i=yield Promise.race([e,n]);if(r&&clearTimeout(r),i===p)throw Error(t);return i})()}(y(e),c)}catch(e){if(t===l-1)throw e;yield s(100)}throw Error(c+" ("+l+" attempts)")})()).then(e=>{h.reload&&(o.init.busy(),o.api.busy());let t=e();return v=()=>g(t),a=()=>g(t),o.api.ready(t),o.load.ready(),!0}).catch(e=>{var t,r;let n,l;j=!1,O=!0,l=(t=e)instanceof Error?t.message:"UNKNOWN",o.api.ready((r="[Error] Main script load error "+l,{setUserId:u,runCaptcha:()=>({dispose:u,promise:Promise.reject()}),runChallenge:n=()=>Promise.resolve(r),initChallenges:()=>Promise.resolve(n),initPhishing:()=>Promise.resolve(i)})),o.init.ready(),setTimeout(()=>{T(h)},1e3)})},U=!1,_=e=>{if(U)return;let t=window[h];if(t&&"function"==typeof t.r){let e=t.r({s:Date.now(),r:0,i:r});v=()=>g(e),a=()=>g(e),o.api.ready(e),o.load.ready(),U=!0;return}T(e)},{initChallenges:e=>{var t,r;let i;return r=(t=P({internal:e.internal||n},e)).url+"/challenges/v2/"+t.siteKey,(i=document.createElement("link")).rel="preload",i.as="script",i.href=r,document.head.appendChild(i),_(t),v().then(e=>e.initChallenges(t)).then(()=>{c=()=>g(void 0),o.init.ready()}),c().then(()=>E)},runChallenge:E=e=>c().then(a).then(t=>t.runChallenge(e)),runCaptcha:e=>{let t=v().then(({runCaptcha:t})=>t(e));return{dispose:()=>{t.then(e=>e.dispose())},promise:Promise.resolve(t.then(e=>e.promise))}},setUserId:e=>{v().then(t=>t.setUserId(e))},initPhishing:e=>(_(e),a().then(t=>t.initPhishing(P({internal:e.internal||n},e))))});return{initChallenges:t=>I(Object.assign({url:t.api||e||C,siteKey:t.clientKey,ver:"1.2.2",internal:{integration:{version:"1.3.1",type:"JS_TAG"}}},t)),runChallenge:S,setUserId:x,initPhishing:t=>N(Object.assign({url:t.api||e||C,internal:{integration:{version:"1.3.0",type:"JS_TAG"}}},t))}},{initChallenges:O,runChallenge:T,setUserId:U,initPhishing:_}=j(C);window.botbye=r})();
</script>
Configuration
Init BotBye on your script with your project client-key:
1
2
3
4
window.botbye.initChallenges({
// Use your client-key
clientKey: "00000000-0000-0000-0000-000000000000"
});
Usage
Generate token using runChallenge and send this token in any convenient way to the backend. For example in x-botbye-token header:
1
2
3
4
5
6
7
8
9
10
11
12
const botByeToken = await window.botbye.runChallenge();
fetch(
'https://domain.com',
{
method: "POST",
headers: {
// "x-botbye-token" is an example — send this token in any convenient way.
"x-botbye-token": botByeToken
}
}
)
User identification
Call setUserId after a successful authentication to associate the current session with a user. This helps BotBye detect multi-account abuse.
1
2
3
4
5
6
7
const response = await login({ username, password });
if (response.userId) {
window.botbye.setUserId(response.userId);
}
Sessions
BotBye! records a timeline of user actions on your site — page changes and clicks — that operators can review in the admin panel. For a click, BotBye! stores a short text label read from the clicked element so the action stays recognizable.
Hiding personal data
If an element can show personal data — a user name, email, account or card number, and so on — mark it with the data-bb-not-track attribute to keep that text out of the recording. The attribute works on the element itself or on any of its ancestors, so wrapping a region protects everything inside it.
Give the attribute a value to record that value instead of the element's real text:
1
<button data-bb-not-track="Account menu">John Doe — john@example.com</button>
Leave the attribute empty to record no text at all — only the click position is stored:
1
2
3
<div data-bb-not-track>
<!-- clicks inside are recorded without any element text -->
</div>
Disabling Sessions
Sessions run by default. To turn them off completely, add withoutSessions: true to the options you pass when you initialize BotBye! — initChallenges, or the plugin / component options in Vue:
1
2
3
4
initChallenges({
clientKey: "00000000-0000-0000-0000-000000000000",
withoutSessions: true
});
Click tags
A click tag ties a token to a real user click on a specific element, so a token for a sensitive action can only be produced after the visitor actually clicked it — not by a script calling runChallenge on its own.
Mark the element with data-bb-tag (only genuine clicks count):
1
<button data-bb-tag="login">Log in</button>
Pass the same name as clickTag when you generate the token. Do it right after the click — the tag is only remembered for a short time:
1
const botByeToken = await runChallenge({ clickTag: "login" });
BotBye! then embeds the tag in the token, so you can add an admin rule that declines requests missing it — for example, decline any login request whose token is not tagged `login`.