# hCaptcha vs Nolgard | Nolgard

> hCaptcha checks that a signup is human, with passive modes on paid plans. Nolgard checks whether it is the same human again and tells your backend how many credits to give. Use both.

Source: https://nolgard.com/compare/hcaptcha/
Last updated: 2026-10-25

Compare

# hCaptcha vs Nolgard

hCaptcha checks that a signup is human. Nolgard checks for linked repeat accounts and tells your backend how many credits to give. Use both when a repeat trial costs you money.

## What hCaptcha does better

- A dedicated challenge with server-side verification through `siteverify`. It can show a visual challenge when it is unsure; Nolgard never shows one. [hCaptcha developer guide](https://docs.hcaptcha.com/)

- Passive and invisible modes. Pro sitekeys default to a "99.9% Passive" mode; Enterprise adds further passive levels. [Pro features](https://docs.hcaptcha.com/pro) · [Invisible mode](https://docs.hcaptcha.com/invisible)

- Enterprise risk scores: `score` and `score_reason` in the `siteverify` response. [siteverify docs](https://docs.hcaptcha.com/)

- A free Basic plan up to 10,000 requests a month. [hCaptcha plans](https://www.hcaptcha.com/plans)

- Mobile app SDKs, listed in its docs. Nolgard covers browsers only; mobile apps are not covered. [hCaptcha mobile SDKs](https://docs.hcaptcha.com/mobile_app_sdks)

Plan and feature details are hCaptcha's own documentation, read 2026-10-25. Check their docs for current limits.

## What hCaptcha does not decide

The documented `siteverify` response carries `success`, `challenge_ts`, `hostname` and error codes, plus a score on Enterprise. None of it is about the account behind the browser.

- **Same person again.** One person with a fresh inbox passes on every trial.

- **How many credits to give.** Pass or fail, or a score. Your backend still has to pick a number.

- **What happens after signup.** It sits on the form and sees nothing the account does later.

- **Referral self-dealing.** Both sides are real humans in real browsers. Both pass.

## Row by row

| Question | hCaptcha | Nolgard |
| --- | --- | --- |
| Is this session automated? | Yes. This is its job. Score on Enterprise. | Yes. Returns a `score`, reason ids and a `decision`. |
| Can it show a challenge? | Yes, including passive modes on paid plans. | No visual challenge. Step-up is email confirmation or proof of work. |
| Is this the same person again? | Not in the documented response. | Yes. Per-site links across browser visitor id, device and normalized email. No per-response visitor id yet. |
| How many credits should this account get? | No. | Yes. `grant.share` and `grant.credits`. |
| Is the email disposable, new or an alias? | No. | Yes. MX, domain age, alias folding. |
| Mobile apps | Yes, through its SDKs. | Not covered. Browsers only. |
| Price | Basic free up to 10,000 requests a month; Pro and Enterprise paid. Check their docs for current limits. | Free: 1,000 new accounts a month. Pro $99 for 15,000. Business $299 for 75,000. [Pricing](https://nolgard.com/pricing/) |

hCaptcha column from its [developer docs](https://docs.hcaptcha.com/) and [plans page](https://www.hcaptcha.com/plans), read 2026-10-25. Nolgard column matches the shipped [API docs](https://nolgard.com/docs/). How we test, and what we miss: [methodology](https://nolgard.com/methodology/).

## Run both for two weeks

- Keep hCaptcha where it is. Add Nolgard's `client.js` and verify each signup that passed hCaptcha, with your `account.id`.

- Set the site to Observe mode: we enforce nothing and record `wouldDecide`.

- Label the accounts you know as `fraud` or `legit` with `POST /v1/feedback`.

- Compare `wouldDecide` with the labels. If the `limit` calls do not line up, you lose nothing.

## Use both

Run hCaptcha first and drop the scripts. Then ask Nolgard what the survivor is worth.

```
const hc = await fetch('https://api.hcaptcha.com/siteverify', { method: 'POST',
  body: new URLSearchParams({ secret: HCAPTCHA_SECRET, response: hcToken, remoteip }) }).then(r => r.json());
if (!hc.success) return reject();                       // challenge failed: stop here
const nf = await fetch('https://nolgard.com/v1/verify', { method: 'POST', headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ secret: NOLGARD_SECRET, token: nfToken, remoteIp: remoteip, action: 'signup', account: { id, email } }) }).then(r => r.json());
if (nf.success) grantCredits(nf.grant.credits ?? Math.floor(nf.grant.share * FULL_TRIAL));
```

Example server-side flow. Handle network failures and verify errors before granting anything: [when verify fails](https://nolgard.com/docs/#failures).

[Estimate the saving](https://nolgard.com/tools/trial-abuse-calculator/)[Ask for a pilot](https://nolgard.com/contact/?topic=pilot)[Start free](https://nolgard.com/app/#/signup)

## Related

- [Methodology](https://nolgard.com/methodology/)
- [Turnstile vs Nolgard](https://nolgard.com/compare/turnstile/)
- [Fingerprint vs Nolgard](https://nolgard.com/compare/fingerprint/)
- [reCAPTCHA migration](https://nolgard.com/docs/recaptcha-migration/)
- [Repeat accounts](https://nolgard.com/features/repeat-accounts/)
- [Trial grants](https://nolgard.com/features/trial-grants/)

[Read the docs](https://nolgard.com/docs/)[Start free](https://nolgard.com/app/#/signup)
