# How to Upload Local Assets to a Stitch Project: A Complete Guide

> Learn how to upload local assets to a Stitch project using the upload-to-stitch skill. Easily send images HTML and Markdown files directly to your Stitch project.

- Repository: [Google Labs Code/stitch-skills](https://github.com/google-labs-code/stitch-skills)
- Tags: how-to-guide
- Published: 2026-07-18

---

**Use the `upload-to-stitch` skill from the Stitch Design plugin to send images, HTML, and Markdown files directly to a Stitch project via the [`upload_to_stitch.py`](https://github.com/google-labs-code/stitch-skills/blob/main/upload_to_stitch.py) script, which handles base-64 encoding and calls the BatchCreateScreens REST API endpoint.**

The **google-labs-code/stitch-skills** repository provides a robust solution to upload local assets to a Stitch project without exhausting model token limits. The Stitch Design plugin includes a reusable `upload-to-stitch` skill that encapsulates the entire workflow, from credential discovery to API communication, as documented in [`plugins/stitch-design/skills/upload-to-stitch/SKILL.md`](https://github.com/google-labs-code/stitch-skills/blob/main/plugins/stitch-design/skills/upload-to-stitch/SKILL.md).

## Architecture of the Upload Workflow

The upload process follows three distinct logical layers that isolate concerns between project management, authentication, and data transfer.

### Project Identification

First, locate the target Stitch project using any MCP-compatible `list-projects` command to retrieve the `projectId`. The skill description in [`plugins/stitch-design/skills/upload-to-stitch/SKILL.md`](https://github.com/google-labs-code/stitch-skills/blob/main/plugins/stitch-design/skills/upload-to-stitch/SKILL.md) (lines 28-31) specifies that the AI must obtain this identifier before proceeding.

### Credential Discovery

Next, extract the Stitch API key from the user’s local Gemini or Claude configuration files. Valid locations include `~/.gemini/settings.json` or [`.gemini/antigravity/mcp_config.json`](https://github.com/google-labs-code/stitch-skills/blob/main/.gemini/antigravity/mcp_config.json), as detailed in the SKILL file (lines 32-38). You may optionally specify a custom API URL if working against a non-production endpoint.

### Upload Execution

Finally, run the helper script [`plugins/stitch-design/skills/upload-to-stitch/scripts/upload_to_stitch.py`](https://github.com/google-labs-code/stitch-skills/blob/main/plugins/stitch-design/skills/upload-to-stitch/scripts/upload_to_stitch.py). This component validates file types, base-64 encodes content, constructs protobuf-compatible requests, and calls the Stitch **BatchCreateScreens** REST endpoint directly.

## Inside the upload_to_stitch.py Implementation

The core logic resides in [`plugins/stitch-design/skills/upload-to-stitch/scripts/upload_to_stitch.py`](https://github.com/google-labs-code/stitch-skills/blob/main/plugins/stitch-design/skills/upload-to-stitch/scripts/upload_to_stitch.py), where four primary functions handle the end-to-end flow.

### MIME Type Mapping and Encoding

The script defines a static `_MIME_TYPES` dictionary (lines 48-57) that maps file extensions to correct MIME types. The `encode_file()` function reads files in binary mode and returns base-64 encoded strings (lines 60-64), ensuring binary-safe transmission of image data.

### Building the Screen Request

The `build_screen_request()` function constructs a `CreateScreenRequest` protobuf-compatible dictionary, handling two distinct screen types:

- **IMAGE** screens for PNG, JPG, and WEBP files, populating the `screenshot` field with base-64 data
- **DOCUMENT** screens for HTML or Markdown, populating the `htmlCode` field and optionally adding a `generatedBy` tag for attribution

### API Communication

The `call_batch_create_screens()` function assembles a POST request to `/v1/projects/<projectId>/screens:batchCreate`. It attaches the `X-Goog-Api-Key` header for authentication and uses an SSL-aware context when `certifi` is present (lines 66-87). Errors trigger a graceful `sys.exit(1)` with printed diagnostics.

### Command-Line Interface

The `parse_args()` function defines required flags (`--project-id`, `--file-path`, `--api-key`) and optional parameters (`--api-url`, `--title`, `--generated-by`, `--create-screen-instances`). The `main()` routine orchestrates validation, encoding, request creation, and prints the formatted JSON response.

## Step-by-Step Upload Workflow

Before execution, the skill requires explicit user approval after displaying file metadata, size, and type. This "Checkpoint" step (documented in SKILL.md lines 49-53) ensures the user confirms the operation before transmitting data.

### Required Parameters

- `--project-id`: The target Stitch project identifier
- `--file-path`: Absolute or relative path to the local asset
- `--api-key`: Your Stitch API authentication key

### Optional Configuration Flags

- `--api-url`: Override the default Stitch API endpoint
- `--title`: Assign a human-readable title to the created screen
- `--generated-by`: Tag document screens with generation metadata
- `--create-screen-instances`: Enable additional instance creation logic

Execute the upload from your terminal:

```bash
python3 plugins/stitch-design/skills/upload-to-stitch/scripts/upload_to_stitch.py \
  --project-id 1234567890 \
  --file-path ./designs/homepage.html \
  --api-key AIzaSy... \
  --title "Homepage Mockup" \
  --generated-by "stitch::extract-static-html"

```

## Programmatic Integration

You can invoke the script from Python using the `subprocess` module for automated pipelines:

```python
from pathlib import Path
import subprocess, shlex

project_id = "1234567890"
api_key    = "AIzaSy...."
file_path  = Path("assets/logo.png")

cmd = f"""python3 upload_to_stitch.py \\
  --project-id {project_id} \\
  --file-path {file_path} \\
  --api-key {api_key} \\
  --title "Brand Logo"
"""
subprocess.run(shlex.split(cmd), check=True)

```

## Resolving SSL Certificate Errors on macOS

If you encounter `ssl.SSLCertVerificationError`, the script automatically falls back to the `certifi` bundle when available (lines 40-45). You can also manually configure the `SSL_CERT_FILE` environment variable before invocation, as documented in SKILL.md (lines 67-80).

## Summary

- The `upload-to-stitch` skill provides a token-efficient method to upload local assets to a Stitch project using direct API calls.
- The workflow requires a valid `projectId`, Stitch API key, and supported file path to execute successfully.
- Supported formats include PNG, JPG, WEBP, HTML, and Markdown, automatically mapped to **IMAGE** or **DOCUMENT** screen types.
- The [`upload_to_stitch.py`](https://github.com/google-labs-code/stitch-skills/blob/main/upload_to_stitch.py) script handles base-64 encoding, `CreateScreenRequest` construction, and REST API communication via the BatchCreateScreens endpoint.
- Always verify the response contains a `screenId` under `responses[0].screen.id` to confirm successful upload.

## Frequently Asked Questions

### What file types can I upload to a Stitch project?

The system supports **IMAGE** types (PNG, JPG, WEBP) and **DOCUMENT** types (HTML, Markdown). Images populate the `screenshot` field with base-64 encoded binary data, while documents populate the `htmlCode` field with text content, optionally carrying a `generatedBy` attribution tag.

### Where do I find my Stitch API key?

Check your local Gemini or Claude configuration files, typically located at `~/.gemini/settings.json` or paths like [`.gemini/antigravity/mcp_config.json`](https://github.com/google-labs-code/stitch-skills/blob/main/.gemini/antigravity/mcp_config.json). The skill documentation in [`plugins/stitch-design/skills/upload-to-stitch/SKILL.md`](https://github.com/google-labs-code/stitch-skills/blob/main/plugins/stitch-design/skills/upload-to-stitch/SKILL.md) (lines 32-38) provides specific guidance on locating these credentials.

### Can I upload multiple files in a single command?

The current implementation processes one file per invocation. For batch uploads, wrap the script execution in a shell loop or Python iteration that calls the command multiple times with different `--file-path` arguments and appropriate titles.

### How do I verify that my upload succeeded?

Check the JSON response printed by the script. A successful upload returns a `screenId` nested under `responses[0].screen.id`. If the script exits with code 1 or prints an error message, the upload failed; inspect the error details to determine whether the issue relates to authentication, file validation, or network connectivity.