# How to Set Up a Custom Report Storage Server for HTML Exports in UI-TARS

> Learn how to set up a custom Report Storage Server for UI-TARS HTML exports. Implement a POST endpoint to store reports and activate automated uploads via Report Settings.

- Repository: [Bytedance Inc./UI-TARS-desktop](https://github.com/bytedance/UI-TARS-desktop)
- Tags: how-to-guide
- Published: 2026-05-10

---

**To configure a custom Report Storage Server in UI-TARS, implement a `POST` endpoint that accepts `multipart/form-data` with a `file` field, store the HTML report, and return a JSON object containing a public `url`; then set the Report Storage Base URL in the application's Report Settings to activate the automated upload flow.**

The **UI-TARS Desktop** application (from the `bytedance/UI-TARS-desktop` repository) supports automatic uploading of interaction reports generated via the **Export as HTML** feature. By configuring a custom storage server, you can replace the local download behavior with a seamless cloud upload that copies the resulting public URL directly to your clipboard.

## How HTML Export Works in UI-TARS

When a user initiates an HTML export, the application generates a complete interaction report as an HTML file. Instead of triggering a local download, UI-TARS can transmit this file to a remote endpoint if the **Report Storage Base URL** is configured. This process leverages the **UTIO** (UI-TARS I/O) event system, specifically the `shareReport` handler implemented in the main process.

In [`apps/ui-tars/src/main/services/utio.ts`](https://github.com/bytedance/UI-TARS-desktop/blob/main/apps/ui-tars/src/main/services/utio.ts), the `shareReport` function packages the report data and constructs an HTTP request. It reads the user-defined base URL from the application settings and appends the configured endpoint path before dispatching a `POST` request with the file attached.

## Server API Requirements

Your custom server must expose a specific HTTP interface to handle the upload correctly. The contract is strictly defined in the application's documentation and enforced by the `shareReport` implementation.

### Endpoint Specification

The server must accept `POST` requests at the path you designate (commonly `/upload` or `/reports`). UI-TARS prepends your configured **Report Storage Base URL** to this path. There is no built-in authentication mechanism currently enforced by the client, though you may implement your own header validation if needed.

### Request Format

The request arrives as `multipart/form-data` containing a single file field named `file`. The uploaded content is the HTML report itself, typically with a size limit of approximately 30 MB. The server must parse this format to extract the binary stream.

### Expected Response

Upon successful storage, the server must reply with HTTP status `200 OK` and a JSON payload structured as follows:

```json
{
  "url": "https://your-domain.com/reports/report-123.html"
}

```

The `url` value must be a publicly reachable string that UI-TARS will copy to the clipboard. Any non-2xx response triggers an error toast in the application.

## Implementation Example: Node.js/Express

Below is a minimal implementation using Express and Multer that satisfies the API contract. This example stores files locally and serves them statically, mirroring the logic found in the official documentation.

```javascript
const express = require('express');
const multer = require('multer');
const path = require('path');
const fs = require('fs');
const cors = require('cors');

const app = express();
app.use(cors());

const upload = multer({ 
  dest: 'uploads/', 
  limits: { fileSize: 30 * 1024 * 1024 } 
});

app.use('/public', express.static(path.join(__dirname, 'uploads')));

app.post('/your-storage-endpoint', upload.single('file'), (req, res) => {
  if (!req.file) {
    return res.status(400).json({ error: 'Missing file field' });
  }

  const ext = path.extname(req.file.originalname) || '.html';
  const newName = `${req.file.filename}${ext}`;
  const newPath = path.join('uploads', newName);
  fs.renameSync(req.file.path, newPath);

  const publicUrl = `${req.protocol}://${req.get('host')}/public/${newName}`;
  res.json({ url: publicUrl });
});

app.listen(3000, () => console.log('Report storage server listening on port 3000'));

```

This implementation handles the `file` field extraction, preserves the `.html` extension, and returns the publicly accessible URL. A comparable **Python/Flask** implementation is also available in the official [`docs/setting.md`](https://github.com/bytedance/UI-TARS-desktop/blob/main/docs/setting.md) for teams preferring Python-based infrastructure.

## Configuring UI-TARS to Use Your Custom Server

To activate the custom storage integration, you must populate the **Report Storage Base URL** field in the application settings.

1. Navigate to **Settings** → **Report Settings**.

2. Locate the **Report Storage Base URL** input field.

3. Enter the root URL of your server (e.g., `http://localhost:3000` or `https://api.example.com`).

4. Save the configuration.

Once configured, clicking **Export as HTML** triggers the following sequence:

- The renderer process emits a `ShareReportEvent` (defined in [`packages/ui-tars/utio/src/types.ts`](https://github.com/bytedance/UI-TARS-desktop/blob/main/packages/ui-tars/utio/src/types.ts)) to the main process.
- The main process executes `shareReport` in [`apps/ui-tars/src/main/services/utio.ts`](https://github.com/bytedance/UI-TARS-desktop/blob/main/apps/ui-tars/src/main/services/utio.ts), reading the base URL from the store.
- The application sends a `POST` request with the HTML file attached.
- On success, UI-TARS displays a confirmation toast and copies the returned `url` to the system clipboard.

If the **Report Storage Base URL** field remains empty, the application falls back to the default behavior of downloading the HTML file locally.

## Source Code References

The custom storage feature is implemented across the following locations in the `bytedance/UI-TARS-desktop` repository:

- **[`apps/ui-tars/src/main/services/utio.ts`](https://github.com/bytedance/UI-TARS-desktop/blob/main/apps/ui-tars/src/main/services/utio.ts)**: Contains the `shareReport` function that manages the HTTP request, response parsing, and clipboard integration.
- **[`packages/ui-tars/utio/src/types.ts`](https://github.com/bytedance/UI-TARS-desktop/blob/main/packages/ui-tars/utio/src/types.ts)**: Defines the `ShareReportEvent` interface that structures the communication between the renderer and main processes.
- **[`docs/setting.md`](https://github.com/bytedance/UI-TARS-desktop/blob/main/docs/setting.md)**: Provides user-facing documentation for the Report Storage Server interface and additional language examples.

## Summary

- **Report Storage Base URL** configuration in UI-TARS enables automatic HTML report uploading instead of local downloads.
- Your server must implement a `POST` endpoint accepting `multipart/form-data` with a `file` field and return JSON containing a public `url`.
- The `shareReport` handler in [`apps/ui-tars/src/main/services/utio.ts`](https://github.com/bytedance/UI-TARS-desktop/blob/main/apps/ui-tars/src/main/services/utio.ts) orchestrates the upload and clipboard copy upon receiving a valid response.
- Node.js/Express with Multer or Python/Flask are valid implementation choices, provided they adhere to the specified response contract.

## Frequently Asked Questions

### Does UI-TARS support authentication headers for the Report Storage Server?

Currently, the `shareReport` implementation does not inject custom headers like `Authorization` or API keys. The endpoint must be publicly reachable or protected via network-level restrictions (IP allowlisting) or reverse proxy authentication. Future versions may add configurable header support.

### What is the maximum file size for HTML reports?

The application enforces a limit of approximately **30 MB** per report. Ensure your server configuration (e.g., Multer's `limits` or Nginx's `client_max_body_size`) is set to accept payloads of this size or larger to prevent upload failures.

### Can I use a local file system path as the Report Storage Base URL?

No, the **Report Storage Base URL** must be a valid HTTP or HTTPS URL. If you wish to store reports locally, leave the base URL field empty to trigger the default local download behavior, which saves the file to your browser's default download directory.

### What happens if my storage server returns an error?

If the server responds with a non-2xx status code or the request times out, UI-TARS displays an error toast notification and aborts the clipboard operation. The HTML file is not retained locally in this scenario, so you should retry the export once the server issue is resolved.