HomeDocs

Integration Guide

Protect any form or action with NexloLabs Verification in three steps. Estimated time: 5 minutes.

1. Create a site

  1. Open the dashboard and log in (or register).
  2. Go to Sites → Create site, give it a name and add your domain (e.g. example.com).
  3. You receive a site key (nlx_site_...) and a site secret (nlx_secret_...). The secret is shown only once — store it in your backend environment variables.

The site secret must never be exposed in the browser. Only your backend may use it.

2. Add the widget to your page

Place this in your HTML — anywhere before the closing </body>:

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

<div
  class="nexlolabs-verification"
  data-sitekey="nlx_site_YOUR_SITE_KEY"
  data-type="checkbox"
  data-theme="auto"
></div>

<script>
  NexloLabsVerification.render(".nexlolabs-verification");

  NexloLabsVerification.onSuccess((token) => {
    // token is a one-time signed verification token.
    // Send it with your form submission to your backend.
    document.querySelector("form").dataset.verificationToken = token;
  });

  NexloLabsVerification.onError((error) => {
    console.error("Verification failed:", error.message);
  });
</script>

render() must run after the widget div is in the DOM. The widget also auto-initializes on DOMContentLoaded if the script is loaded before the container.

In your form handler (e.g. on submit), include the token:

<form id="my-form" method="POST" action="/submit">
  <input type="hidden" name="verificationToken" id="verification-token" />
  <!-- your fields -->
</form>

<script>
  NexloLabsVerification.onSuccess((token) => {
    document.getElementById("verification-token").value = token;
  });
</script>

3. Verify server-side

Never trust the token from the client. In your backend, call the verify endpoint with your site secret:

POST https://verify.nexlolabs.net/api/challenge/verify
Content-Type: application/json

{
  "token": "the-token-from-the-widget",
  "secret": "nlx_secret_YOUR_SITE_SECRET"
}

Response:

{
  "success": true,
  "score": 0.97,
  "challengeId": "clx9...",
  "hostname": "example.com",
  "expires": "2026-08-06T12:00:00.000Z"
}
FieldDescription
successtrue when the token is valid, unused and not expired
scoreRisk score between 0 (bot) and 1 (human)
challengeIdThe challenge that produced this token
hostnameThe origin the widget ran on (already validated)
expiresUTC timestamp when the token expires

Accept the submission when success is true and score is above your threshold. A sensible default is 0.5.

Full flow for a protected form

  1. User loads your page → widget requests a challenge from POST /api/challenge/create (using the site key).
  2. User solves the challenge (or passes invisibly) → widget sends the answer to POST /api/challenge/solve and receives a token.
  3. User submits your form → your frontend sends the token alongside the form data.
  4. Your backend calls POST /api/challenge/verify with the token and the site secret.
  5. If verification passes, process the form. Otherwise reject with an error.

Next