@tokenring-ai/chrome
Overview
The @tokenring-ai/chrome package provides Chrome browser automation for Token Ring using Puppeteer. It enables AI agents to perform web searches, news searches, web scraping, and screenshot capture in a headless browser environment.
Key Features
- Puppeteer-based headless Chrome browser automation
- Google web search integration via DOM parsing
- Google News search with article metadata extraction
- Web page scraping with HTML to Markdown conversion
- Page metadata extraction including JSON-LD structured data
- Visual screenshot capture with configurable viewport dimensions
- Browser lifecycle management (launch vs connect)
- Support for rendered and non-rendered page fetching
- Agent state management for browser configuration
- Custom Puppeteer script execution tool
Installation
bun install @tokenring-ai/chrome
Configuration
ChromeConfigSchema
export const ChromeConfigSchema = z.object({
agentDefaults: z.object({
launch: z.boolean().default(true),
headless: z.boolean().default(true),
browserWSEndpoint: z.string().optional(),
executablePath: z.string().optional(),
screenshot: z.object({
maxPixels: z.number().default(1000000),
}).prefault({}),
}).prefault({}),
});
ChromeAgentConfigSchema
export const ChromeAgentConfigSchema = z.object({
launch: z.boolean().optional(),
headless: z.boolean().optional(),
browserWSEndpoint: z.string().optional(),
executablePath: z.string().optional(),
screenshot: z.object({
maxPixels: z.number().optional(),
}).optional(),
}).default({});
Example Configuration
{
"chrome": {
"agentDefaults": {
"launch": true,
"headless": true,
"screenshot": {
"maxPixels": 1000000
}
}
}
}
Configuration Notes:
launch: true- Creates a new Puppeteer browser instance for each operationlaunch: false- Connects to an existing browser session (for production use with remote browser)headless: true- Runs browser in headless mode (default)headless: false- Runs browser with visible UI (useful for debugging)browserWSEndpoint- WebSocket endpoint for connecting to an existing browser (e.g.,ws://localhost:9222/devtools/browser)executablePath- Custom path to Chrome/Chromium executablescreenshot.maxPixels- Maximum total pixels for screenshot viewport calculation (default: 1000000)
Core Components
ChromeService
Main service implementation that manages browser lifecycle and provides browser instances to other components.
Class Definition:
import ChromeService from "@tokenring-ai/chrome";
const chromeService = new ChromeService({
agentDefaults: {
launch: true,
headless: true,
screenshot: {
maxPixels: 1000000
}
}
});
Public Methods:
attach(agent: Agent): void
Attaches the ChromeService to an agent, merging configuration with agent-specific configuration using deepMerge from @tokenring-ai/utility, and initializing state using ChromeState.
async getBrowser(agent: Agent): Promise<Browser>
Manages browser lifecycle based on configuration:
- If
launch: true: Creates new Puppeteer browser instance viapuppeteer.launch() - If
launch: false: Connects to existing browser session viapuppeteer.connect() - Returns browser instance for the operation
ChromeState
Agent state slice for managing Chrome browser configuration and persistence.
Class Definition:
import {ChromeState} from "@tokenring-ai/chrome";
const state = new ChromeState({
launch: true,
headless: true,
browserWSEndpoint: undefined,
executablePath: undefined,
screenshot: {
maxPixels: 1000000
}
});
Properties:
launch: boolean- Whether to launch a new browser instanceheadless: boolean- Whether to run browser in headless modebrowserWSEndpoint?: string- WebSocket endpoint for connecting to existing browserexecutablePath?: string- Custom path to Chrome/Chromium executablescreenshot: { maxPixels: number }- Maximum pixels for viewport calculation
Methods:
serialize(): z.output<typeof serializationSchema>
Returns serialized state for persistence.
deserialize(data: z.output<typeof serializationSchema>): void
Restores state from serialized data.
show()
:
string
Returns a formatted string representation of the state:
"Launch: true/false""Headless: true/false""Browser WS Endpoint: endpoint or N/A""Executable Path: path or N/A"
reset(): void
Reset state (currently no-op).
ChromeWebSearchProvider
Main provider implementation extending WebSearchProvider from @tokenring-ai/websearch. Handles browser automation for search and content retrieval.
Class Definition:
import ChromeWebSearchProvider from "@tokenring-ai/chrome";
const provider = new ChromeWebSearchProvider(chromeService);
Public Methods:
async searchWeb(query: string, options?: WebSearchProviderOptions, agent?: Agent): Promise<WebSearchResult>
Performs Google web search via Puppeteer browser. Returns organic search results with title, link, and snippet in order of appearance. Supports countryCode parameter. Uses [data-ved] h3 selectors for results and [data-sncf] for snippets. Browser is disconnected after each request. Requires agent parameter.
async searchNews(query: string, options?: WebSearchProviderOptions, agent?: Agent): Promise<NewsSearchResult>
Performs Google News search via Puppeteer browser. Returns array of news articles with metadata. Parses article containers using [data-news-doc-id] attribute. Extracts title, snippet, source, and date from page elements using data attributes. Browser is disconnected after each request. Requires agent parameter.
async fetchPage(url: string, options?: WebPageOptions, agent?: Agent): Promise<WebPageResult>
Scrapes web page content using Puppeteer browser. Converts HTML to Markdown using TurndownService. Supports rendered and non-rendered fetching via render option - true waits for networkidle0, false waits for domcontentloaded. Browser is disconnected after each request. Requires agent parameter.
Services
The package provides the following service implementation:
ChromeService
The ChromeService class implements the TokenRingService interface and provides browser lifecycle management for Puppeteer automation.
Interface:
interface TokenRingService {
name: string;
description: string;
attach(agent: Agent): void;
}
Implementation Details:
name: "ChromeService"description: "Chrome browser automation service"attach(): Merges default configuration with agent-specific configuration usingdeepMergefrom@tokenring-ai/utility, then initializesChromeState
Providers
The package provides the following provider implementations:
ChromeWebSearchProvider
The ChromeWebSearchProvider class extends WebSearchProvider from @tokenring-ai/websearch and implements search functionality using Chrome/Puppeteer.
Key Methods:
searchWeb(): Performs Google web search via DOM parsing (requires agent)searchNews(): Performs Google News search with article metadata extraction (requires agent)fetchPage(): Scrapes web page content with HTML to Markdown conversion (requires agent)
Important: All methods require an Agent parameter. If no agent is provided, they throw an error.
Tools
The package provides the following tools for agent use:
chrome_scrapePageText
Web page text scraping tool that converts entire page content to Markdown.
Tool Definition:
{
name: "chrome_scrapePageText",
displayName: "Chrome/scrapePageText",
description: "Scrape text content from a web page using Puppeteer. By default, it prioritizes content from 'article', 'main', or 'body' tags in that order. Returns the extracted text along with the source selector used.",
inputSchema: {
url: string,
timeoutSeconds?: number,
selector?: string
}
}
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| url | string | Yes | The URL of the web page to scrape text from |
| timeoutSeconds | number | No | Timeout for the scraping operation (default 30s, min 5s, max 180s) |
| selector | string | No | Custom CSS selector to target specific content. If not provided, will use 'article', 'main', or 'body' in that priority order |
Output: Returns a TokenRingToolResult with:
result: A message describing the extractionattachments: Array containing one attachment with:name: "extracted_text.md"mimeType: "text/markdown"encoding: "text"body: The extracted markdown content
Usage Example:
const result = await agent.callTool("chrome_scrapePageText", {
url: "https://example.com/article",
timeoutSeconds: 30
});
console.log(result.result); // Message describing extraction
console.log(result.attachments[0].body); // Markdown content
Implementation Notes:
- Uses ChromeService for browser management via
agent.requireServiceByType(ChromeService) - Waits for
domcontentloadedevent before extracting content - If
selectoris provided, extracts only that element's outerHTML - If no
selector, tries 'article', then 'main', then 'body' in priority order - Falls back to full page content if no element found
- Converts to Markdown using
TurndownService - Browser is disconnected (not closed) after each operation via
browser.disconnect() - Enforces timeout on operation via
page.gototimeout parameter - Returns
TokenRingToolResultwithresultmessage andattachmentsarray
chrome_scrapePageMetadata
Extracts metadata from web pages including HTML head and JSON-LD structured data.
Tool Definition:
{
name: "chrome_scrapePageMetadata",
displayName: "Chrome/scrapePageMetadata",
description: "Loads a web page and extracts metadata from the <head> tag and any JSON-LD (Schema.org) blocks found in the document. This is useful for SEO analysis and extracting structured data.",
inputSchema: {
url: string,
timeoutSeconds?: number
}
}
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| url | string | Yes | The URL of the web page to scrape metadata from |
| timeoutSeconds | number | No | Timeout for the operation (default 30s, min 5s, max 180s) |
Output: Returns a JSON string containing:
headHtml: Cleaned HTML of the<head>element (with script/style content removed)jsonLd: Array of parsed JSON-LD objects (or error objects for invalid JSON)url: The URL that was scraped
Usage Example:
const result = await agent.callTool("chrome_scrapePageMetadata", {
url: "https://example.com/article",
timeoutSeconds: 30
});
const data = JSON.parse(result);
console.log('Head HTML:', data.headHtml);
console.log('JSON-LD:', data.jsonLd);
console.log('URL:', data.url);
Implementation Details:
- Uses ChromeService for browser management via
agent.requireServiceByType(ChromeService) - Waits for
domcontentloadedevent before extracting metadata - Clones the
<head>element to avoid modifying the live page - Removes content from
<style>and<script>tags (except JSON-LD) to reduce size - Extracts all
<script type="application/ld+json">blocks and parses them as JSON - Handles parsing errors gracefully, returning error objects for invalid JSON
- Enforces timeout on operation via setTimeout (max 180s, min 5s)
- Browser is closed (not disconnected) after operation completion via
browser.close() - Returns a JSON string (not wrapped in TokenRingToolJSONResult)
chrome_takeScreenshot
Captures visual screenshots of web pages with configurable viewport dimensions.
Tool Definition:
{
name: "chrome_takeScreenshot",
displayName: "Chrome/takeScreenshot",
description: "Captures a visual screenshot of a web page at a specific width. Returns the image as base64 data.",
inputSchema: {
url: string,
screenWidth?: number
}
}
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| url | string | Yes | The URL of the web page to screenshot |
| screenWidth | number | No | Viewport width (default 1024, min 300, max 1024) |
Output: Returns a TokenRingToolResult with:
result: A message describing the screenshotattachments: Array containing one attachment with:name: "screenshot.png"mimeType: "image/png"encoding: "base64"body: Base64-encoded PNG image data
Usage Example:
const result = await agent.callTool("chrome_takeScreenshot", {
url: "https://example.com",
screenWidth: 1024
});
console.log(result.result); // Message describing screenshot
console.log(result.attachments[0].body); // Base64 PNG data
// Save to file
import fs from 'fs';
fs.writeFileSync('screenshot.png', result.attachments[0].body, 'base64');
Implementation Details:
- Uses ChromeService for browser management via
agent.requireServiceByType(ChromeService) - Reads
screenshot.maxPixelsfrom agent state (ChromeState) to calculate viewport height - Calculates viewport height as:
height = Math.floor(config.screenshot.maxPixels / screenWidth) - Sets viewport with
deviceScaleFactor: 1for 1:1 pixel ratio - Waits for
networkidle2before capturing screenshot (network activity has mostly stopped) - Captures only the visible viewport (not full page) with
fullPage: false - Returns screenshot as base64-encoded PNG in attachments
- Browser is closed (not disconnected) after operation completion via
browser.close() - Returns
TokenRingToolResultwithresultmessage andattachmentsarray
chrome_runPuppeteerScript
Execute custom Puppeteer scripts with access to page and browser instances. This tool launches its own browser independently of ChromeService.
Tool Definition:
{
name: "chrome_runPuppeteerScript",
displayName: "Chrome/runPuppeteerScript",
description: "Run a Puppeteer script with access to a browser and page. Accepts a JavaScript function or module as a string, executes it with Puppeteer page instance, and returns the result.",
inputSchema: {
script: string,
navigateTo?: string,
timeoutSeconds?: number
}
}
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| script | string | Yes | JavaScript code string defining an async function |
| navigateTo | string | No | Page URL to navigate before executing the script |
| timeoutSeconds | number | No | Timeout (default 30, min 5, max 180) |
Output: Returns a JSON string containing:
result: The return value from the executed scriptlogs: Array of log strings fromconsoleLogcalls and browser console events
Usage Example:
const result = await agent.callTool("chrome_runPuppeteerScript", {
script: `(async ({ page, browser, consoleLog }) => {
consoleLog('Starting Puppeteer script...');
await page.goto('https://example.com');
const title = await page.title();
consoleLog('Page title:', title);
const links = await page.$$eval('a', links => links.map(l => l.href));
consoleLog('Found', links.length, 'links');
return { title, linkCount: links.length };
})`,
navigateTo: 'https://example.com',
timeoutSeconds: 30
});
const data = JSON.parse(result);
console.log('Result:', data.result);
console.log('Logs:', data.logs);
Script Function Signature:
The script should define or export an async function that accepts:
page: Puppeteer Page instance for navigation and interactionbrowser: Puppeteer Browser instance for browser-level operationsconsoleLog: Custom logging function that captures output to thelogsarray
Implementation Details:
- Launches its own browser with
puppeteer.launch({headless: false})- does NOT use ChromeService - Browser is launched in visible mode (
headless: false) for debugging purposes - Creates new page via
browser.newPage() - Provides
consoleLogfunction that captures arguments as space-separated strings - Listens to
page.on('console')events and captures browser console output - If
navigateTois provided, navigates to URL withwaitUntil: 'load'and 20s timeout - Wraps user script in async IIFE and executes with
page,browser, andconsoleLogcontext - Enforces timeout on script execution (max 180s, min 5s) using
setTimeout - Catches errors and throws with
[chrome_runPuppeteerScript]prefix - Browser is closed (not disconnected) after operation completion via
browser.close() - Returns a JSON string (not wrapped in TokenRingToolResult)
- Important: This tool operates independently of ChromeService and agent configuration
Usage Examples
Basic Web Search
import ChromeWebSearchProvider from "@tokenring-ai/chrome";
import ChromeService from "@tokenring-ai/chrome";
const chromeService = new ChromeService({
agentDefaults: {
launch: true,
headless: true,
screenshot: {
maxPixels: 1000000
}
}
});
const provider = new ChromeWebSearchProvider(chromeService);
// Perform a web search (requires agent)
const results = await provider.searchWeb('TypeScript documentation', {
countryCode: 'us'
}, agent);
console.log('Organic results:', results.organic.map(r => r.title));
console.log('Result count:', results.organic.length);
// Access individual results
results.organic.forEach(result => {
console.log(`${result.position}. ${result.title}`);
console.log(` Link: ${result.link}`);
console.log(` Snippet: ${result.snippet}`);
});
Google News Search
// Search for recent news (requires agent)
const news = await provider.searchNews('artificial intelligence', {
countryCode: 'us'
}, agent);
console.log('News articles:', news.news.length);
news.news.forEach(article => {
console.log(`\`${article.title}\``);
console.log(` Source: ${article.source}`);
console.log(` Date: ${article.date}`);
console.log(` Snippet: ${article.snippet}`);
});
Page Content Retrieval
// Scrape web page content (requires agent)
const pageContent = await provider.fetchPage('https://example.com/article', {
render: true
}, agent);
console.log(pageContent.markdown.substring(0, 200) + '...');
// Returns markdown-formatted content of the page
// Non-rendered fetching (faster, no JavaScript)
const staticContent = await provider.fetchPage('https://example.com', {
render: false
}, agent);
Tool Usage - Scrape Page Text
// Use the scrapePageText tool directly
const result = await agent.callTool("chrome_scrapePageText", {
url: "https://example.com/blog/post",
timeoutSeconds: 30
});
console.log(result.result); // Message describing extraction
console.log(result.attachments[0].body); // Markdown content
Metadata Extraction
const result = await agent.callTool("chrome_scrapePageMetadata", {
url: "https://example.com/article"
});
const data = JSON.parse(result);
console.log('Head HTML:', data.headHtml.substring(0, 200) + '...');
console.log('JSON-LD blocks:', data.jsonLd.length);
data.jsonLd.forEach((item, i) => {
console.log(`\nJSON-LD block ${i + 1}:`, item);
});
Screenshot Capture
const result = await agent.callTool("chrome_takeScreenshot", {
url: "https://example.com",
screenWidth: 1024
});
// The screenshot is returned in attachments
import fs from 'fs';
fs.writeFileSync('screenshot.png', result.attachments[0].body, 'base64');
Tool Usage - Run Custom Puppeteer Script
const result = await agent.callTool("chrome_runPuppeteerScript", {
script: `(async ({ page, browser, consoleLog }) => {
consoleLog('Starting script...');
await page.goto('https://example.com');
const title = await page.title();
const links = await page.$$eval('a', links => links.map(l => l.href));
consoleLog('Found', links.length, 'links');
return { title, linkCount: links.length };
})`,
navigateTo: 'https://example.com',
timeoutSeconds: 30
});
const data = JSON.parse(result);
console.log('Result:', data.result);
console.log('Logs:', data.logs);
Integration
The Chrome plugin integrates with the following Token Ring services:
- WebSearchService: Registers ChromeWebSearchProvider as the 'chrome' provider
- ChatService: Registers tools (chrome_scrapePageText, chrome_scrapePageMetadata, chrome_takeScreenshot, chrome_runPuppeteerScript)
- Agent System: Enables agents to perform browser-based tasks via registered tools and configuration
Plugin Registration
The package is registered as a service and tool provider in the TokenRing plugin system:
import type {TokenRingPlugin} from "@tokenring-ai/app";
import {ChatService} from "@tokenring-ai/chat";
import {WebSearchService} from "@tokenring-ai/websearch";
import {z} from "zod";
import ChromeService from "./ChromeService.ts";
import ChromeWebSearchProvider from "./ChromeWebSearchProvider.ts";
import packageJSON from "./package.json" with {type: "json"};
import {ChromeConfigSchema} from "./schema.ts";
import tools from "./tools.ts";
const packageConfigSchema = z.object({
chrome: ChromeConfigSchema.prefault({}),
});
export default {
name: packageJSON.name,
displayName: "Chrome Automation",
version: packageJSON.version,
description: packageJSON.description,
install(app, config) {
app.waitForService(ChatService, (chatService) =>
chatService.addTools(tools),
);
const chromeService = new ChromeService(config.chrome);
app.addServices(chromeService);
app.waitForService(WebSearchService, (websearchService) => {
websearchService.registerProvider(
"chrome",
new ChromeWebSearchProvider(chromeService),
);
});
},
config: packageConfigSchema,
} satisfies TokenRingPlugin<typeof packageConfigSchema>;
Agent Configuration
Configure the chrome service in your TokenRing application:
import TokenRingApp from "@tokenring-ai/app";
import chromePlugin from "@tokenring-ai/chrome";
const app = new TokenRingApp();
app.install(chromePlugin, {
chrome: {
agentDefaults: {
launch: true,
headless: true,
screenshot: {
maxPixels: 1000000
}
}
},
});
// Access provider through websearch service
const websearchService = app.requireService(WebSearchService);
const results = await websearchService.search('your query', 'chrome');
Connecting to Existing Browser
For production environments, connect to an existing browser to avoid launching overhead:
app.install(chromePlugin, {
chrome: {
agentDefaults: {
launch: false,
browserWSEndpoint: "ws://localhost:9222/devtools/browser"
}
}
});
Note: Requires Puppeteer to be launched with --remote-debugging-port=9222 flag.
State Management
The package provides state management for Chrome browser configuration through the ChromeState class.
State Slice
ChromeState manages the following configuration properties:
launch: boolean- Whether to launch a new browser instanceheadless: boolean- Whether to run browser in headless modebrowserWSEndpoint?: string- WebSocket endpoint for connecting to existing browserexecutablePath?: string- Custom path to Chrome/Chromium executablescreenshot: { maxPixels: number }- Maximum pixels for viewport calculation
Persistence and Restoration
The state automatically persists and restores configuration:
// Serialize state
const serialized = chromeState.serialize();
// Deserialize state
chromeState.deserialize(serialized);
Checkpoint Generation
State is automatically checkpointed during agent operations to maintain browser configuration across sessions.
Best Practices
Browser Lifecycle Management
The chrome package uses different browser lifecycle strategies depending on the tool:
- ChromeWebSearchProvider methods (
searchWeb,searchNews,fetchPage): Usebrowser.disconnect()- maintains the browser session - chrome_scrapePageText: Uses
browser.disconnect()- maintains the browser session - chrome_scrapePageMetadata: Uses
browser.close()- terminates the browser session - chrome_takeScreenshot: Uses
browser.close()- terminates the browser session - chrome_runPuppeteerScript: Launches its own browser with
browser.close()- independent operation
Important: Understanding the difference between disconnect() and close():
disconnect()- Closes the connection but keeps the browser running (better for performance)close()- Terminates the browser process entirely (cleaner but slower)
Performance
- Reuse browser connection: Use
launch: falsein production for better performance - Monitor timeouts: Configure appropriate timeouts based on page load times
- Batch operations: Minimize browser launches for multiple requests
- Viewport optimization: Adjust
screenshot.maxPixelsfor optimal screenshot dimensions
Content Extraction
- Full page scraping: The
scrapePageTexttool scrapes the entire page content - Metadata focus: Use
scrapePageMetadatafor SEO analysis and structured data extraction - Timeout management: Keep timeouts reasonable to avoid hanging operations
- Error handling: Always wrap tool calls in try-catch blocks
Resource Management
- Browser cleanup: Browser is automatically closed/disconnected after each operation
- Memory handling: Monitor memory usage during long-running operations
- Network stability: Ensure network connectivity for page loading
Screenshot Usage
- Viewport sizing: The height is calculated as
maxPixels / screenWidth - Viewport capture: Only the visible viewport is captured (not full page)
- Base64 handling: Screenshot data is base64 encoded, handle appropriately for your use case
Custom Script Execution
- Clean script structure: Write scripts that properly clean up after themselves
- Error handling: Use try-catch blocks within scripts
- Console logging: Use provided
consoleLogfunction to capture debug output - Timeouts: Set appropriate timeouts for complex operations
- Browser visibility: Note that scripts run with
headless: falseby default - Independent operation: The
runPuppeteerScripttool operates independently of ChromeService
Testing
The package uses vitest for unit testing:
# Run all tests
bun run test
# Run tests with coverage
bun run test:coverage
# Run tests in watch mode
bun run test:watch
Test Configuration
// vitest.config.ts
import {defineConfig} from 'vitest/config';
export default defineConfig({
test: {
include: ['**/*.test.ts'],
environment: 'node',
globals: true,
isolate: true,
coverage: {
provider: 'v8',
reporter: ['text', 'json', 'html']
}
},
});
Dependencies
The package depends on the following core packages:
@tokenring-ai/app0.2.0 - Application framework and plugin system@tokenring-ai/chat0.2.0 - Chat service and tool definitions@tokenring-ai/agent0.2.0 - Agent framework for tool execution@tokenring-ai/websearch0.2.0 - Base WebSearchProvider and result types@tokenring-ai/utility0.2.0 - Utility functions for deep mergingpuppeteer^24.40.0 - Headless Chrome browser automationturndown^7.2.2 - HTML to Markdown conversionzod^4.3.6 - Runtime type validation
Browser Requirements
- Chrome or Chromium browser installed on the system
- Puppeteer requires system packages for headless mode (Linux/Mac)
- Remote debugging endpoint required when using
launch: false
Install system dependencies (Linux):
# Ubuntu/Debian
sudo apt-get install -y gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget
# Install Chrome
wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
sudo dpkg -i google-chrome-stable_current_amd64.deb
Error Handling
The package provides robust error handling for browser operations:
Common Errors
Browser Launch Failure
// Error: Failed to launch the browser process
// Solution: Ensure Chrome/Chromium is installed and accessible
Connection Timeout
// Error: Navigation took over 20000 ms
// Solution: Increase timeout or verify network connectivity
Invalid URL
// Error: [chrome_scrapePageText] Invalid URL
// Solution: Ensure URL is properly formed and includes http:// or https://
Agent Required
// Error: Agent required for ChromeWebSearchProvider
// Solution: Pass agent parameter to provider methods
Troubleshooting
Puppeteer Launch Issues
"No such binary: chrome"
- Install Chrome browser on your system
- The wrong Chromium binary may be used
- Specify custom
executablePathif needed
"Failed to launch"
- Check Chrome version compatibility with Puppeteer
- Ensure system dependencies are installed
- Verify Chrome is not already running with debugging port
Page Loading Issues
"Navigation timeout exceeded"
- Increase timeout in tool parameters
- Check network connectivity
- Verify target URL is accessible and responsive
Text extraction returns unexpected content
- The tool scrapes the entire page content
- Use
scrapePageMetadatafor structured data instead - Consider using
runPuppeteerScriptfor custom extraction
Metadata extraction returns empty
- Check if page has JSON-LD structured data
- Verify page loads completely before extraction
- Increase timeout for complex pages
Resource Issues
High memory usage
- Browser is automatically closed after each operation
- Process results promptly
- Consider committing browser sessions
Connection refused
- Ensure remote debugging server is running
- Verify WebSocket endpoint is accessible
- Check firewall settings
Screenshot not captured
- Verify URL is accessible
- Check viewport dimensions are valid
- Ensure page loads completely before screenshot
Browser Lifecycle Issues
Inconsistent browser behavior
- Different tools use different lifecycle strategies (disconnect vs close)
- ChromeWebSearchProvider and scrapePageText use disconnect (keeps browser alive)
- ScrapePageMetadata, takeScreenshot, and runPuppeteerScript use close (terminates browser)
- For consistent behavior, consider using runPuppeteerScript for custom control
Custom Script Execution
Script execution failed
- Ensure script returns a value
- Check syntax and import statements
- Use
consoleLogfor debugging output
Timeout errors
- Increase
timeoutSecondsparameter - Optimize script execution time
- Check network conditions
Browser visible when running scripts
- The
runPuppeteerScripttool launches withheadless: false - This is by default for debugging purposes
- Modify the tool implementation if headless mode is required
Tool not using ChromeService
- The
runPuppeteerScripttool operates independently - It does not use the ChromeService or agent configuration
- This is intentional for isolated script execution
Package Structure
pkg/chrome/
├── index.ts # Main exports (ChromeWebSearchProvider, ChromeService)
├── ChromeWebSearchProvider.ts # Main provider implementation
├── ChromeService.ts # Browser lifecycle management service
├── plugin.ts # Plugin registration and tool setup
├── tools.ts # Barrel export for tool definitions
├── schema.ts # Configuration schemas
├── state/
│ └── chromeState.ts # Agent state slice for browser configuration
├── tools/
│ ├── scrapePageText.ts # Web scraping tool implementation
│ ├── scrapePageMetadata.ts # Metadata extraction tool implementation
│ ├── takeScreenshot.ts # Screenshot capture tool implementation
│ └── runPuppeteerScript.ts # Custom script execution tool implementation
├── vitest.config.ts # Test configuration
├── package.json # Package metadata and dependencies
└── README.md # This documentation
Related Components
- WebSearchProvider: Base provider interface from
@tokenring-ai/websearch - WebSearchResult: Search result types from
@tokenring-ai/websearch - TurndownService: HTML to Markdown conversion
- Puppeteer: Chrome browser automation library
- Agent: Token Ring agent framework for tool execution
License
MIT License - see the root LICENSE file for details.