Emulating real customer behavior: scripts that don't get caught

Good Carder

Professional
Messages
1,014
Reaction score
692
Points
113
From a carder to carders. You set up OpenBullet 2, upload your cards, launch it — and within 5 minutes, all your proxies are gone, and BIN is blacklisted. Why? Because your script is too perfect. It fills out the form in 2 seconds, clicks exactly in the center of the button, and makes no mistakes. For anti-fraud software, this is a screaming signal: "I'm a bot." In this article, I'll show you how to make your script look human. Humans make mistakes, hesitate, and move crookedly. Your script should do the same.

Part 1: Why OpenBullet's Default Scripts Burn in 5 Minutes​

OpenBullet and SilverBullet are powerful tools, but their default settings are designed for speed, not stealth. They send requests at perfect intervals, without delays, with identical headers. Antifraud detects this in seconds.

1.1 Ideal intervals are death​

The default OpenBullet configuration sends requests with a fixed delay (e.g., 500 ms). Humans don't work that way. They might pause for two seconds, then quickly fill in the field, then pause again. Their rhythm is chaotic.

Solution: add random delays. OpenBullet 2 has a Random Delay parameter. Set it between 200 and 1500 ms. But even that's not enough — you need to vary the delays based on the action.

1.2. Perfect mouse movements are a red flag​

OpenBullet doesn't emulate a mouse. It simply sends POST requests. But if you're using browser-based solutions (Playwright, Puppeteer), moving your mouse in a straight line is an instant ban. Human movements curve, with accelerations and decelerations.

Solution: use the ghost-cursor or @@extra /humanize libraries to emulate natural movements.

1.3. The absence of errors is a sign of a bot​

People never enter data perfectly the first time. They might make a mistake in a number, erase it, and reenter it. If your script fills the form without a single error, that's suspicious.

Solution: add 1-2 errors to the form. Intentionally enter an incorrect character, then delete it and enter the correct one.

1.4 Same User-Agent and Headers​

If all requests come from the same User-Agent and the same set of headers, this is easily detected.

Solution: Rotate the User-Agent and replace headers for each request.

Part 2. Setting Delays: Human Pauses​

2.1. Basic Delays​

ActionHuman delayBot delay (is detected)
Between symbols50–150 ms0–10 ms
Between the fields200–600 ms0–50 ms
Before clicking200–500 ms0–50 ms
After the page loads1000–3000 ms0–500 ms

2.2. Python Implementation (Playwright)​

Python:
import random
import time
from playwright.sync_api import sync_playwright

def human_delay(min_ms=100, max_ms=500):
time.sleep(random.randint(min_ms, max_ms) / 1000)

def human_type(page, selector, text):
page.click(selector)
human_delay(200, 600)
for char in text:
page.keyboard.type(char, delay=random.randint(50, 150))
# Sometimes pause mid-word (simulating human thought)
if random.random() < 0.05:
human_delay(200, 800)

2.3. Speed variation​

Not all fields are filled out at the same speed. People enter their first and last names quickly, their addresses more slowly, and their card numbers with pauses between entries.
Python:
def type_card_number(page, card_number):
groups = card_number.split(' ')
for i, group in enumerate(groups):
for char in group:
page.keyboard.type(char, delay=random.randint(30, 80))
if i < len(groups) - 1:
human_delay(200, 600) # pause between groups

Part 3. Mouse Movement Emulation​

3.1 Why do straight lines burn?​

Anti-fraud systems analyze mouse trajectory. If the cursor moves in a straight line from point A to point B, it's a sign of a bot. A human moves along a Bézier curve, accelerating at the beginning and decelerating at the end.

3.2 Using a ghost cursor (Puppeteer/Playwright)​

JavaScript:
const puppeteer = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
const ghostCursor = require('ghost-cursor');

puppeteer.use(StealthPlugin());

(async () => {
const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
await page.goto('https://example.com/checkout');
const cursor = ghostCursor.createCursor(page);

// Moving to the input field
const input = await page.$('#card-number');
const box = await input.boundingBox();
await cursor.moveTo({
x: box.x + box.width / 2 + (Math.random() - 0.5) * 20,
y: box.y + box.height / 2 + (Math.random() - 0.5) * 20
});

// Clicking with a hover pause
await page.waitForTimeout(random.randint(200, 500));
await cursor.click();

await browser.close();
})();

3.3. Implementing a Bezier Curve in Python (without External Libraries)​

Python:
import math
import random
import pyautogui

def bezier_curve(p0, p1, p2, p3, t):
"""Calculate a point on a cubic Bézier curve"""
x = (1-t)**3 * p0[0] + 3*(1-t)**2*t * p1[0] + 3*(1-t)*t**2 * p2[0] + t**3 * p3[0]
y = (1-t)**3 * p0[1] + 3*(1-t)**2*t * p1[1] + 3*(1-t)*t**2 * p2[1] + t**3 * p3[1]
return (x, y)

def human_move(start, end, steps=50):
# Generate control points for the curve
cp1_x = start[0] + (end[0] - start[0]) * 0.25 + random.randint(-30, 30)
cp1_y = start[1] + (end[1] - start[1]) * 0.25 + random.randint(-30, 30)
cp2_x = start[0] + (end[0] - start[0]) * 0.75 + random.randint(-30, 30)
cp2_y = start[1] + (end[1] - start[1]) * 0.75 + random.randint(-30, 30)
p0 = start
p1 = (cp1_x, cp1_y)
p2 = (cp2_x, cp2_y)
p3 = end

for i in range(steps + 1):
t = i / steps
point = bezier_curve(p0, p1, p2, p3, t)
pyautogui.moveTo(point[0], point[1], duration=0.01)
# Random delay between steps ...with dots
time.sleep(random.uniform(0.005, 0.015))

3.4. Overshoot and micro-corrections​

People often "fly" past the target and return. Add this to the script.
Python:
# Transit flight
human_move(start, (end[0] + 20, end[1] + 20), steps=30)
# Return to target
human_move((end[0] + 20, end[1] + 20), end, steps=20)

Part 4. Error Emulation​

4.1. Why are mistakes necessary?​

Anti-fraud systems analyze not only what you enter but also how you enter it. If you enter data perfectly the first time, it's a sign of a bot. Errors and their corrections are a human trait.

4.2. Error Types​

Error typeFrequencyExample
Typo in name5–10%Entered Jhon instead of John
Typo in card number3–5%Entered 4242 4242 4242 4243 instead of 4242 4242 4242 4242
Typo in CVV2–4%Entered 123 instead of 321
Extra character5–8%Entered JOhn instead of John

4.3. Implementing Errors in the Script​

Python:
def type_with_errors(page, selector, text, error_rate=0.05):
page.click(selector)
human_delay(200, 600)
for i, char in enumerate(text):
# Sometimes type an incorrect character
if random.random() < error_rate:
# Type a random character
wrong_char = chr(random.randint(97, 122))
page.keyboard.type(wrong_char, delay=random.randint(30, 80))
human_delay(200, 500)  # pause before correcting
page.keyboard.press('Backspace')
human_delay(100, 300)
page.keyboard.type(char, delay=random.randint(30, 80))

4.4. Errors in product selection​

A person can add a product, then delete it, then add another. Simulate this.
Python:
# Adding an item
page.click('.add-to-cart')
human_delay(500, 1500)
# Pause — human is thinking
human_delay(2000, 5000)
# Removal
page.click('.remove-from-cart')
human_delay(500, 1500)
# Adding a different item
page.click('.add-to-cart-alternative')

Part 5. Real-World Python Scripting Examples (Playwright)​

5.1. Complete checkout script with human behavior​

Python:
import random
import time
from playwright.sync_api import sync_playwright

def human_delay(min_ms=100, max_ms=500):
time.sleep(random.randint(min_ms, max_ms) / 1000)

def human_move(page, start, end, steps=30):
# ...implementation of a Bezier curve...
pass

def type_with_errors(page, selector, text, error_rate=0.05):
page.click(selector)
human_delay(200, 600)
for char in text:
if random.random() < error_rate:
wrong_char = chr(random.randint(97, 122))
page.keyboard.type(wrong_char, delay=random.randint(30, 80))
human_delay(200, 500)
page.keyboard.press('Backspace')
human_delay(100, 300)
page.keyboard.type(char, delay=random.randint(30, 80))

def main():
with sync_playwright() as p:
browser = p.chromium.launch(
headless=False,
args=['--no-sandbox', '--disable-setuid-sandbox']
)
context = browser.new_context(
user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/132.0.0.0 Safari/537.36'
)
page = context.new_page()

# Step 1: Go to the site
page.goto('https://example.com/checkout')
human_delay(1000, 3000)

# Step 2: Filling in email (with an error)
type_with_errors(page, '#email', 'test@example.com', error_rate=0.03)
human_delay(500, 1500)

# Step 3: Entering the card number (with errors)
type_with_errors(page, '#card-number', '4242424242424242', error_rate=0.02)
human_delay(500, 1500)

# Step 4: Entering the expiry date
type_with_errors(page, '#expiry', '1226', error_rate=0.02)
human_delay(500, 1500)

# Step 5: Entering the CVV (with errors)
type_with_errors(page, '#cvv', '123', error_rate=0.04)
human_delay(500, 1500)

# Step 6: Clicking the button with delay and overshoot
button = page.locator('#submit')
box = button.bounding_box()
target_x = box['x'] + box['width']/2
target_y = box['y'] + box['height']/2
# Overshoot
human_move(page, (500, 300), (target_x + 30, target_y + 20), steps=25)
human_delay(200, 400)
# Return
human_move(page, (target_x + 30, target_y + 20), (target_x, target_y), steps=20)
human_delay(200, 500)
page.click('#submit')

browser.close()

if __name__ == '__main__':
main()

5.2. Integration with OpenBullet (via API, not browser)​

If you're using OpenBullet 2, you can't emulate a mouse. But you can emulate delays and errors at the request level using variables and functions within the config.

Here's an example of a LoliScript with delays and variability:
Code:
SET card_number = {WORD}
SET delay_random = {RANDOM:200,1500}
DELAY %delay_random%

# Error generation: occasionally add an extra character to the card number
IF {RANDOM:1,100} < 5:
SET card_number = {CARD_NUMBER} + "X"
DELAY 500
SET card_number = {REMOVE_LAST_CHAR}
ENDIF

POST https://api.stripe.com/v1/payment_intents
HEADER Idempotency-Key: {GUID}
BODY: payment_method_data[card][number]={{card_number}}&...
DELAY {RANDOM:300,800}

Part 6. Mistakes and how to fix them​

Mistake 1: Making too many mistakes​

Symptom: You're adding an error in every field, and it looks unnatural.
Fix: Errors should be rare (3-5% per field). Don't make errors in every field in a row.

Mistake 2: The Perfect Click​

Symptom: You click exactly in the center of the button with perfect accuracy.
Fix: Add an offset of ±5–15 pixels. Use bounding_box and a random offset.

Mistake 3. Fixed delays​

Symptom: All delays are the same (e.g., 500 ms).
Fix: Use random ranges. People never use pauses of the same length.

Mistake 4. No scrolling​

Symptom: You never scroll the page before filling it.
Fix: Add variable-speed scrolling with random pauses.
Python:
def human_scroll(page):
for _ in range(random.randint(2, 5)):
page.evaluate(f"window.scrollBy(0, {random.randint(100, 300)})")
human_delay(200, 800)
# Sometimes scroll back up
if random.random() < 0.3:
page.evaluate(f"window.scrollBy(0, {random.randint(-100, -50)})")
human_delay(200, 600)

Part 7. A Checklist for a Script That Won't Get Detected​

  • Random delays: between characters, fields, clicks.
  • Mouse movement curves: Bezier, overshoot, micro-corrections.
  • Input errors: typos, extra characters, pauses before correction.
  • Rotation of User-Agent and headers.
  • Scroll with variable speed and returns.
  • Simulating doubts: freezing before clicking, returning to the previous page.
  • Random selection of products: not always the first one.
  • Removing and adding items to the cart.
  • Using different proxies for each session.

Summary​

OpenBullet's default scripts burn out within five minutes because they're too perfect. Humans make mistakes, hesitate, and move erratically. Your script should do the same. Add random delays, emulate mouse movements along a Bézier curve, make typos and fix them. Use the ghost-cursor and @@extra /humanize libraries if you're working with a browser. In OpenBullet, use random delays and variability in the config. Then the anti-fraud system won't recognize you as a bot.

A quick one-line reminder:
"Error is a human. Perfection is a bot. Add random delays, erratic movements, and typos. Then the anti-fraud system won't recognize you."
 
Top