Skip to main content
If you’re running Browser Use Cloud today, switching to pre.dev Browser Agents is an SDK swap + an env-var rename. Same task shape (URL + instruction + schema), same structured JSON out. Both services pass 100/100 on our public benchmark — pre.dev is 12× cheaper.

1. Swap env vars + install the SDK

npm uninstall browser-use-sdk
npm install predev-api

# Replace in .env, .env.example, CI, docker-compose, etc.
# BROWSER_USE_API_KEY=...  →  PREDEV_API_KEY=...
Grab your pre.dev key at pre.dev/projects/browser-agents.

2. Run one task

Before — Browser Use
import { BrowserUse } from 'browser-use-sdk/v3';

const client = new BrowserUse({ apiKey: process.env.BROWSER_USE_API_KEY! });

const response = await client.run(
  'Extract the H1 from https://example.com. Return JSON { heading: string }.',
  { llm: 'bu-mini' },
);
const data = JSON.parse(response.output);
After — pre.dev
import { PredevAPI } from 'predev-api';

const client = new PredevAPI({ apiKey: process.env.PREDEV_API_KEY! });

const result = await client.browserAgent([
  {
    url: 'https://example.com',
    instruction: 'Extract the H1.',
    output: {
      type: 'object',
      properties: { heading: { type: 'string' } },
      required: ['heading'],
    },
  },
]);
const data = result.results[0].data; // { heading: 'Example Domain' }
Key differences:
  • URL is a first-class field, not embedded in the instruction. The agent navigates there before running.
  • Output schema is JSON Schema, not a serialized Pydantic/Zod model. The runner validates the response and retries on schema-failure.
  • Tasks is always an array — one method covers 1 task or 1,000.

3. Run many tasks in parallel

Browser Use makes you fire N concurrent run() calls yourself. pre.dev takes an array and fans out server-side — one request, one response.
Before — Browser Use (manual fan-out)
const urls = ['https://news.ycombinator.com', 'https://lobste.rs', 'https://reddit.com/r/programming'];

const responses = await Promise.all(
  urls.map((url) =>
    client.run(`Extract the top 5 story titles from ${url}. Return JSON { titles: string[] }.`, { llm: 'bu-mini' }),
  ),
);
const data = responses.map((r) => JSON.parse(r.output));
After — pre.dev (one call, server-side concurrency)
const result = await client.browserAgent(
  urls.map((url) => ({
    url,
    instruction: 'Extract the top 5 story titles.',
    output: {
      type: 'object',
      properties: { titles: { type: 'array', items: { type: 'string' } } },
      required: ['titles'],
    },
  })),
  { concurrency: 3 },
);
const data = result.results.map((r) => r.data);
Up to 1,000 tasks per request. See Run a Task for the full schema.

4. Async + poll pattern

If you were polling Browser Use by session id, pre.dev has a direct equivalent: pass async: true on submit, then call getBrowserAgent(id).
Before — Browser Use
const handle = client.run(task, { llm: 'bu-mini' });
const sessionId = handle.sessionId;

while (true) {
  const status = await client.sessions.get(sessionId);
  if (status.state === 'finished') break;
  await new Promise((r) => setTimeout(r, 2000));
}
After — pre.dev
const { id } = await client.browserAgent(
  [{ url, instruction, output }],
  { async: true },
);

while (true) {
  const batch = await client.getBrowserAgent(id);
  if (batch.status === 'completed' || batch.status === 'failed') break;
  await new Promise((r) => setTimeout(r, 2000));
}
See Task Status for the full polling contract (pass includeEvents=True for the per-step timeline).

One-shot Claude Code prompt

Drop this into Claude Code at the root of your repo. Works for any stack — Node, Bun, Deno, Python, monorepos.
Migrate this codebase from Browser Use Cloud to pre.dev Browser Agents.

## Why

pre.dev Browser Agents is a drop-in replacement for Browser Use Cloud's
task API: same URL + instruction + JSON-schema contract, structured JSON
output, 12× cheaper at 100/100 pass on the public benchmark. Docs:
https://docs.pre.dev/browser-agents/migrate-from-browser-use

## Do this

1. **Find call sites.** Search the entire repo (not just `src/`) for:
   - Imports: `browser-use-sdk`, `from browser_use`, `BrowserUse`,
     `browser_use_sdk`.
   - Env refs: `BROWSER_USE_API_KEY` in code, `.env`, `.env.example`,
     `.env.*`, CI configs (`.github/workflows/*`, `render.yaml`,
     `vercel.json`, `docker-compose*.yml`, `Dockerfile*`, `fly.toml`),
     README, internal docs.
   - Any `cloud.browser-use.com` or `api.browser-use.com` URLs.

2. **Swap the SDK.**
   - Node/TS/Bun: replace `browser-use-sdk` dependency with
     `predev-api` in `package.json`, `bun.lockb`, `yarn.lock`, or
     `pnpm-lock.yaml` (let the user run the install).
   - Python: replace `browser-use-sdk` with `predev-api` in
     `requirements.txt`, `pyproject.toml`, `poetry.lock`, or
     `Pipfile` (let the user run the install).

3. **Rewrite calls** per these rules. Full mapping at
   https://docs.pre.dev/browser-agents/migrate-from-browser-use — read
   it once before editing.

   | Browser Use | pre.dev |
   |---|---|
   | `import { BrowserUse } from 'browser-use-sdk/v3'` | `import { PredevAPI } from 'predev-api'` |
   | `new BrowserUse({ apiKey })` | `new PredevAPI({ apiKey })` |
   | `client.run(taskStr, { llm })` | `client.browserAgent([{ url, instruction, output }])` |
   | `response.output` (JSON string) | `result.results[0].data` (already parsed) |
   | Python `from browser_use_sdk import BrowserUse` | `from predev_api import PredevAPI` |
   | Python `BrowserUse(api_key=...)` | `PredevAPI(api_key=...)` |
   | Python `client.run(task, llm=...)` | `client.browser_agent([{...}])` |
   | Python `json.loads(response.output)` | `result["results"][0]["data"]` |
   | Embedded URL in task string | first-class `url` field |
   | Zod/Pydantic schema | JSON Schema in `output` field |
   | Parallel via `Promise.all(client.run(...))` | single call with `client.browserAgent([...])` + `{ concurrency }` |
   | `handle.sessionId` + session polling | `client.browserAgent([...], { async: true })` + `client.getBrowserAgent(id)` |
   | Python async equivalent | `client.browser_agent([...], run_async=True)` + `client.get_browser_agent(id)` |

4. **Env vars.** Rename `BROWSER_USE_API_KEY``PREDEV_API_KEY`
   everywhere (code, env files, CI, docker). Base URL is
   `https://api.pre.dev` if it's referenced explicitly.

5. **Unsupported features — leave TODOs, don't delete.** For any of:
   - `client.sessions.*` (persistent sessions)
   - `client.agent_profiles.*` / `AgentProfile`
   - `client.schedules.*`
   - raw Playwright handoff

   Leave a comment above the call:
   `// TODO: pre.dev equivalent not yet available — see https://docs.pre.dev/browser-agents/migrate-from-browser-use#whats-different--not-yet-supported`
   and keep the original code path so tests don't explode. We'll
   hand-migrate these.

6. **Verify.** After edits, run the project's typecheck and test
   commands (infer them from `package.json` scripts,
   `pyproject.toml`, or a `Makefile`). Fix anything that breaks.
   Do not skip this step.

7. **Report.** At the end, print:
   - Files changed (grouped: imports, env, call sites).
   - Count of migrated calls.
   - Count of TODO-comments left for unsupported features.
   - Any test/typecheck failures you couldn't fix, with exact
     file:line and why.

## Constraints

- **Don't delete** any original code until the replacement is verified
  working. If unsure of a mapping, leave the old call with a TODO
  and surface it in the final report.
- **Don't guess** the pre.dev SDK name — it's `predev-api` on both
  npm and pip. If that's not what the project's package manager
  resolves, stop and ask.
- **Respect the user's existing code style** — don't reformat files
  you didn't otherwise change.

Next