Free trial abuse: one trial per person, not per email
A new email costs nothing, so a free month can be taken again and again. At sign-up, ask SpoofLens how many of your accounts this browser has opened in the last 30 days, and make the second and third ones prove they are new.
The problem
The pattern is easy to spot by hand: trials that never convert, sign-ups from the same few browsers, emails that differ only by a number or a dot. Asking every new user for a card or a phone number stops it, but it also stops honest people who only want to try the product.
This recipe keeps the trial open for a first account and adds a step only for later accounts from the same device and for browsers that do not look normal.
What the API gives you
seen.accounts_on_device_30d | How many of your accounts used this device in the last 30 days, this sign-up included. 1 means a new person. It needs user_ref, and the count stays inside your SpoofLens account: no other site sees it. |
decision.action | What your rules say: allow, review or block. With the default rules, block means an automated browser or a score below 30, and review a score below 70. |
device.id | The browser profile, the same on your site visit after visit. Keep it with the account: support, the block list and the referral recipe use it. |
The code
It calls the helper (sl_check_visitor and sl_user_ref), which sends the browser data from the form, the IP address, the headers and a hash of the email.
PHP
<?php
// sign-up handler: decide what kind of trial the new account gets
$r = sl_check_visitor(sl_user_ref($_POST['email']));
$trial = 'start'; // no answer: start the trial as usual
$deviceId = '';
if ($r) {
$accounts = $r['seen']['accounts_on_device_30d'] ?? 1; // this sign-up included
$action = $r['decision']['action'] ?? 'allow'; // what your rules say
if ($action === 'block') {
$trial = 'none'; // automation or a block list: no trial, offer the paid plan
} elseif ($accounts >= 3) {
$trial = 'card'; // a third account from this device in 30 days: trial with a card on file
} elseif ($accounts === 2 || $action === 'review') {
$trial = 'verify'; // a second account or a doubtful browser: confirm the phone or the email first
}
$deviceId = $r['device']['id']; // save it with the account
} Node.js
// sign-up handler (Express): decide what kind of trial the new account gets
const r = await slCheckVisitor(req, slUserRef(req.body.email));
let trial = 'start'; // no answer: start the trial as usual
let deviceId = '';
if (r) {
const accounts = (r.seen && r.seen.accounts_on_device_30d) || 1; // this sign-up included
const action = (r.decision && r.decision.action) || 'allow'; // what your rules say
if (action === 'block') trial = 'none'; // automation or a block list: no trial, offer the paid plan
else if (accounts >= 3) trial = 'card'; // a third account from this device in 30 days: trial with a card on file
else if (accounts === 2 || action === 'review') trial = 'verify'; // confirm the phone or the email first
deviceId = r.device.id; // save it with the account
} Python
# sign-up handler (Flask): decide what kind of trial the new account gets
r = sl_check_visitor(request, sl_user_ref(request.form['email']))
trial = 'start' # no answer: start the trial as usual
device_id = ''
if r:
accounts = (r.get('seen') or {}).get('accounts_on_device_30d', 1) # this sign-up included
action = (r.get('decision') or {}).get('action', 'allow') # what your rules say
if action == 'block':
trial = 'none' # automation or a block list: no trial, offer the paid plan
elif accounts >= 3:
trial = 'card' # a third account from this device in 30 days: trial with a card on file
elif accounts == 2 or action == 'review':
trial = 'verify' # a second account or a doubtful browser: confirm the phone or the email first
device_id = r['device']['id'] # save it with the account The numbers are a starting point. After a week, look at your request log: if second accounts from one device are mostly couples or colleagues who really are different people, move the extra step to the third account.
Soft steps instead of a ban
- Confirm a phone number or the email address before the trial starts.
- Start the trial with a card on file, charged only when the trial ends.
- Give a shorter trial, or the free plan instead of the trial.
- For block: no trial, but a clear way to buy or to contact support. A real person stopped by mistake should always have a way forward.
Rules in your account
Set them in Rules and alerts: the result comes back as decision in every answer, so your code does not change when the rules do.
- Start with the default thresholds: review below 70, block below 30, automated browsers blocked.
- When you find someone farming trials, put their device ID on the block list: later sign-ups from that browser profile get block, whatever the email.
- Put your own team's devices on the allow list, so testing new sign-ups never trips the limits.
- Turn on the webhook for review if you want a message about doubtful sign-ups to look at by hand.
Where it can be wrong
- One computer, several people: a family, a shared office PC, a computer lab. That is why the second account gets a check, not a refusal.
- A VPN or a privacy browser on its own is not abuse. Brave, Firefox with resistFingerprinting and Tor Browser change some values on purpose; SpoofLens reports them as privacy protection, and they do not lower the score.
- iCloud Private Relay hides the address of many Apple users. SpoofLens recognises it and does not count it against them.
One line for your privacy policy
To prevent abuse of free trials, we check technical characteristics of your browser with SpoofLens (spooflens.com) when you sign up.
Limits
- The device ID belongs to one browser profile. The same person in another browser, or in a privacy browser that changes its fingerprint on every visit, looks like a new device. The recipe stops the common case, someone who signs up again and again from one browser, not a determined attacker.
- The count covers the last 30 days.
- SpoofLens does not see payments or card numbers. Matching cards is your payment provider's job; the two together are stronger than either one.
Other recipes
- Welcome coupons: a first-order discount for first orders only
- Referral programs: no bonus for inviting yourself
- The API documentation
Get a free key 1,000 checks a month free, no card.