Free trial abuse and fake account detection for SaaS
Trial abusers and fake-account farms reset the cheap parts of a signup: a new inbox, a new IP, sometimes a new browser profile. Maskbreak checks the signup from the visitor’s browser and gives your backend allow, review or block, with the reasons: a throwaway inbox, a device already behind several of your accounts, a fake browser, a proxy.
How free trial abuse works, layer by layer
Trial abuse needs no botnet: one person with a checklist is enough. Each item on the list defeats something a signup form might count, and each one costs almost nothing. Here is the list, and what each item looks like when Maskbreak sees it.
A new email for every trial
Throwaway inbox services, catch-all domains, plus-addresses. Send the address with the check and a known throwaway domain comes back as disposable_email, which turns an allow into a review. Catch-all domains and plus-addressing are not a Maskbreak signal; normalise those in your own code.
A new IP address for every trial
A VPN, a residential proxy or a phone hotspot. A VPN comes back as vpn_detected, a review, with the service named in network.service when known. A recognised proxy is proxy_detected, a block. A phone hotspot is an ordinary mobile carrier address, so the network check has nothing to flag, and toggling flight mode often hands out a new one. That is why per-IP signup limits leak, and why the device matters more than the address.
The same laptop behind all of them
A lazier abuser resets everything except the machine: same laptop, same browser. Send your own account id as accountId and the response carries device.linked_accounts; above one, multi_account_device joins the reasons. Links are one-way hashes and count only your accounts.
A new browser profile for every trial
A determined abuser runs a fake browser (an “antidetect browser” such as GoLogin, AdsPower or Dolphin) that presents a fresh fingerprint for every profile. When Maskbreak’s device check sees the spoofing, the reasons include antidetect_browser, device.tampering_score (0 to 1) comes with it, and the default decision is block.
Why trial abuse is detectable: the trade-off every abuser makes
Keep the device, and the accounts link. Emails and IP addresses cost nothing to replace; a laptop does not. A resetter who stays on the same machine and browser usually arrives as the same visitor ID trial after trial, and linked_accounts climbs with each one (when the device check completes and you send accountId). The multi-accounting playbook uses the same signal against ban evasion and referral farming.
Change the browser and the count restarts; spoof it and the spoofing shows. A new visitor ID takes another browser on the machine, a fake browser that spoofs canvas, WebGL, fonts and the rest of the fingerprint, or another device or virtual machine. A second browser leaves nothing to find: it simply starts a new count. The spoofing is what Maskbreak’s device check looks for, and a virtual machine shows as virtual_machine, which asks for review on its own, never a block. Maskbreak publishes no catch rate; the check raises the cost of each trial beyond a new email.
Automate it, and the automation shows. Farming trials at volume means scripts: headless browsers, automation frameworks, emulators. When the device check sees them, they return automation_detected or emulator_detected, both blocked by default, before the account receives an API key, credits or any quota. Bot detection and stopping fake signups go further into scripted registrations.
Hide the network, and the hiding shows. A VPN or proxy that Maskbreak’s network intelligence recognises, residential proxy exits included, comes back as vpn_detected or proxy_detected. Neither proves abuse by itself, and a VPN alone is only flagged for review. But a VPN plus a fake browser plus a fourth linked account is a very different visitor from a VPN alone, and the reasons array lets your code tell them apart.
How to detect fake accounts in a SaaS platform
Not every fake account wants the trial. Some exist to send spam through your product, host a phishing page on your domain or collect referral credit. They register the same way, often scripted and often through a proxy, so the same signup check sees them; what changes is what you protect afterwards.
Judge the account while its browser is on the page. Once signup is over, a fake account is a row like any other, and nothing in it records the script, the spoofed fingerprint or the proxy behind it. Accounts that already exist come into view at their next login: run the same check there with the account id and they join the device count. To choose a tool, read fake account prevention software compared: eight tools, what each checks at signup and what it costs.
What trial abuse looks like in a Maskbreak response
First, the lazier abuser: the fourth signup from one laptop, on home broadband, with a throwaway inbox. The connection and the browser are clean, so there is little to score. linked_accounts: 4 is the finding, and no check on the account row could have found it: every row is genuinely new. The throwaway inbox is what moves this one to review: multi_account_device alone does not change the default decision, since families, agencies and freelancers share machines.
// Example response, selected fields: the 4th trial from one laptop
{
"decision": "review",
"risk_score": 15,
"reasons": ["disposable_email", "multi_account_device"],
"network": { "vpn": false, "proxy": false, "datacenter": false, "tor": false },
"device": {
"antidetect": false,
"automation": false,
"linked_accounts": 4,
"multi_account": true
},
"email": { "disposable": true }
}Second, the determined abuser: a brand-new fake-browser profile behind a residential proxy. The profile did its job, because the device is new and has exactly one linked account, so there is nothing to link. The spoofing and the proxy give it away instead, and either one blocks under the default policy.
// Example response, selected fields: a new fake-browser profile behind a residential proxy
{
"decision": "block",
"risk_score": 92,
"reasons": ["proxy_detected", "antidetect_browser"],
"network": { "vpn": false, "proxy": true, "datacenter": false, "service": "<proxy service, when known>" },
"device": {
"antidetect": true,
"automation": false,
"tampering_score": 0.7,
"linked_accounts": 1,
"multi_account": false
}
}The everyday case sits between the two: a VPN and nothing else. That is vpn_detected and a review, with the VPN service named when known. Plenty of real evaluators work behind a company VPN, so treat it as a reason to ask for one more step, not as a verdict. The field reference is in the API docs.
What to do with each signal at trial signup
For a SaaS trial, review is where most of the value sits. A block refuses a visitor; a review lets you ask each visitor for a different amount of proof. The clean signup gets instant access, the VPN user confirms a work email, and the fourth account from one laptop is offered a trial with a card on file. Most of these defaults can be changed per signal on the console’s Rules tab. A rule changes the decision only for the signal it names, so relaxing one signal never lets another through.
- Block:
automation_detected,emulator_detected,antidetect_browser,proxy_detected,tor_exit_node. These block by default. No workspace, no API key, no quota. - Review, then ask for one more step:
vpn_detected,virtual_machineorprivacy_relay(Apple’s iCloud Private Relay) on its own,disposable_email, andtimezone_mismatch(the browser’s time zone disagrees with the country of an ordinary-looking IP; travellers land here too). Hold the trial until the email is verified, ask for a work address, or ask for a card on file before the features that cost you money. - Your call:
multi_account_deviceis allow by default. When a repeat trial has a real cost, such as model inference, compute or paid seats, escalate it: treat anallowwhosereasonsincludemulti_account_deviceas a review in your signup handler, or set Multi-accounting to Review on the Rules tab. The rule applies to every check on your account, logins included, and never softens another signal: a linked device that also shows a proxy or a fake browser still blocks. - Let through:
datacenter_asnalone (engineers evaluate from cloud dev boxes) andprivate_browsingalone (careful people try new products in a private window). Both stay allow. - Missing evidence is not a pass: a response without a
deviceblock means the fake-browser check and the account link did not run; adeviceblock withcomplete: falsemeans the fake-browser or automation check did not run;degraded: truemeans the network check (VPN, proxy) did not run. Once you enforce, hold all three like a review instead of starting the trial.
Where to check free trial signups, and why watch mode comes first
Add the browser snippet from the quickstart to the signup form first; it adds the two tokens your server forwards. Then put the check in your signup handler after you create the account row and before the trial starts: before the workspace, the API key or the first unit of quota exists. Passing that row’s id as accountId is what lets Maskbreak count accounts per device; set it on your server, never from a browser field.
If you offer “Sign up with Google”, the same check belongs in the OAuth callback, or the Google button becomes the way around your form. If your product grants quota again later, check there too; the trial abuse playbook covers quota farming on AI products.
The snippet below watches before it acts. It logs every decision, never stops a signup, and carries on if Maskbreak is unreachable. Give it a week, read the log next to the Events tab in your console, set the Rules you want, and only then turn on the enforce line. The integration guide has the complete enforce handler, and the staged rollout guide covers what to look for first.
// Trial signup: `user` is the account row you just created; no trial yet // Watch mode first: log the verdict, always continue, fail open const body = req.body || {}; // sentinel.js adds monocle + sentinel_fp to your form let risk = null; try { const verdictRes = await fetch('https://maskbreak.com/v1/evaluate', { method: 'POST', signal: AbortSignal.timeout(5000), headers: { 'Authorization': 'Bearer ' + process.env.MASKBREAK_API_KEY, 'Content-Type': 'application/json' }, body: JSON.stringify({ token: body.token || body.monocle, // network evidence fingerprintEventId: body.fingerprintEventId || body.sentinel_fp, // device evidence tz: body.tz || body.sentinel_tz, email: body.email, // disposable-domain check, not stored accountId: String(user.id) // your own id, set server-side: counts accounts per device }) }); if (verdictRes.ok) risk = await verdictRes.json(); } catch {} // unreachable or timed out: your handler still runs console.log('[maskbreak]', JSON.stringify({ decision: risk?.decision ?? null, reasons: risk?.reasons ?? null, risk_score: risk?.risk_score ?? null, linked_accounts: risk?.device?.linked_accounts ?? null, degraded: risk ? !!risk.degraded : null })); // Enforce later: if (risk?.decision === 'block') return res.status(403).json({ error: 'Signup rejected' }); // (disable the account row you just created before returning the 403) // and on 'review', degraded, no device block, device.complete false, no answer, or a // test, sample or sandbox response, start the trial only after email verification // or a card on file (full handler: /integrate.md). Repeat trials cost you money? // Treat an allow with multi_account_device in reasons as a review, in code.
What Maskbreak does not do for SaaS trials
No identity verification. There is no KYC, no document or selfie check, and nothing that tells you who a person is. A visitor ID is a risk signal, not proof of identity, and two colleagues on one shared laptop look like one device.
No payment verification. Maskbreak does not check cards, score transactions or offer a chargeback guarantee. If a card on file is your review step, your payment provider does that part.
No email or phone reputation. The email check answers one question: is this domain a known throwaway inbox service. It does not confirm the mailbox exists, and catch-all domains and plus-addresses pass it. The disposable email playbook covers what the signal can and cannot tell you.
No shared identity network. Account links are counted against your accounts only and stored as one-way hashes. A device that farmed trials at another company starts at one linked account with you.
No scoring of old signups from your logs. The VPN, proxy and device verdicts come from a live visit. A bare-IP lookup covers Tor exits and published cloud ranges only, so start at the form, and run the same check at login with the account id to bring existing accounts into the device count.
No replacement for your own controls. Keep email verification, authentication, rate limits and usage caps. A trial account that scrapes your app a week after signup is a usage-cap problem, or a reason to check again at the moment quota is granted.
behind nine trials and nine email addresses. The SaaS trial abuse playbook is a worked model, not a customer result: how the reset loop runs, why card walls cost conversion and per-IP limits miss it, and an honest way to estimate what enforcement recovers.
Read the attack playbook Trial abuse at scaleTrial abuse and fake account detection: common questions
Watch a week of your own trial signups
Free plan: 10,000 visitor checks a month, every signal included, no card. Paid plans from €29 a month.