How to stop free-trial abuse in a SaaS or AI app
Short answer. Link each new signup to accounts already created from the same browser, device or mailbox, then give repeats a smaller trial instead of blocking them. Normalize email aliases, flag disposable domains, run in watch-only mode for two weeks, and fail open with a reduced grant when the check is unavailable. A CAPTCHA does not stop one human with many inboxes.
Last updated 2026-10-26 ยท Written by the Nolgard team
Why trials get abused
A free trial or a bag of free credits is worth real money when each account costs you model tokens, SMS or compute. The cheapest way to get more of it is a new email address. Most repeat signups are one real person in one real browser, so bot checks pass them every time.
Steps
- Normalize the email before you look it up. Gmail ignores dots and plus tags, so
jane.doe+2@gmail.comandjanedoe@gmail.comare one mailbox. Nolgard folds aliases for Gmail, Outlook, iCloud, Fastmail and Proton and reports them asrepeat.emailAliases. - Link accounts to the browser and device. Load
client.json the signup page and send the token with the form:<script src="https://nolgard.com/v1/client.js" data-site-key="SITE_KEY" defer></script> <script> // on submit await Nolgard.ready; const token = await Nolgard.execute({ action: 'signup' }); // send token with the form to your backend </script> - Verify on the server with the account. Pass your account id and email so the signup joins its cluster:
// Your signup handler, after the browser sent `token` const res = await fetch('https://nolgard.com/v1/verify', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ secret: process.env.NOLGARD_SECRET, token, remoteIp, action: 'signup', account: { id: newUserId, email } }), signal: AbortSignal.timeout(3000) }); const result = await res.json(); if (!result.success) return createAccount({ share: 0.2 }); // fail open, reduced grant (see /docs/#failures) if (result.decision === 'allow' || result.decision === 'limit') return createAccount({ credits: result.grant.credits ?? result.grant.share }); if (result.decision === 'challenge') return askForEmailConfirmation(); return reject(); - Grade the trial, do not block. A repeat gets
decision: "limit"and a smallergrant.share. Offices and families share devices, so a smaller grant costs a false positive far less than a rejection. See trial grants. - Start in Observe mode. Nothing is enforced and every event records
wouldDecide. Compare it with accounts you already know were abuse, then switch to enforcing. See Observe and tuning. - Label what you learn. Send chargebacks and confirmed abuse as Fraud, paying users as Legit, with
POST /v1/feedback. A Legit device label clears repeat limits for 30 days.
Approaches compared
| Approach | Stops the same person with a new email? | Friction for real users | Notes |
|---|---|---|---|
| Email verification | No. A new inbox verifies fine. | Low | Still worth keeping; it proves the inbox exists. |
| Block disposable domains | Partly. Gmail aliases pass. | None | Lists go stale; pair with alias folding. |
| CAPTCHA or Turnstile | No. A human solves it every time. | Low to medium | Good against scripts, not against repeat humans. |
| Card on file | Mostly, with card fingerprinting by your payment provider. | High; fewer trials start | Changes your funnel, not just your fraud rate. |
| Phone verification | Mostly, until virtual numbers. | High; SMS costs money | Can invite SMS pumping. See SMS pumping. |
| Device and alias linking (Nolgard) | Yes, within 30 days on the same browser or device, or the same mailbox. | None visible | A fresh device, browser and email can still evade it. |
Questions
Should I block repeat signups outright?
Usually no. A shared device is evidence, not proof: an office, a classroom or a family shares one. Give repeats a smaller trial with limit and keep block for clear automation.
How many accounts per device are normal?
Nolgard's default repeat threshold is three. The fourth distinct device-linked account within 30 days triggers repeat_device. You can tune it per site.
What if the check is down or I am over quota?
Fail open with a reduced grant, for example 20 percent of the trial. The Node SDK does this with failOpenShare, default 0.2. Fail closed only on config errors such as a wrong secret.
Do I need a credit card on signup to stop abuse?
No. A card cuts abuse and trial starts at the same time. Measure repeat signups first with the trial abuse calculator, then decide.
Does this work for mobile apps?
Not yet. Nolgard covers browsers only.