| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Humanize browser automation for AI agents, QA tests, and demos.
Playwright that moves, types, scrolls, and reads like a real person.
Modern websites are increasingly hostile to all browser automation, and they can't tell the difference between a scraper and an AI agent acting on a user's instructions. Cloudflare, DataDome, PerimeterX read your mouse trajectory and interaction rhythm — and they block on it.
If you're building:
…then your robotic Playwright runs are the problem.
HumanJS makes interactions feel natural. Curved mouse paths. Typing rhythm with hesitation. Reading dwell time based on word count. Configurable personalities. Drop-in for Playwright.
A stealth tool. We do not ship:
Sophisticated anti-bot systems will still detect us. We reduce friction for legitimate use cases — and we say no to the rest by design. If you need evasion tooling, you want a stealth plugin, not HumanJS.
npm install @humanjs/playwright
# or
pnpm add @humanjs/playwrightimport { chromium, createHuman } from '@humanjs/playwright';
const browser = await chromium.launch();
const page = await browser.newPage();
const human = await createHuman(page, {
personality: 'careful', // careful | fast | distracted | precise
seed: 'session-42', // deterministic for tests
speed: 'human', // human | fast | instant
});
await human.goto('https://example.com');
await human.click('Sign in');
await human.type('Email', 'gonzalo@example.com');
await human.paste('Password', process.env.PW!);
await human.check('Remember me');
await human.read('Welcome back');
await human.scroll('natural');Everything that's not specified humanizes by default. Selectors prefer accessible names and roles over CSS. Determinism via seed. CI-friendly via speed: 'instant'.
await createHuman(page, { personality: 'careful' }); // slow, precise, few mistakes
await createHuman(page, { personality: 'fast' }); // quick but still natural
await createHuman(page, { personality: 'distracted' }); // scrolls back, retypes, hovers
await createHuman(page, { personality: 'precise' }); // minimal noise, smooth motionExtend, override, or blend:
await createHuman(page, {
personality: { extends: 'careful', typing: { typoProbability: 0.1 } },
});
await createHuman(page, {
personality: blend('careful', 'distracted', 0.3),
});Or build your own and publish it as @yourname/personality-*. The full Personality type is exported and stable.
Drive a humanized browser straight from your AI agent via the MCP server — works with Claude Code, Claude Desktop, Cursor, Codex, Cline, and any other MCP client. Register it in one command:
claude mcp add humanjs -- npx -y @humanjs/mcp…or one-click for Cursor:
Every action the agent takes goes through HumanJS without changing your agent code. See @humanjs/mcp for the full tool catalog and per-client config.
Writing HumanJS by hand with an AI coding assistant? Install the skill so Claude Code, Cursor, and Codex know the API:
npx @humanjs/skill # this project
npx @humanjs/skill --global # every project (~/.claude/skills, ~/.codex/AGENTS.md)Drops the HumanJS skill into your project (.claude/skills/, .cursor/rules/, or AGENTS.md) — or, with --global, into your home dir for every project. See @humanjs/skill. (The MCP server runs a humanized browser; the skill teaches an agent to write HumanJS.)
const recording = await human.record(async () => {
await human.goto('/checkout');
await human.click('Buy now');
await human.type('Card number', '4242424242424242');
});
await recording.toVideo('checkout.mp4'); // mp4 / webm of the session
await recording.toGif('checkout.gif'); // palette-optimized gif for README embeds
await recording.toTimeline('checkout.json'); // structured JSON for analysis
await recording.toHumanJS('checkout.ts'); // runnable HumanJS script
await recording.toPlaywright('checkout.spec.ts'); // @playwright/test spec (humanized)Replay a recorded timeline against a live page — driven through the same humanized primitives, with per-step pass/fail and stop-at-first-failure (no @playwright/test needed):
import { replayTimeline } from '@humanjs/playwright';
const result = await replayTimeline(page, recording.timeline, {
onStep: ({ index, status }) => console.log(`${index}: ${status}`),
});
console.log(result.status); // 'pass' | 'fail'Or replay a timeline while capturing frames and export the clean run as video/gif — recordReplay is the timeline twin of human.record():
import { recordReplay } from '@humanjs/playwright';
const clip = await recordReplay(page, recording.timeline); // replays + captures, cursor visible
await clip.toGif('demo.gif');
await clip.toVideo('demo.mp4');Or one-call for the simple case (browser/page lifecycle handled for you):
import { record } from '@humanjs/recorder';
await record({ output: 'demo.mp4' }, async (human) => {
await human.click('a');
await human.type('#search', 'humanjs');
});Or skip writing the script entirely — record it visually:
npx @humanjs/generator https://your-app.com@humanjs/generator opens a real Chromium window and a local (loopback-only) dashboard. As you click, type, scroll, and select text, each action is captured with a role-first selector (accessible name + role — the way a person sees the page, not a brittle CSS path) and streams into a live editor as a step. There you can:
Hit Run to replay the recording in a fresh window and watch each step go green or red — verify it passes before you export. When it looks right, export a @playwright/test spec (.spec.ts) or a standalone HumanJS script (.ts) — it runs through the same codegen the library ships, so generated tests stay in lockstep — or export an .mp4 / .gif of the clean replayed flow for a demo or tutorial.
Use the @humanjs/playwright/test fixture — it extends Playwright's test with a ready-to-use human, seeded from the test title and instant in CI, humanized locally. No boilerplate:
import { test, expect } from '@humanjs/playwright/test';
test('checkout flow', async ({ human, page }) => {
await human.goto('/');
await human.click('Buy now');
await expect(page).toHaveURL(/checkout/);
});The seed (the test title) makes runs deterministic; speed: 'instant' in CI keeps the suite fast, full humanization runs locally. Customize per file or project: test.use({ humanOptions: { personality: 'distracted' } }).
Prefer to wire it yourself? Create the human explicitly:
import { test, expect } from '@playwright/test';
import { createHuman } from '@humanjs/playwright';
test('checkout flow', async ({ page }) => {
const human = await createHuman(page, {
seed: test.info().title,
speed: process.env.CI ? 'instant' : 'human',
});
await human.goto('/');
await human.click('Buy now');
await expect(page).toHaveURL(/checkout/);
});| HumanJS | Playwright | ghost-cursor | |
|---|---|---|---|
| Mouse trajectories | ✅ | ❌ | ✅ |
| Typing rhythm | ✅ | ❌ | ❌ |
| Reading dwell | ✅ | ❌ | ❌ |
| Scroll humanization | ✅ | ❌ | ✅ |
| Personalities | ✅ | ❌ | ❌ |
| Session recorder + code export | ✅ | partial | ❌ |
| AI agent integration (MCP server) | ✅ | ❌ | ❌ |
| Playwright-native | ✅ | ✅ | ❌ (Puppeteer) |
| Deterministic via seed | ✅ | n/a | ❌ |
ghost-cursor pioneered humanized mouse paths and is excellent at what it does. HumanJS is for the broader job: humanizing entire interaction sessions in Playwright, with first-class support for AI agents and QA suites.
We welcome PRs that:
We do not accept PRs that:
See CONTRIBUTING.md to get started, and please follow our Code of Conduct. To report a security issue, see the security policy.
The cubic Bezier path math behind humanized mouse trajectories is adapted from ghost-cursor by @Xetera (MIT-licensed). HumanJS humanizes a much broader surface — typing rhythm, reading dwell, scroll, the plugin system, personalities, AI-agent adapters — but the underlying coordinate generation builds on their solid foundation. See THIRD_PARTY_NOTICES.md for full attribution.
MIT — see LICENSE.
Built by Gonzalo Muñoz.
| Back | FazBrowse Home | New Git URL |