Skip to content
Open
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
38 changes: 38 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Examples

Runnable examples demonstrating Open Browser's capabilities.

## Prerequisites

```bash
bun install
```

Set at least one API key:

```bash
export ANTHROPIC_API_KEY=sk-...
# or
export OPENAI_API_KEY=sk-...
# or
export GOOGLE_GENERATIVE_AI_API_KEY=...
```

## Examples

| Example | Description |
|---|---|
| [basic-agent.ts](./basic-agent.ts) | Give a task in natural language, get a result |
| [extract-data.ts](./extract-data.ts) | Extract structured data from a web page |
| [multi-provider.ts](./multi-provider.ts) | Switch between OpenAI, Anthropic, and Google models |
| [step-callbacks.ts](./step-callbacks.ts) | Monitor agent progress with `onStepStart`/`onStepEnd` hooks |
| [headless-vs-visible.ts](./headless-vs-visible.ts) | Run with or without a visible browser window |
| [url-security.ts](./url-security.ts) | Restrict which URLs the agent can visit |

## Running

```bash
bun run examples/basic-agent.ts
bun run examples/multi-provider.ts openai
bun run examples/headless-vs-visible.ts visible
```
39 changes: 39 additions & 0 deletions examples/basic-agent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* Basic agent example — give a task in natural language and let the agent complete it.
*
* Usage:
* ANTHROPIC_API_KEY=sk-... bun run examples/basic-agent.ts
*/
import { createAnthropic } from '@ai-sdk/anthropic';
import { Agent, Viewport, VercelModelAdapter } from 'open-browser';

const anthropic = createAnthropic({});
const model = new VercelModelAdapter({
model: anthropic('claude-haiku-4-5-20251001'),
});

const browser = new Viewport({ headless: true });
await browser.start();

try {
const agent = new Agent({
task: 'Go to https://news.ycombinator.com and tell me the title of the top story',
model,
browser,
settings: {
stepLimit: 10,
},
});

const result = await agent.run();

console.log('Success:', result.success);
console.log('Result:', result.finalResult);

if (result.totalCost) {
console.log(`Cost: $${result.totalCost.totalCost.toFixed(4)}`);
console.log(`Tokens: ${result.totalCost.totalInputTokens + result.totalCost.totalOutputTokens}`);
}
} finally {
await browser.close();
}
41 changes: 41 additions & 0 deletions examples/extract-data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* Structured data extraction — extract typed data from a web page using a Zod schema.
*
* Usage:
* ANTHROPIC_API_KEY=sk-... bun run examples/extract-data.ts
*/
import { z } from 'zod';
import { createAnthropic } from '@ai-sdk/anthropic';
import { Agent, Viewport, VercelModelAdapter } from 'open-browser';

const anthropic = createAnthropic({});
const model = new VercelModelAdapter({
model: anthropic('claude-haiku-4-5-20251001'),
});

const browser = new Viewport({ headless: true });
await browser.start();

try {
const agent = new Agent({
task: `Go to https://news.ycombinator.com and extract the top 5 stories.
For each story, get the title, URL, points, and number of comments.
Return the data as your final result.`,
model,
browser,
settings: {
stepLimit: 10,
},
});

const result = await agent.run();

if (result.success && result.finalResult) {
console.log('Extracted data:');
console.log(result.finalResult);
} else {
console.error('Extraction failed:', result.errors);
}
} finally {
await browser.close();
}
35 changes: 35 additions & 0 deletions examples/headless-vs-visible.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* Headless vs visible browser — run with or without a visible browser window.
*
* Usage:
* ANTHROPIC_API_KEY=sk-... bun run examples/headless-vs-visible.ts # headless (default)
* ANTHROPIC_API_KEY=sk-... bun run examples/headless-vs-visible.ts visible # show browser
*/
import { createAnthropic } from '@ai-sdk/anthropic';
import { Agent, Viewport, VercelModelAdapter } from 'open-browser';

const headless = process.argv[2] !== 'visible';

const anthropic = createAnthropic({});
const model = new VercelModelAdapter({
model: anthropic('claude-haiku-4-5-20251001'),
});

const browser = new Viewport({ headless });
await browser.start();

console.log(`Browser mode: ${headless ? 'headless' : 'visible'}`);

try {
const agent = new Agent({
task: 'Go to https://example.com and tell me the page title',
model,
browser,
settings: { stepLimit: 5 },
});

const result = await agent.run();
console.log('Result:', result.finalResult);
} finally {
await browser.close();
}
53 changes: 53 additions & 0 deletions examples/multi-provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* Multi-provider example — use different LLM providers (OpenAI, Anthropic, Google).
*
* Usage:
* OPENAI_API_KEY=sk-... bun run examples/multi-provider.ts openai
* ANTHROPIC_API_KEY=sk-... bun run examples/multi-provider.ts anthropic
* GOOGLE_GENERATIVE_AI_API_KEY=... bun run examples/multi-provider.ts google
*/
import { Agent, Viewport, VercelModelAdapter, type LanguageModel } from 'open-browser';

const provider = process.argv[2] ?? 'anthropic';

async function createModel(provider: string): Promise<LanguageModel> {
switch (provider) {
case 'openai': {
const { createOpenAI } = await import('@ai-sdk/openai');
const openai = createOpenAI({});
return new VercelModelAdapter({ model: openai('gpt-4o-mini') });
}
case 'anthropic': {
const { createAnthropic } = await import('@ai-sdk/anthropic');
const anthropic = createAnthropic({});
return new VercelModelAdapter({ model: anthropic('claude-haiku-4-5-20251001') });
}
case 'google': {
const { createGoogleGenerativeAI } = await import('@ai-sdk/google');
const google = createGoogleGenerativeAI({});
return new VercelModelAdapter({ model: google('gemini-2.0-flash') });
}
default:
throw new Error(`Unknown provider: ${provider}. Use: openai, anthropic, google`);
}
}

const model = await createModel(provider);
const browser = new Viewport({ headless: true });
await browser.start();

try {
console.log(`Using provider: ${provider} (${model.modelId})`);

const agent = new Agent({
task: 'Go to https://example.com and tell me the main heading text',
model,
browser,
settings: { stepLimit: 5 },
});

const result = await agent.run();
console.log('Result:', result.finalResult);
} finally {
await browser.close();
}
50 changes: 50 additions & 0 deletions examples/step-callbacks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* Step callbacks — monitor agent progress with onStepStart/onStepEnd hooks.
*
* Usage:
* ANTHROPIC_API_KEY=sk-... bun run examples/step-callbacks.ts
*/
import { createAnthropic } from '@ai-sdk/anthropic';
import { Agent, Viewport, VercelModelAdapter } from 'open-browser';

const anthropic = createAnthropic({});
const model = new VercelModelAdapter({
model: anthropic('claude-haiku-4-5-20251001'),
});

const browser = new Viewport({ headless: true });
await browser.start();

try {
const agent = new Agent({
task: 'Go to https://example.com, click the "More information..." link, and tell me the page title',
model,
browser,
settings: { stepLimit: 10 },
onStepStart: (step) => {
console.log(`\n--- Step ${step} starting ---`);
},
onStepEnd: (step, results) => {
for (const result of results) {
const status = result.success ? '✓' : '✗';
const action = result.isDone ? 'done' : 'action';
console.log(` ${status} ${action}`);

if (result.extractedContent) {
console.log(` extracted: ${result.extractedContent.slice(0, 100)}`);
}
if (result.error) {
console.log(` error: ${result.error}`);
}
}
},
onDone: (result) => {
console.log(`\n=== Done (${result.success ? 'success' : 'failed'}) ===`);
},
});

const result = await agent.run();
console.log('Final result:', result.finalResult);
} finally {
await browser.close();
}
37 changes: 37 additions & 0 deletions examples/url-security.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* URL security policies — restrict which URLs the agent can navigate to.
*
* Usage:
* ANTHROPIC_API_KEY=sk-... bun run examples/url-security.ts
*/
import { createAnthropic } from '@ai-sdk/anthropic';
import { Agent, Viewport, VercelModelAdapter } from 'open-browser';

const anthropic = createAnthropic({});
const model = new VercelModelAdapter({
model: anthropic('claude-haiku-4-5-20251001'),
});

// Allow only specific domains
const browser = new Viewport({
headless: true,
allowedUrls: ['https://example.com/*', 'https://*.iana.org/*'],
});
await browser.start();

try {
const agent = new Agent({
task: 'Go to https://example.com and tell me what you see',
model,
browser,
settings: { stepLimit: 5 },
});

const result = await agent.run();
console.log('Result:', result.finalResult);

// The agent cannot navigate outside the allowed domains.
// If it tries, the UrlPolicyGuard will block the navigation.
} finally {
await browser.close();
}