# How ego-browser Handles File Uploads with setInputFiles: A CDP Deep Dive

> Learn how ego-browser handles file uploads using setInputFiles. This CDP deep dive explains invoking DOM.setFileInputFiles via Chrome DevTools Protocol for efficient file uploads.

- Repository: [CitroLabs/ego-lite](https://github.com/citrolabs/ego-lite)
- Tags: deep-dive
- Published: 2026-08-07

---

**The `setInputFiles` helper in ego-browser uploads files to `<input type="file">` elements by resolving selectors to Chrome DevTools Protocol (CDP) object IDs and invoking the native `DOM.setFileInputFiles` method.**

The `ego-browser` package from the `citrolabs/ego-lite` repository enables agent scripts to automate complex browser interactions programmatically. When you need to upload files through web forms, the **`setInputFiles`** function provides a direct bridge between your agent code and the browser's file input mechanics, handling the entire workflow from selector resolution to CDP execution.

## Architecture of the setInputFiles Helper

The `setInputFiles` implementation follows a layered architecture that separates the public API surface from the underlying CDP operations.

### Public API Entry Point (src/helpers.ts)

The helper is exposed to agent scripts through the main helpers module. In [`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts) at line 99, the function is re-exported from the driver files module:

```typescript
// src/helpers.ts (line 99)
export { setInputFiles } from "./driver/files.js";

```

This export makes `setInputFiles` available in the helper context that agents receive during script execution.

### Driver Implementation (src/driver/files.ts)

The actual upload logic resides in [`src/driver/files.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/driver/files.ts) (lines 4-15). The function accepts a selector and file path(s), then orchestrates the CDP interaction:

```typescript
// src/driver/files.ts
/**
 * Set files on a file input.
 * @param {string} selector CSS selector / @ref / loc= / xpath= for an input[type=file].
 * @param {string|string[]} path Absolute file path or paths to upload.
 */
export async function setInputFiles(selector, path) {
  const files = Array.isArray(path) ? path : [path];
  await withHandle(selector, async ({ objectId, sessionId }) => {
    await cdp("DOM.setFileInputFiles", { files, objectId }, sessionId);
  });
}

```

The implementation uses **array normalization** to handle both single strings and arrays of paths uniformly before passing them to the Chrome DevTools Protocol.

## How the Upload Works Under the Hood

The execution flow involves three critical components working in sequence to manipulate the browser's DOM directly.

### Selector Resolution via withHandle

The `withHandle` utility from [`src/driver/element-ops.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/driver/element-ops.ts) resolves the provided selector to a CDP **objectId** and **sessionId**. This function handles multiple selector formats including:

- CSS selectors (`input#resume`)
- Reference IDs (`@123`)
- Location-based selectors (`loc=css:#profile-pic`)
- XPath expressions (`xpath=//input[@type='file']`)

### CDP Command Invocation

Once resolved, the function invokes `cdp("DOM.setFileInputFiles", …)` from [`src/cdp-eval.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/cdp-eval.ts). This sends the native CDP command that updates the DOM node's `files` property directly, simulating a user file selection without requiring UI interaction.

The CDP call structure follows this pattern:

```typescript
await cdp("DOM.setFileInputFiles", { 
  files: ['/absolute/path/to/file.pdf'], 
  objectId: 'node-object-id' 
}, sessionId);

```

When the command succeeds, the file input's `files` property reflects the uploaded files exactly as if a user had manually selected them through the browser's file picker.

## Practical Code Examples

You can call `setInputFiles` anywhere within an ego-browser agent script. The function returns a Promise that resolves when the browser confirms the file list update.

Upload a single file using a CSS selector:

```javascript
await setInputFiles('input#resume', '/home/user/documents/resume.pdf');

```

Upload multiple files to inputs supporting the `multiple` attribute:

```javascript
await setInputFiles('#gallery-upload', [
  '/tmp/img1.png',
  '/tmp/img2.png',
  '/tmp/img3.png'
]);

```

Using alternative selector syntax supported by the `withHandle` utility:

```javascript
// Reference-based selector
await setInputFiles('@123', '/var/data/report.csv');

// Location-based selector
await setInputFiles('loc=css:#profile-pic', '/pics/avatar.png');

```

## Error Handling Behavior

Any errors originating from the CDP call—such as invalid file paths, non-existent DOM nodes, or elements that aren't file inputs—bubble up through the helper framework. These errors manifest as standard JavaScript exceptions that you can catch using standard `try…catch` blocks:

```javascript
try {
  await setInputFiles('#upload', '/nonexistent/file.pdf');
} catch (error) {
  console.error('Upload failed:', error.message);
}

```

This error propagation ensures that agent scripts can implement robust retry logic or fallback behaviors when file operations fail.

## Summary

- **Entry Point**: `setInputFiles` is exported from [`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts) (line 99) for use in agent scripts.
- **Core Logic**: Implementation resides in [`src/driver/files.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/driver/files.ts), utilizing `withHandle` from [`src/driver/element-ops.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/driver/element-ops.ts) and CDP commands from [`src/cdp-eval.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/cdp-eval.ts).
- **Selector Support**: Accepts CSS, `@ref`, `loc=`, and `xpath=` selector formats, all resolved to CDP object IDs.
- **Protocol**: Uses `DOM.setFileInputFiles` via Chrome DevTools Protocol to set absolute file paths directly on DOM nodes.
- **Input Types**: Handles both single strings and arrays of absolute file paths for multiple file uploads.
- **Error Handling**: CDP errors propagate as JavaScript exceptions for standard try/catch handling within agent scripts.

## Frequently Asked Questions

### What selector types does setInputFiles support?

The function supports CSS selectors, reference IDs prefixed with `@` (like `@123`), location-based selectors using the `loc=` prefix, and XPath expressions using the `xpath=` prefix. The `withHandle` utility in [`src/driver/element-ops.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/driver/element-ops.ts) normalizes these formats to CDP object IDs before execution.

### Can setInputFiles handle multiple file uploads?

Yes. When the target `<input type="file">` element has the `multiple` attribute, pass an array of absolute paths as the second argument. The function normalizes single strings into arrays internally, ensuring consistent handling regardless of whether you upload one file or many.

### How does error handling work in setInputFiles?

Errors from the underlying CDP call—such as invalid selectors, non-existent files, or elements that aren't file inputs—propagate up through the helper framework as standard JavaScript exceptions. You can wrap calls in `try…catch` blocks to handle failures gracefully within your agent scripts.

### Is setInputFiles used for file downloads as well?

No. While `setInputFiles` specifically handles uploads via `DOM.setFileInputFiles`, the ego-browser package handles downloads through different CDP mechanisms, typically via `Page.setDownloadBehavior` or network response interception. The `setInputFiles` function is exclusively for uploading files to `<input type="file">` elements.