Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "1.1.3"
".": "1.2.0"
}
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changelog

## 1.2.0 (2025-08-22)

Full Changelog: [v1.1.3...v1.2.0](https://github.com/browser-use/browser-use-node/compare/v1.1.3...v1.2.0)

### Features

* NextJS Utils ([b5e1006](https://github.com/browser-use/browser-use-node/commit/b5e10060a064de9a9454fa90e461f09154094742))

## 1.1.3 (2025-08-22)

Full Changelog: [v1.1.2...v1.1.3](https://github.com/browser-use/browser-use-node/compare/v1.1.2...v1.1.3)
Expand Down
59 changes: 2 additions & 57 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ export async function POST(req: Request) {
}
```

## Advanced Usage

## Handling errors

When the library is unable to connect to the API,
Expand Down Expand Up @@ -197,8 +199,6 @@ On timeout, an `APIConnectionTimeoutError` is thrown.

Note that requests which time out will be [retried twice by default](#retries).

## Advanced Usage

### Accessing raw Response data (e.g., headers)

The "raw" `Response` returned by `fetch()` can be accessed through the `.asResponse()` method on the `APIPromise` type that all methods return.
Expand Down Expand Up @@ -277,49 +277,6 @@ const client = new BrowserUse({
});
```

### Making custom/undocumented requests

This library is typed for convenient access to the documented API. If you need to access undocumented
endpoints, params, or response properties, the library can still be used.

#### Undocumented endpoints

To make requests to undocumented endpoints, you can use `client.get`, `client.post`, and other HTTP verbs.
Options on the client, such as retries, will be respected when making these requests.

```ts
await client.post('/some/path', {
body: { some_prop: 'foo' },
query: { some_query_arg: 'bar' },
});
```

#### Undocumented request params

To make requests using undocumented parameters, you may use `// @ts-expect-error` on the undocumented
parameter. This library doesn't validate at runtime that the request matches the type, so any extra values you
send will be sent as-is.

```ts
client.tasks.create({
// ...
// @ts-expect-error baz is not yet public
baz: 'undocumented option',
});
```

For requests with the `GET` verb, any extra params will be in the query, all other requests will send the
extra param in the body.

If you want to explicitly send an extra argument, you can do so with the `query`, `body`, and `headers` request
options.

#### Undocumented response properties

To access undocumented response properties, you may access the response object with `// @ts-expect-error` on
the response object, or cast the response object to the requisite type. Like the request params, we do not
validate or strip extra properties from the response from the API.

### Customizing the fetch client

By default, this library expects a global `fetch` function is defined.
Expand Down Expand Up @@ -401,18 +358,6 @@ const client = new BrowserUse({

## Frequently Asked Questions

## Semantic versioning

This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:

1. Changes that only affect static types, without breaking runtime behavior.
2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_
3. Changes that we do not expect to impact the vast majority of users in practice.

We take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.

We are keen for your feedback; please open an [issue](https://www.github.com/browser-use/browser-use-node/issues) with questions, bugs, or suggestions.

## Requirements

TypeScript >= 4.9 is supported.
Expand Down
8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "browser-use-sdk",
"version": "1.1.3",
"version": "1.2.0",
"description": "The official TypeScript library for the Browser Use API",
"author": "Browser Use <[email protected]>",
"types": "dist/index.d.ts",
Expand Down Expand Up @@ -41,6 +41,7 @@
"@swc/jest": "^0.2.29",
"@types/jest": "^29.4.0",
"@types/node": "^24.3.0",
"@types/react": "^19.1.10",
"@typescript-eslint/eslint-plugin": "8.31.1",
"@typescript-eslint/parser": "8.31.1",
"commander": "^14.0.0",
Expand All @@ -51,6 +52,8 @@
"jest": "^29.4.0",
"prettier": "^3.0.0",
"publint": "^0.2.12",
"react": "^19.1.1",
"react-dom": "^19.1.1",
"ts-jest": "^29.1.0",
"ts-node": "^10.5.0",
"tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.9/tsc-multi.tgz",
Expand All @@ -61,7 +64,8 @@
"zod": "^4.0.17"
},
"peerDependencies": {
"zod": "^4.0.17"
"react": "^18 || ^19",
"zod": "^4"
},
"exports": {
".": {
Expand Down
37 changes: 37 additions & 0 deletions src/lib/nextjs/hooks/useBrowserUse.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { useEffect, useState } from 'react';
import type { ZodType } from 'zod';

import type { BrowserUseEvent } from '../server/utils';
import { TaskViewWithSchema } from '../../parse';

/**
* A hook to stream Browser Use updates to the client.
*/
export function useBrowserUse<T extends ZodType = ZodType>(route: string): TaskViewWithSchema<T> | null {
const [status, setStatus] = useState<TaskViewWithSchema<T> | null>(null);

useEffect(() => {
const es = new EventSource(route);

es.addEventListener('status', (e) => {
if (e instanceof MessageEvent) {
const msg = JSON.parse(e.data) as BrowserUseEvent<T>;

setStatus(msg.data);

if (msg.data.status === 'finished') {
es.close();
}
} else {
console.error('Event is not a MessageEvent', e);
}
});

es.addEventListener('end', () => es.close());
es.addEventListener('error', () => es.close());

return () => es.close();
}, [route]);

return status;
}
69 changes: 69 additions & 0 deletions src/lib/nextjs/server/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { TaskViewWithSchema } from '../../parse';
import { ZodType } from 'zod';

export type BrowserUseEvent<T extends ZodType = ZodType> = {
event: 'status';
data: TaskViewWithSchema<T>;
};

/**
* Convert an async generator to a stream.
*
* @param gen - The async generator to convert to a stream.
* @returns A stream of the async generator.
*/
export function gtos(
gen: AsyncGenerator<{
event: 'status';
data: TaskViewWithSchema<ZodType>;
}>,
opts?: {
/**
* Called when an event is emitted.
*/
onEvent?: (event: TaskViewWithSchema<ZodType>) => void;

/**
* Called when the task is finished.
*/
onFinished?: (event: TaskViewWithSchema<ZodType>) => void;
},
): ReadableStream<Uint8Array<ArrayBufferLike>> {
const enc = new TextEncoder();

const stream = new ReadableStream<Uint8Array>({
async start(controller) {
// open the SSE stream quickly
controller.enqueue(enc.encode(': connected\n\n'));

try {
for await (const msg of gen) {
opts?.onEvent?.(msg.data);

const data: BrowserUseEvent = {
event: msg.event,
data: msg.data,
};

const encoded = JSON.stringify(data);

const payload = `event: ${msg.event}\ndata: ${encoded}\n\n`;

controller.enqueue(enc.encode(payload));

if (msg.data.status === 'finished') {
opts?.onFinished?.(msg.data);
}
}

controller.enqueue(enc.encode('event: end\ndata: {}\n\n'));
} catch (e) {
controller.enqueue(enc.encode(`event: error\ndata: ${JSON.stringify({ message: String(e) })}\n\n`));
} finally {
controller.close();
}
},
});

return stream;
}
2 changes: 1 addition & 1 deletion src/version.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export const VERSION = '1.1.3'; // x-release-please-version
export const VERSION = '1.2.0'; // x-release-please-version
29 changes: 29 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -991,6 +991,13 @@
dependencies:
undici-types "~7.10.0"

"@types/react@^19.1.10":
version "19.1.10"
resolved "https://registry.yarnpkg.com/@types/react/-/react-19.1.10.tgz#a05015952ef328e1b85579c839a71304b07d21d9"
integrity sha512-EhBeSYX0Y6ye8pNebpKrwFJq7BoQ8J5SO6NlvNwwHjSj6adXJViPQrKlsyPw7hLBLvckEMO1yxeGdR82YBBlDg==
dependencies:
csstype "^3.0.2"

"@types/stack-utils@^2.0.0":
version "2.0.3"
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8"
Expand Down Expand Up @@ -1475,6 +1482,11 @@ cross-spawn@^7.0.3, cross-spawn@^7.0.6:
shebang-command "^2.0.0"
which "^2.0.1"

csstype@^3.0.2:
version "3.1.3"
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81"
integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==

debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.7:
version "4.4.1"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.1.tgz#e5a8bc6cbc4c6cd3e64308b0693a3d4fa550189b"
Expand Down Expand Up @@ -2984,11 +2996,23 @@ queue-microtask@^1.2.2:
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==

react-dom@^19.1.1:
version "19.1.1"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.1.1.tgz#2daa9ff7f3ae384aeb30e76d5ee38c046dc89893"
integrity sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==
dependencies:
scheduler "^0.26.0"

react-is@^18.0.0:
version "18.3.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e"
integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==

react@^19.1.1:
version "19.1.1"
resolved "https://registry.yarnpkg.com/react/-/react-19.1.1.tgz#06d9149ec5e083a67f9a1e39ce97b06a03b644af"
integrity sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==

readable-stream@^3.4.0:
version "3.6.2"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967"
Expand Down Expand Up @@ -3063,6 +3087,11 @@ safe-buffer@~5.2.0:
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==

scheduler@^0.26.0:
version "0.26.0"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.26.0.tgz#4ce8a8c2a2095f13ea11bf9a445be50c555d6337"
integrity sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==

semver@^6.3.0, semver@^6.3.1:
version "6.3.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
Expand Down