Practical guide

How to add invisible reCAPTCHA to a form

The invisible reCAPTCHA code in most guides calls form.submit(), which skips the browser's own checks. In our test it sent an empty form straight through.

The short answer. Invisible reCAPTCHA is reCAPTCHA v2 without the checkbox: add a div with data-size="invisible", call grecaptcha.execute() when the form is sent, post the token from the callback, and reset the widget after each try. Skip the bound-button sample most guides copy: in our test its form.submit() sent an empty form in 1 of 1 tries.

Formgong

How to add invisible reCAPTCHA to a form
How to add invisible reCAPTCHA to a form

What is invisible reCAPTCHA, and how is it different from v3?

Invisible reCAPTCHA is version 2 of Google's check with the "I'm not a robot" box taken away. The visitor clicks your own Send button, Google decides in the background, and only traffic it finds suspicious gets an image puzzle. Google's overview of reCAPTCHA versions puts it this way: "By default only the most suspicious traffic will be prompted to solve a captcha."

That is the difference from v3. Version 3 never shows a puzzle and gives your server a score from 0.0 to 1.0 to act on, which our reCAPTCHA v3 setup guide covers along with Google's test keys. Invisible v2 gives a plain yes or no and can still challenge a person. It also has one practical advantage: Google's published test keys are v2 keys, so you can run the whole flow end to end before you have a real key, which is what we did on 3 November 2026.

Why does the usual invisible reCAPTCHA code send empty forms?

Google's invisible reCAPTCHA page shows the simplest setup first: put the site key on the button and, in the callback, call form.submit(). Formspree's guide and the Splitforms guide (reviewed 29 October 2026) use the same callback. It works, and it has a flaw none of the three pages mentions: form.submit() sends the form without running the browser's validation. required, type="email" and minlength are all skipped.

The bound-button sample
<!-- The pattern most guides copy. Do not use it as is: see below. -->
<button class="g-recaptcha" data-sitekey="YOUR_SITE_KEY" data-callback="onSubmit">Submit</button>
<script>
  function onSubmit(token) {
    document.getElementById("demo-form").submit(); // skips required, type=email and every other check
  }
</script>

What did our test show?

Eight runs with Google's published test key in Chromium, 3 November 2026. No run showed an image challenge.
SetupWhat happened
Bound button, empty formCallback ran once, form.submit() sent three empty fields, siteverify said success, the backend stored an empty message
Bound button, filled formSent and stored
Submit listener, empty formThe browser stopped it at the first required field. No token, no request
Submit listener, filled formToken of 1,678 characters, sent and stored in 3.4 s
Two sends, grecaptcha.reset() after each2 of 2 sent
Two sends, no resetFirst sent. The second stayed on "Checking…" for 13 s: no callback
Badge hidden with display: noneToken returned, sent
Badge hidden with visibility: hiddenToken returned, sent

The first row is the problem. Our form had three required fields, all empty. Clicking the bound button ran the check, the callback called form.submit(), siteverify said success, and an empty message landed in the inbox. A real visitor who taps Send too early gets no hint that anything is missing, and you get blank submissions to read.

How do you add invisible reCAPTCHA without skipping validation?

Bind the widget to a div instead of the button, and start the check from the form's submit event. The browser runs its own field checks before that event fires, so an invalid form never reaches reCAPTCHA. In our run the empty form stopped at the first required field and no token was requested.

Then send the form from the callback with fetch, which lets you show the server's answer on the page, and call grecaptcha.reset() when the request ends. Google's page lists reset without saying when you need it. Our runs answer that: without it, a visitor who sends a second message gets no answer at all. The second execute() never called back, and the page sat on "Checking…" for the 13 seconds we waited. Keep the line under the button that says the site is protected by reCAPTCHA; Google requires it if you hide the badge.

HTML + JavaScript
<form id="contact">
  <label for="name">Name</label> <input id="name" name="name" required>
  <label for="email">Email</label> <input id="email" name="email" type="email" required>
  <label for="message">Message</label> <textarea id="message" name="message" required></textarea>
  <div class="g-recaptcha" data-sitekey="YOUR_SITE_KEY" data-size="invisible"
       data-callback="onToken" data-error-callback="onCaptchaError"></div>
  <button type="submit">Send</button>
  <p id="form-status" role="status"></p>
  <p class="hint">This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.</p>
</form>
<script>
  var BACKEND = "/contact"; // your own server route, which verifies the token
  var form = document.getElementById("contact");
  var statusLine = document.getElementById("form-status");
  // The browser checks the fields before this runs; an invalid form never fires "submit".
  form.addEventListener("submit", function (event) {
    event.preventDefault();
    if (!form.reportValidity()) return; // still needed if the form has novalidate
    statusLine.textContent = "Checking…";
    grecaptcha.execute();
  });
  function onToken(token) {
    statusLine.textContent = "Sending…";
    fetch(BACKEND, { method: "POST", body: new URLSearchParams(new FormData(form)) })
      .then(function (response) { return response.json(); })
      .then(function (data) { statusLine.textContent = data.success ? "Thanks, your message was sent." : (data.message || "Not sent."); })
      .catch(function () { statusLine.textContent = "Not sent. Please try again."; })
      .finally(function () { grecaptcha.reset(); }); // without this, the next execute() never calls back
  }
  function onCaptchaError() { statusLine.textContent = "The check could not load. Please try again."; }
</script>
<script src="https://www.google.com/recaptcha/api.js" async defer></script>

Can you hide the invisible reCAPTCHA badge?

Yes, if the reCAPTCHA notice is visible in the form, as in the template above. Google's reCAPTCHA FAQ allows hiding the badge on that condition and gives the CSS as visibility: hidden. By default the badge sits in the bottom-right corner, folded so only the logo shows; data-badge="bottomleft" or "inline" moves it.

Formspree's guide warns that display: none has "been reported to turn the spam checking off". With the test key, both ways of hiding still returned a token and the message went through. The test key passes everything, though, so this shows only that the widget keeps working, not that its judgement is the same. Use visibility: hidden, as Google asks.

What should the server check for invisible reCAPTCHA?

Post the token and your secret to Google's siteverify endpoint and accept the form only if success is true and hostname is your own site. There is no score and no action in a v2 answer, so those two fields are the whole check. The hostname matters: without it, someone can solve the check on their own page with your public site key and post the token to your server.

With the test secret every answer is a success with the hostname testkey.google.com, so a strict hostname check refuses test tokens; switch it off only in your test environment. The full table of what the test secret answers, including made-up and empty tokens, is in our reCAPTCHA v3 guide.

JavaScript (server)
// On your server: one call, then decide.
const body = new URLSearchParams({ secret: process.env.RECAPTCHA_SECRET, response: token });
const result = await (await fetch("https://www.google.com/recaptcha/api/siteverify", { method: "POST", body })).json();
const ok = result.success === true && ["your-site.example", "www.your-site.example"].includes(result.hostname);

Does Formgong verify invisible reCAPTCHA?

No. A reCAPTCHA token posted straight to https://formgong.com/submit is stored as an ordinary field, so use a small backend in front, like the one in our v3 guide, which checks the token and forwards the rest. Here Splitforms does more: its invisible reCAPTCHA guide, read on 3 November 2026, says it verifies the token on every plan once you save your secret key.

What Formgong verifies on every plan, Free included, is Cloudflare Turnstile with your own keys, including the hostname check from the section above. Turnstile has an invisible mode too, and our captcha comparison sets the three side by side. If your form gets only a little spam, a honeypot field may be all you need, and our guide to stopping spam without a CAPTCHA lists what to add next.

Did invisible reCAPTCHA behave differently for you?

If a real key showed a challenge where we saw none, or display: none changed what your visitors got, write to support@formgong.com. We will add it here, with your permission.

Frequently asked questions

What is the difference between invisible reCAPTCHA and reCAPTCHA v3?

Invisible reCAPTCHA is v2: a yes or no answer, and a puzzle for suspicious visitors. v3 never shows a puzzle and gives your server a score from 0.0 to 1.0.

Why does invisible reCAPTCHA submit my form without validation?

The common callback calls form.submit(), which skips the browser's checks. Start the check from the form's submit event and send from the callback instead.

Why does grecaptcha.execute() not work the second time?

The widget does not run again until you call grecaptcha.reset(). In our test the second execute() without a reset never called back.

Can I hide the invisible reCAPTCHA badge?

Yes, if the form shows that the site is protected by reCAPTCHA, with Google's privacy policy and terms. Google gives visibility: hidden as the CSS.

Does Formgong verify reCAPTCHA tokens?

No. Formgong verifies Cloudflare Turnstile and uses honeypot fields. A reCAPTCHA token sent to it is stored as an ordinary field.

Sources and documentation

Official references for this guide: Formgong: reCAPTCHA v3 setup with the server score check, Formgong: Turnstile vs reCAPTCHA vs hCaptcha. HTML forms, where data is stored.

Rate this guide

Your rating

We read every rating. A comment appears here only after we approve it.

← Back to the blog