> Full docs index: https://docs.steel.dev/llms.txt

# Overview
URL: https://docs.steel.dev/overview/files-api/overview


Steel provides two complementary file management systems: Session Files for working with files within active browser sessions, and Global Files for persistent file storage across your organization.

### Overview

Steel's file management system makes it easy to work with files in your automated workflows:

*   **Session-Based File Operations**: Upload files to active sessions for immediate use in browser automations, download files acquired during browsing

*   **Persistent File Storage**: Maintain a global file repository for reuse across multiple sessions and workflows

*   **Workspace Management**: Organize and access files generated across different automation runs

*   **Data Pipeline Integration**: Upload datasets once and reference them across multiple automation sessions

*   **File Archival**: Automatically preserve files from completed sessions for later access

### How It Works

#### Session Files System

Files uploaded to active sessions become available within that session's isolated VM environment. These files can be used immediately with web applications and browser automation tools. When files are downloaded from the internet during a session, they become accessible through the same API. Session files persist beyond session lifecycle - files are automatically backed up when sessions end.

#### Global Files System

The Global Files API provides persistent, organization-wide file storage independent of browser sessions. Files uploaded to global storage can be referenced and mounted in any session. All session files are automatically promoted to global storage when sessions are released, creating a comprehensive file workspace.

### Session Files API

This section outlines how to interact with the filesystem inside of the VM that your session is running from. All of these files are accessible from the browser.

#### Upload Files to Session File System

```typescript
// Upload file to session environment
const file = fs.createReadStream("./steel.png");
const session = await client.sessions.create();
const uploadedFile = await client.sessions.files.upload(session.id, {
  file: file, // or path in global files api or absolute url
});
```

```python
import requests

session_id = "YOUR_SESSION_ID"
api_key = "YOUR_API_KEY_HERE"
file_path = "./steel.png"

with open(file_path, "rb") as f:
    response = requests.post(
        f"https://api.steel.dev/v1/sessions/{session_id}/files",
        headers={"steel-api-key": api_key},
        files={"file": f}
    )
print(response.json())
```

#### List Files in a Session File System

```typescript
const files = await client.sessions.files.list(sessionId);
files.data.forEach((file) => {
  console.log(`${file.path} | Size: ${file.size} | Last Modified: ${file.lastModified}`);
});
```

```python
import requests

session_id = "YOUR_SESSION_ID"
api_key = "YOUR_API_KEY_HERE"

response = requests.get(
    f"https://api.steel.dev/v1/sessions/{session_id}/files",
    headers={"steel-api-key": api_key}
)
for file in response.json()["data"]:
    print(f"{file['path']} | Size: {file['size']} | Last Modified: {file['lastModified']}")
```

#### Download Files from Session File System

For raw HTTP requests, the `{path}` parameter is relative. Session file responses currently come back in a `/files/...` form, so strip that prefix before interpolating the value into the URL.

```typescript
// Download a specific file from a session
const response = await client.sessions.files.download(sessionId, "path/to/file");
const fileBlob = await response.blob();

// Download all files as zip archive
const archiveResponse = await client.sessions.files.downloadArchive(sessionId);
```

```python
import requests

session_id = "YOUR_SESSION_ID"
api_key = "YOUR_API_KEY_HERE"

# Download a specific file
file_resp = requests.get(
    f"https://api.steel.dev/v1/sessions/{session_id}/files/path/to/file",
    headers={"steel-api-key": api_key}
)
with open("downloaded_file", "wb") as f:
    f.write(file_resp.content)

# Download all files as zip archive
archive_resp = requests.get(
    f"https://api.steel.dev/v1/sessions/{session_id}/files.zip",
    headers={"steel-api-key": api_key}
)
with open("session_files.zip", "wb") as f:
    f.write(archive_resp.content)
```

#### Delete Files from Sessions File System

The raw HTTP delete endpoint also expects the relative path segment rather than the `/files/...` form returned by session file responses.

```typescript
// Delete a specific file from a session
const response = await client.sessions.files.delete(sessionId, "path/to/file");

// Delete all files in a session
const archiveResponse = await client.sessions.files.deleteAll(session.id);
```

```python
import requests

session_id = "YOUR_SESSION_ID"
api_key = "YOUR_API_KEY_HERE"

# Delete a specific file
del_resp = requests.delete(
    f"https://api.steel.dev/v1/sessions/{session_id}/files/path/to/file",
    headers={"steel-api-key": api_key}
)
print(del_resp.status_code)

# Delete all files in a session
del_all_resp = requests.delete(
    f"https://api.steel.dev/v1/sessions/{session_id}/files",
    headers={"steel-api-key": api_key}
)
print(del_all_resp.status_code)
```

### Global Files API

#### Upload File to Global Storage

```typescript
const file = fs.createReadStream("./dataset.csv");
const globalFile = await client.files.upload({
    file,
   // path: "dataset.csv" // optional
});
console.log(globalFile.path); // dataset.csv

// Using the file from Global Files API in a session
const session = await client.sessions.create();
const uploadedFile = await client.sessions.files.upload(session.id, {
  file: globalFile.path
});
```

```python
import requests

api_key = "YOUR_API_KEY_HERE"
file_path = "./dataset.csv"

with open(file_path, "rb") as f:
    response = requests.post(
        "https://api.steel.dev/v1/files",
        headers={"steel-api-key": api_key},
        files={"file": f}
    )
print(response.json())
```

#### List All Files

```typescript
const files = await client.files.list();
files.data.forEach((file) => {
  console.log(`${file.path} | Size: ${file.size} | Last Modified: ${file.lastModified}`);
});
```

```python
import requests

api_key = "YOUR_API_KEY_HERE"

response = requests.get(
    "https://api.steel.dev/v1/files",
    headers={"steel-api-key": api_key}
)
for file in response.json()["data"]:
    print(f"{file['path']} | Size: {file['size']} | Last Modified: {file['lastModified']}")
```

#### Download Global File

For raw HTTP requests, pass a relative `{path}` value here as well.

```typescript
const response = await client.files.download(file.path); // dataset.csv
const fileBlob = await response.blob();
```

```python
import requests

api_key = "YOUR_API_KEY_HERE"
file_path = "dataset.csv"

response = requests.get(
    f"https://api.steel.dev/v1/files/{file_path}",
    headers={"steel-api-key": api_key}
)
with open(file_path, "wb") as f:
    f.write(response.content)
```

#### Delete Global File

The raw HTTP delete endpoint expects the same relative `{path}` format used by the download endpoint.

```typescript
await client.files.delete(file.path);
```

```python
import requests

api_key = "YOUR_API_KEY_HERE"
file_path = "dataset.csv"

response = requests.delete(
    f"https://api.steel.dev/v1/files/{file_path}",
    headers={"steel-api-key": api_key}
)
print(response.status_code)
```

### Usage in Context

#### Set File Input Values

Reference uploaded files in file input elements using CDP (Chrome DevTools Protocol).

```typescript
// Create CDP session for advanced controls
const cdpSession = await currentContext.newCDPSession(page);
const document = await cdpSession.send("DOM.getDocument");

// Find the input element
const inputNode = await cdpSession.send("DOM.querySelector", {
  nodeId: document.root.nodeId,
  selector: "#file-input"
});

// Set the uploaded file as input
await cdpSession.send("DOM.setFileInputFiles", {
  files: [uploadedSessionFile.path],
  nodeId: inputNode.nodeId,
});

```

#### Standard Playwright/Puppeteer Upload

```typescript
// For simple/smaller file uploads,
// using standard automation library methods will look at local files
await page.setInputFiles("#file-input", [uploadedSessionFile.path]);
```

#### Browser-Use Example

Browser-use needs some setup before it can be used. This includes setting up the browser profile with the correct downloads path and adding in a step hook to extract downloaded files to your local machine if necessary.

```python
# Before agent main loop...

# Hook to extract downloaded files to local machine if necessary
async def step_hook_start(agent):
    if os.environ.get("BROWSER_PROVIDER") == "steel":
        await agent._check_and_update_downloads()
        if agent.available_file_paths and len(agent.available_file_paths) > 0:
            has_new_files = False
            for file_path in agent.available_file_paths:
                if file_path not in downloaded_files:
                    downloaded_files.append(file_path)
                    has_new_files = True
            if has_new_files:
                try:
                    extracted_files = await browser_service.extract_downloaded_files(DOWNLOAD_PATH)
                    logger.info(f"Extracted files: {extracted_files}")
                except Exception as e:
                    logger.error(f"Failed to extract downloaded files: {e}")

async def main():
    try:
        browser_session = Browser(cdp_url=cdp_url, downloads_path="/files")
        await browser_session.connect()
        await browser_session.cdp_client.send.Target.createBrowserContext()
        browser_context_ids_return = await browser_session.cdp_client.send.Target.getBrowserContexts()
        browser_context_ids = browser_context_ids_return['browserContextIds']
        browser_context_id = browser_context_ids[0]
        await browser_session.cdp_client.send.Browser.setDownloadBehavior(params={"behavior": "allow", "downloadPath": "/files", "eventsEnabled": True, "browserContextId": browser_context_id})
        agent = Agent(task=TASK, llm=model, browser_session=browser_session)
        agent.browser_session.browser_profile.downloads_path = LOCAL_DOWNLOAD_PATH
        agent_results = await agent.run(
            on_step_start=step_hook_start,
            max_steps=5
        )
    except Exception as e:
        print(f"Error: {e}")
    finally:
        # Clean up resources
        if session:
            client.sessions.release(session.id)
            print("Session released")
        print("Done!")
# Rest of code...
```

#### Complete Example

End-to-end workflow demonstrating global file management and session file operations.

```typescript
import dotenv from "dotenv";
import fs from "fs";
import { chromium } from "playwright";
import Steel from "steel-sdk";

dotenv.config();

const client = new Steel({
  steelAPIKey: process.env.STEEL_API_KEY,
});

async function main() {
  let session;
  let browser;

  try {
    // Upload dataset to global storage for reuse
    const datasetFile = new File(
      [fs.readFileSync("./data/stock-data.csv")],
      "stock-data.csv",
      { type: "text/csv" }
    );

    const globalFile = await client.files.upload({ file: datasetFile });
    console.log(`Dataset uploaded to global storage: ${globalFile.path}`);

    // Create session and mount global file
    session = await client.sessions.create();
    console.log(`Session created: ${session.sessionViewerUrl}`);

    const sessionFile = await client.sessions.files.upload(session.id, {
      file: globalFile.path
    });

    // Connect browser and use the file
    browser = await chromium.connectOverCDP(
      `wss://connect.steel.dev?apiKey=${process.env.STEEL_API_KEY}&sessionId=${session.id}`
    );

    const currentContext = browser.contexts()[0];
    const page = currentContext.pages()[0];

    // Navigate to data visualization tool
    await page.goto('https://www.csvplot.com/');

    // Upload file to web application using CDP
    const cdpSession = await currentContext.newCDPSession(page);
    const document = await cdpSession.send("DOM.getDocument");
    const inputNode = await cdpSession.send("DOM.querySelector", {
      nodeId: document.root.nodeId,
      selector: "#load-file",
    });

    await cdpSession.send("DOM.setFileInputFiles", {
      files: [sessionFile.path],
      nodeId: inputNode.nodeId,
    });

    // Wait for visualization and capture
    await page.waitForSelector("svg.main-svg");

    // Download all session files (original upload + any generated files)
    const archiveResponse = await client.sessions.files.downloadArchive(session.id);
    const zipBlob = await archiveResponse.blob();

    // Files are automatically available in global storage after session ends

  } catch (error) {
    console.error("Error:", error);
  } finally {
    if (browser) await browser.close();
    if (session) await client.sessions.release(session.id);

    // List all available files in global storage
    const allFiles = await client.files.list();
    console.log(`Total files in storage: ${allFiles.data.length}`);
  }
}

main();
```

### Need help building with the Files API?
Reach out to us on the **#help** channel on [Discord](https://discord.gg/steel-dev) under the ⭐ community section.

### FAQ

### How do I upload a file into a website's file input from a Steel session?

Upload the file to the session first, then either use CDP's `DOM.setFileInputFiles` with the session file path, or for simpler cases use standard automation methods like Playwright's `page.setInputFiles` with the session file path.

### Can I download all files from a session at once?

Yes. Use `client.sessions.files.downloadArchive(sessionId)` in the SDK, or hit the `files.zip` endpoint via raw HTTP, to download every file in the session as a single zip archive.
