Generic bot that browses any website you point it at. Every N seconds, it randomly picks one of these main actions:
- scroll — scrolls the page in several smooth steps
- click — clicks a random link from the mapped list (
links.json) - refresh — reloads the current page
- home — goes directly back to the start URL (no link click needed)
The click action is weighted higher. Every cycle also includes scrolling, so the time spent on a page mimics a real user reading the content.
Anti-stuck: the bot returns home automatically when (1) the current page has no clickable links, (2) a navigation fails, or (3) every N cycles (default 5, tunable via HOME_EVERY_N_CYCLES).
Multiple bots in parallel: run BOTS=N to spin up N independent sessions in the same process. Each one has isolated cookies/storage and varied User-Agents. Each bot gets its own log color and a random name (e.g. [ada-falcon]) so you can tell them apart.
git clone https://github.com/interaminense/traffic-generator.git
cd traffic-generator
npm install
npx playwright install chromium# As CLI arg:
npm run map-links -- https://example.com
# Or via env var:
TARGET_URL=https://example.com npm run map-linksThe resulting links.json is written to the project root:
{
"baseHost": "example.com",
"startUrl": "https://example.com",
"links": [
{ "href": "...", "text": "...", "foundOn": "..." }
]
}Re-run whenever you switch sites or when the target site gains new links. You can also edit links.json by hand.
# As CLI arg:
node bot.js https://example.com
# Or via env var:
TARGET_URL=https://example.com npm start
TARGET_URL=https://example.com npm run headlessIf links.json is missing (or belongs to another host), the bot automatically falls back to extracting links from the current page each cycle.
| Variable | Default | Description |
|---|---|---|
TARGET_URL |
— (required) | Start URL. Can also be passed as the first CLI arg. |
INTERVAL_MS |
30000 (30 s) |
Time between cycles, in ms. Use min-max (e.g. 20000-45000) for a random range per cycle |
HEADLESS |
false |
true to run without a window |
LINKS_FILE |
./links.json |
Path to the mapped-links file |
HOME_EVERY_N_CYCLES |
5 |
Force home every N cycles (0 disables) |
BOTS |
1 |
Number of parallel bots in the same process |
STAGGER_MS |
2000 |
Delay between each bot's start |
NO_COLOR |
0 |
1 to disable colored logs (auto-disables when stdout isn't a TTY) |
USER_AGENTS |
— (uses 15 built-in UAs) | List of UAs separated by ` |
USER_AGENTS_FILE |
— | Path to JSON with an array of strings (or { "userAgents": [...] }) |
MAX_PAGES |
15 (only for map-links) |
Maximum pages visited during crawl |
PATH_PREFIX |
— (empty) | Restrict links to a path prefix (e.g. /blog) |
EXCLUDE_PATTERNS |
— (empty) | Comma-separated regexes. Any link matching any of them is skipped |
SAME_HOST_ONLY |
true |
false allows following links to other hosts |
# Browse only the blog section
PATH_PREFIX=/blog node bot.js https://example.com
# Skip login/admin pages
EXCLUDE_PATTERNS='/login,/admin,p_p_id=' node bot.js https://example.com
# Liferay site (filters out portlet/infra URLs)
EXCLUDE_PATTERNS='p_p_id=,/c/portal/,/-/login/' node bot.js https://my-liferay.com
# 5 parallel bots, headless, 1-minute cycle, in the background
HEADLESS=true BOTS=5 INTERVAL_MS=60000 \
nohup node bot.js https://example.com > bot.log 2>&1 &
# Human-like timing: each cycle waits a random 20–45 seconds
INTERVAL_MS=20000-45000 BOTS=3 node bot.js https://example.com
# More aggressive crawl: 100 pages
MAX_PAGES=100 npm run map-links -- https://example.comAutomatic, no configuration needed. Each bot picks its own User-Agent from a built-in pool of ~15 real, current UAs covering:
- Desktop: Chrome / Firefox / Safari / Edge / Opera (Windows, macOS, Linux)
- Mobile: iOS Safari (iPhone/iPad), Android Chrome (Pixel/Samsung), Android Firefox
Bot N picks the UA at position (N-1) % poolSize (deterministic, so logs are reproducible). With BOTS<=15, every bot gets a distinct UA. Beyond that, the pool cycles.
You don't have to configure anything — just BOTS=N and each bot becomes a different "user".
If you want to force specific UAs (e.g. test as Googlebot or a corporate UA), priority is: USER_AGENTS_FILE > USER_AGENTS env > built-in pool.
Via env var (separator |):
USER_AGENTS='MyUA-1/1.0|MyUA-2/1.0|MyUA-3/1.0' BOTS=3 node bot.js https://example.comVia JSON file (USER_AGENTS_FILE):
[
"Mozilla/5.0 (iPhone; CPU iPhone OS 17_2 like Mac OS X) AppleWebKit/605.1.15 ...",
"GoogleBot/2.1 (+http://www.google.com/bot.html)"
]USER_AGENTS_FILE=./user-agents.json BOTS=3 node bot.js https://example.comAssignment rule: bot N receives the UA at position (N-1) % length. A list shorter than the bot count is cycled; if longer, the extras are ignored.
The bot considers a link navigable when it:
- Uses
http/httpsprotocol - Is on the same host as
TARGET_URL(unlessSAME_HOST_ONLY=false) - Is not an asset (image, video, css, js, pdf, font, etc.)
- Is not an anchor (
#),mailto:,tel:,javascript:ordata: - Matches the configured
PATH_PREFIX, if any - Doesn't match any of the configured
EXCLUDE_PATTERNS
Press Ctrl+C in the foreground window, or kill <pid> if running in the background.