HomeDocs

Widget Configuration

The widget is a single script (widget.js) with zero runtime dependencies. It exposes the global NexloLabsVerification object.

Loading the script

<script src="https://verify.nexlolabs.net/widget.js"></script>

A minified version is available at https://verify.nexlolabs.net/widget.min.js.

Data attributes

Every <div class="nexlolabs-verification"> is configured through attributes:

AttributeDefaultValuesDescription
data-sitekeynlx_site_...Required. Public key of your site.
data-typecheckboxcheckbox, image_select, puzzle, math, code, shapes, vowels, invisibleChallenge type to render.
data-difficultynormaleasy, normal, hardChallenge strength (tile count, grid size, code length).
data-themeautoauto, light, darkColor scheme. auto follows prefers-color-scheme.
data-localeautoen, de, fr, esUI language. auto follows the browser language.
data-sizenormalnormal, compactWidget size.
data-styles{}JSON stringPer-widget styling overrides (see below).

Example:

<div
  class="nexlolabs-verification"
  data-sitekey="nlx_site_YOUR_SITE_KEY"
  data-type="puzzle"
  data-difficulty="hard"
  data-theme="dark"
  data-locale="de"
></div>

Styling

Apply a brand look via data-styles (JSON) with CSS custom-property overrides:

<div
  class="nexlolabs-verification"
  data-sitekey="nlx_site_YOUR_SITE_KEY"
  data-styles='{"primaryColor":"#7c3aed","radius":"10px","checkboxSize":"28px"}'
></div>
KeyTypeDefaultDescription
primaryColorstringbrand colorAccent color for buttons & active elements.
radiusstringinheritedBorder radius of the container (any CSS length).
checkboxSizestringplatform defaultSide length of the checkbox (any CSS length).

Global configuration

Set window.NexloLabsConfig before the widget script loads:

<script>
  window.NexloLabsConfig = {
    apiBaseUrl: "https://verify.nexlolabs.net/api", // override for self-hosting
    locale: "en",
    theme: "auto",
  };
</script>
<script src="https://verify.nexlolabs.net/widget.js"></script>
OptionTypeDefaultDescription
apiBaseUrlstringhttps://verify.nexlolabs.net/apiBase URL of the API.
locale"en" | "de" | "fr" | "es"enDefault locale for all widgets.
theme"auto" | "light" | "dark"autoDefault theme for all widgets.

JavaScript API

render(selector)NexloLabsVerification

Renders a widget into every matching element.

NexloLabsVerification.render(".nexlolabs-verification");

onSuccess(callback)

Called with the verification token once the challenge is solved.

NexloLabsVerification.onSuccess((token) => {
  console.log("Token:", token);
});

onError(callback)

Called when the widget fails (network error, invalid site key, expired challenge, ...).

NexloLabsVerification.onError((error) => {
  console.error(error.message);
});

onExpired(callback)

Called when a token expires before being redeemed.

NexloLabsVerification.onExpired(() => {
  console.log("Token expired - re-verifying");
});

reset()

Clears all widgets and resets their state. Useful on form errors.

NexloLabsVerification.reset();

execute()

Runs the challenge flow programmatically (e.g. for invisible verification).

NexloLabsVerification.execute();

getToken()string | null

Returns the current token (same value as delivered to onSuccess).

destroy()

Removes all widget UI and event listeners.

Token lifecycle

  1. Widget creates a challenge (POST /api/challenge/create).
  2. User solves it (POST /api/challenge/solve) → signed token returned.
  3. Token is valid for 120 seconds and can be redeemed once.
  4. onSuccess fires with the token. After verification server-side, it cannot be re-used.

The widget itself never verifies the token — verification always happens in your backend with your site secret. A token shown in the browser cannot be forged or reused because it is HMAC-signed.

Multiple widgets per page

Every nexlolabs-verification div becomes its own widget. Tokens are emitted per widget and each token can only be redeemed once — submit the token that belongs to the form being sent.

Self-hosting

Point apiBaseUrl at your own deployment:

window.NexloLabsConfig = { apiBaseUrl: "https://verify.your-domain.com/api" };