capture_screenshot
Capture webpage screenshots as base64-encoded PNG images. Use this tool to visually document web content, wait for page loading, and optionally save screenshots to local directories for web analysis and documentation.
Instructions
[STATELESS] Capture webpage screenshot. Returns base64-encoded PNG data. Creates new browser each time. Optionally saves screenshot to local directory. IMPORTANT: Chained calls (execute_js then capture_screenshot) will NOT work - the screenshot won't see JS changes! For JS changes + screenshot use create_session + crawl(session_id, js_code, screenshot:true) in ONE call.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| save_to_directory | No | Directory path to save screenshot (e.g., ~/Desktop, /tmp). Do NOT include filename - it will be auto-generated. Large screenshots (>800KB) won't be returned inline when saved. | |
| screenshot_wait_for | No | Seconds to wait before taking screenshot (allows page loading/animations) | |
| url | Yes | The URL to capture |
Implementation Reference
- src/handlers/content-handlers.ts:52-130 (handler)Primary MCP handler for 'capture_screenshot' tool. Handles input validation response formatting, optional local file saving, size-based image return logic, and delegates core screenshot capture to service.async captureScreenshot(options: ScreenshotEndpointOptions) { try { const result: ScreenshotEndpointResponse = await this.service.captureScreenshot(options); // Response has { success: true, screenshot: "base64string" } if (!result.success || !result.screenshot) { throw new Error('Screenshot capture failed - no screenshot data in response'); } let savedFilePath: string | undefined; // Save to local directory if requested if (options.save_to_directory) { try { // Resolve home directory path let resolvedPath = options.save_to_directory; if (resolvedPath.startsWith('~')) { const homedir = os.homedir(); resolvedPath = path.join(homedir, resolvedPath.slice(1)); } // Check if user provided a file path instead of directory if (resolvedPath.endsWith('.png') || resolvedPath.endsWith('.jpg')) { console.warn( `Warning: save_to_directory should be a directory path, not a file path. Using parent directory.`, ); resolvedPath = path.dirname(resolvedPath); } // Ensure directory exists await fs.mkdir(resolvedPath, { recursive: true }); // Generate filename from URL and timestamp const url = new URL(options.url); const hostname = url.hostname.replace(/[^a-z0-9]/gi, '-'); const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, -5); const filename = `${hostname}-${timestamp}.png`; savedFilePath = path.join(resolvedPath, filename); // Convert base64 to buffer and save const buffer = Buffer.from(result.screenshot, 'base64'); await fs.writeFile(savedFilePath, buffer); } catch (saveError) { // Log error but don't fail the operation console.error('Failed to save screenshot locally:', saveError); } } const textContent = savedFilePath ? `Screenshot captured for: ${options.url}\nSaved to: ${savedFilePath}` : `Screenshot captured for: ${options.url}`; // If saved locally and screenshot is large (>800KB), don't return the base64 data const screenshotSize = Buffer.from(result.screenshot, 'base64').length; const shouldReturnImage = !savedFilePath || screenshotSize < 800 * 1024; // 800KB threshold const content = []; if (shouldReturnImage) { content.push({ type: 'image', data: result.screenshot, mimeType: 'image/png', }); } content.push({ type: 'text', text: shouldReturnImage ? textContent : `${textContent}\n\nNote: Screenshot data not returned due to size (${Math.round(screenshotSize / 1024)}KB). View the saved file instead.`, }); return { content }; } catch (error) { throw this.formatError(error, 'capture screenshot'); } }
- src/crawl4ai-service.ts:140-157 (helper)Core service method that performs the actual HTTP POST request to Crawl4AI's /screenshot endpoint, returning base64 PNG data. Includes URL validation and error handling.async captureScreenshot(options: ScreenshotEndpointOptions): Promise<ScreenshotEndpointResponse> { // Validate URL if (!validateURL(options.url)) { throw new Error('Invalid URL format'); } try { const response = await this.axiosClient.post('/screenshot', { url: options.url, screenshot_wait_for: options.screenshot_wait_for, // output_path is omitted to get base64 response }); return response.data; } catch (error) { return handleAxiosError(error); } }
- Zod schema for validating capture_screenshot tool inputs, using createStatelessSchema to reject session_id.export const CaptureScreenshotSchema = createStatelessSchema( z.object({ url: z.string().url(), screenshot_wait_for: z.number().optional(), save_to_directory: z.string().optional().describe('Local directory to save screenshot file'), // output_path not exposed as MCP needs base64 data }), 'capture_screenshot', );
- src/server.ts:829-835 (registration)Server switch case registration mapping 'capture_screenshot' tool calls to the contentHandlers.captureScreenshot method with schema validation.case 'capture_screenshot': return await this.validateAndExecute( 'capture_screenshot', args, CaptureScreenshotSchema, async (validatedArgs) => this.contentHandlers.captureScreenshot(validatedArgs), );
- src/server.ts:150-174 (registration)Tool registration in listTools response: defines name, description, and inputSchema for capture_screenshot.{ name: 'capture_screenshot', description: "[STATELESS] Capture webpage screenshot. Returns base64-encoded PNG data. Creates new browser each time. Optionally saves screenshot to local directory. IMPORTANT: Chained calls (execute_js then capture_screenshot) will NOT work - the screenshot won't see JS changes! For JS changes + screenshot use create_session + crawl(session_id, js_code, screenshot:true) in ONE call.", inputSchema: { type: 'object', properties: { url: { type: 'string', description: 'The URL to capture', }, screenshot_wait_for: { type: 'number', description: 'Seconds to wait before taking screenshot (allows page loading/animations)', default: 2, }, save_to_directory: { type: 'string', description: "Directory path to save screenshot (e.g., ~/Desktop, /tmp). Do NOT include filename - it will be auto-generated. Large screenshots (>800KB) won't be returned inline when saved.", }, }, required: ['url'], }, },