Skip to content
Troubleshooting

hCaptcha returns "token invalid" — the actual fix

Your form submission returns "invalid input response" or hCaptcha's siteverify endpoint comes back with error-codes including invalid-input-response or timeout-or-duplicate.

Cause

Three common culprits: (1) the token was bound to a different sitekey than what the form's server checks, (2) more than 120 seconds passed between solve and submit (tokens expire), (3) the token landed in g-recaptcha-response but the backend reads h-captcha-response — or vice versa.

Fix

Re-solve immediately before submitting (don't solve at page load and submit much later). Set both h-captcha-response and g-recaptcha-response inputs so the form post validates regardless of which one the backend reads. Use the exact websiteKey from the page's data-sitekey attribute.

Runnable example
import { CaptchaSonic } from 'captchasonic'

const sonic = new CaptchaSonic('YOUR_API_KEY')
const { token } = await sonic.solve({
  type: 'HCaptchaTaskProxyless',
  websiteURL: 'https://target.example.com/login',
  websiteKey: 'XXX-XXX-XXX', // copy from page's [data-sitekey]
})

// Set BOTH response fields — hCaptcha is a drop-in for reCAPTCHA so
// many backends read the legacy field.
document.querySelector('[name="h-captcha-response"]').value = token
document.querySelector('[name="g-recaptcha-response"]').value = token
document.querySelector('form').submit()

Frequently asked questions

Inspect the page for [data-sitekey] on the h-captcha div, or grep the page source for "sitekey". Use the live value — not a sample from docs.

hCaptcha is a drop-in replacement for reCAPTCHA. Backends that originally integrated reCAPTCHA may still read g-recaptcha-response. Setting both ensures the form post validates regardless of which field the backend reads.

About 120 seconds from issue. Solve right before submit, not at page load.

Related guides