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

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, 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:

{
  "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.

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 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 SettingsReport 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) to the main process.
  • The main process executes shareReport in 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:

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 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →