Szymdows CAPTCHA

Add a CAPTCHA to any website with simple integration, clear documentation, and practical server-side verification.

1. Install the script

Paste one line into the <head> of your HTML page. That's the whole installation: no npm, no build tools, no configuration.

Find your <head>

It's the part of your HTML file between <head> and </head>.

<html>
<head>
  <!-- paste the script tag here -->

</head>
<body>
  ...
</body>
</html>

Paste the script tag

Copy this line into your <head> exactly as it is. Don't add defer or async.

<script src="https://cdn.szymdows.com/szymdows-captcha.js"></script>
The script loads on its own and makes SzymdowsCaptcha available on your page.

2. Place the widget

Add an empty <div> where you want the CAPTCHA to appear, usually just above your submit button. The id can be anything, as long as you use the same one in the next step.

<form>
  <input type="text" placeholder="Your name" />
  <input type="email" placeholder="Your email" />

  <!-- CAPTCHA goes here -->
  <div id="my-captcha"></div>

  <button type="button" id="submit-btn">Submit</button>
</form>
The widget fills the div by itself and fits into normal layouts.

3. Show the CAPTCHA

Add a small script block just before your closing </body> tag and call SzymdowsCaptcha.render().

<script>
  SzymdowsCaptcha.render('my-captcha', {

    onSuccess: function(token) {
      document.getElementById('submit-btn').disabled = false;
    },

    onFail: function() {
      document.getElementById('submit-btn').disabled = true;
    },

  });
</script>
That's the basic setup. The CAPTCHA appears, and your onSuccess function runs when the user passes.

4. Handle the result

When the user passes, you get a token. Send it to your server along with the rest of the form data.

document.getElementById('submit-btn')
  .addEventListener('click', function() {

    var token = SzymdowsCaptcha.getToken('my-captcha');

    fetch('/submit', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        name: document.getElementById('name').value,
        email: document.getElementById('email').value,
        captchaToken: token,
      }),
    });

  });
Tokens expire after 60 seconds and can only be used once.

Recipe: a complete contact form

A full working page you can copy and use as a starting point.

<!DOCTYPE html>
<html>
<head>
  <script src="https://cdn.szymdows.com/szymdows-captcha.js"></script>
</head>
<body>

  <input type="text"  id="name"  placeholder="Your name"  />
  <input type="email" id="email" placeholder="Your email" />

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

  <button id="submit-btn" disabled>Send message</button>

  <script>
    SzymdowsCaptcha.render('my-captcha', {
      onSuccess: function(token) {
        document.getElementById('submit-btn').disabled = false;
      },
      onFail: function() {
        document.getElementById('submit-btn').disabled = true;
      },
    });

    document.getElementById('submit-btn')
      .addEventListener('click', function() {
        fetch('/submit', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            name: document.getElementById('name').value,
            email: document.getElementById('email').value,
            captchaToken: SzymdowsCaptcha.getToken('my-captcha'),
          }),
        });
      });
  </script>

</body>
</html>

Recipe: show it when the user clicks submit

Keep the CAPTCHA hidden until the user clicks the button.

<div id="my-captcha" style="display:none"></div>
<button id="submit-btn">Submit</button>

<script>
  document.getElementById('submit-btn')
    .addEventListener('click', function() {

      if (SzymdowsCaptcha.isVerified('my-captcha')) {
        submitMyForm(SzymdowsCaptcha.getToken('my-captcha'));
        return;
      }

      document.getElementById('my-captcha').style.display = 'block';

      SzymdowsCaptcha.show('my-captcha', {
        onSuccess: function(token) {
          submitMyForm(token);
        },
      });
    });

  function submitMyForm(token) {
    fetch('/submit', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ captchaToken: token }),
    });
  }
</script>

Recipe: verify the token on your server

Check every token on the server before you trust it.

Always verify server-side. A token arriving in a request doesn't prove it's real.
app.post('/submit', async function(req, res) {

  var token = req.body.captchaToken;

  var check = await fetch(
    'https://captcha.szymdows.com/__szc/verify-token', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ token: token }),
    }
  );

  var result = await check.json();

  if (!result.valid) {
    return res.status(403).json({ error: 'CAPTCHA failed' });
  }

  saveToDatabase(req.body);
  res.json({ success: true });

});

Options

Everything you can pass to render() or show().

OptionDefaultWhat it does
onSuccessnullCalled when the user passes. Receives the token string.
onFailnullCalled when the check fails. The widget retries automatically.
onExpirenullCalled when the CAPTCHA resets itself after 5 minutes.
autoResettrueIf true, the CAPTCHA resets itself after 5 minutes.
theme'auto'Use 'light', 'dark' or 'auto'.

Methods

What you can do with SzymdowsCaptcha.

SzymdowsCaptcha.render('element-id', options)
Shows the CAPTCHA widget inside the given element.
SzymdowsCaptcha.show('element-id', options)
Does the same as render(). Use it when you want to show the widget on demand.
SzymdowsCaptcha.getToken('element-id')
Returns the token if the user has passed, or null if they haven't.
SzymdowsCaptcha.isVerified('element-id')
Returns true if the user has already passed.
SzymdowsCaptcha.reset('element-id')
Clears the current result and loads a fresh challenge.

FAQ

The CAPTCHA isn't showing up at all

Check that the script tag doesn't have defer or async, and that the div's id matches the one you passed to render().

It says "Verification failed" every time

Try dragging more slowly and naturally. The challenge resets automatically if it needs to.

Can I use it on more than one form on the same page?

Yes. Give each form its own div and call render() for each one.

<div id="captcha-form-1"></div>
<div id="captcha-form-2"></div>

<script>
  SzymdowsCaptcha.render('captcha-form-1', { onSuccess: function() {} });
  SzymdowsCaptcha.render('captcha-form-2', { onSuccess: function() {} });
</script>
How do I match my site's colours?

Set the theme option to 'light', 'dark' or 'auto'.

SzymdowsCaptcha.render('my-captcha', {
  theme: 'dark',
  onSuccess: function(token) { ... },
});
Does it work on mobile?

Yes. It supports touch screens and adjusts to smaller screens.

Does it track my users?

No. Szymdows CAPTCHA sets no cookies, does no fingerprinting, and makes no calls to third-party tracking platforms.