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

> Learn how to upload local assets to a Stitch project using the Stitch Design plugin and BatchCreateScreens API. Easily send images and files to Stitch via base-64 encoding and direct REST calls.

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

---

**The Stitch Design plugin provides a reusable `upload-to-stitch` skill that sends local images, HTML, and Markdown files directly to a Stitch project via the BatchCreateScreens API, bypassing model token limits through base-64 encoding and direct REST calls.**

The `google-labs-code/stitch-skills` repository delivers a token‑efficient workflow for uploading local design assets to Stitch projects. Instead of passing file contents through the LLM context window, the `upload-to-stitch` skill validates, encodes, and transmits assets directly to the Stitch backend, making screenshots, HTML prototypes, and Markdown documentation immediately available for downstream processing.

## The Three-Layer Upload Architecture

The upload process follows a logical three‑layer pattern defined 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‑38).

### Project Identification

First, locate the target Stitch project by running any MCP‑compatible list‑projects command and extracting the `projectId`. The skill assumes you have already provisioned a project within the Stitch ecosystem.

### Credential Discovery

Next, retrieve the Stitch API key from local Gemini or Claude configuration files. The skill searches standard locations such as `~/.gemini/settings.json` or [`.gemini/antigravity/mcp_config.json`](https://github.com/google-labs-code/stitch-skills/blob/main/.gemini/antigravity/mcp_config.json) (lines 32‑38 in SKILL.md). You may also pass the key explicitly via the `--api-key` flag.

### Upload Execution

Finally, invoke 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 script orchestrates file validation, base‑64 encoding, and the HTTP POST to Stitch’s BatchCreateScreens endpoint.

## How the Upload Script Works

The core implementation in [`upload_to_stitch.py`](https://github.com/google-labs-code/stitch-skills/blob/main/upload_to_stitch.py) handles five distinct responsibilities:

### MIME-Type Validation

A static `_MIME_TYPES` dictionary (lines 48‑57) maps file extensions to their correct MIME types. Supported formats include PNG, JPG, WEBP, HTML, and Markdown.

### Base-64 Encoding

The `encode_file()` function (lines 60‑64) reads the asset in binary mode and returns a base‑64 encoded string suitable for JSON transmission.

### Screen Request Construction

The `build_screen_request()` function (lines 29‑77) constructs the `CreateScreenRequest` payload. It distinguishes between two screen types:
- **IMAGE** screens use the `screenshot` field for PNG/JPG/WEBP assets.
- **DOCUMENT** screens use the `htmlCode` field for HTML or Markdown content, optionally appending a `generatedBy` tag.

### HTTP API Call

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

### Command-Line Interface

The `parse_args()` function (lines 81‑67) defines required flags (`--project-id`, `--file-path`, `--api-key`) and optional parameters (`--api-url`, `--title`, `--generated-by`, `--create-screen-instances`). The `main()` routine validates inputs, executes the encoding, and prints the formatted JSON response.

## Step-by-Step Workflow

Follow this sequence to upload assets from your local machine:

1. **Find the project** – Run `stitch list_projects` and copy the `projectId`.
2. **Locate your API key** – Inspect `~/.gemini/settings.json` or similar configuration files, or request the key from the user.
3. **Confirm assets** – The skill pauses before execution to display the file path, size, and type. You must obtain explicit user approval (see the "Checkpoint" note in SKILL.md, lines 49‑53).
4. **Run the upload** – Execute the command block, which expands to:
   ```bash
   python3 <SKILL_DIR>/scripts/upload_to_stitch.py \
     --project-id <PROJECT_ID> \
     --file-path <PATH_TO_ASSET> \
     --api-key <API_KEY> \
     [--api-url <STITCH_API_URL>] \
     [--title <SCREEN_TITLE>] \
     [--generated-by <GENERATED_BY>]
   ```

5. **Verify the response** – A successful upload returns a JSON object containing `screenId` under `responses[0].screen.id`.

## SSL Troubleshooting on macOS

If you encounter `ssl.SSLCertVerificationError`, the script automatically falls back to the `certifi` bundle (lines 40‑45). You may also manually set the `SSL_CERT_FILE` environment variable as documented in SKILL.md (lines 67‑80).

## Code Examples

Use the script programmatically from Python:

```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)

```

Or invoke directly from the terminal:

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

```

## Summary

- The **upload-to-stitch** skill bypasses LLM token limits by uploading assets directly to the Stitch API.
- The process requires three inputs: a valid `projectId`, a Stitch API key, and the local file path.
- The script [`upload_to_stitch.py`](https://github.com/google-labs-code/stitch-skills/blob/main/upload_to_stitch.py) handles MIME detection, base‑64 encoding, and the `BatchCreateScreens` REST call.
- Supported formats include **IMAGE** screens (PNG, JPG, WEBP) and **DOCUMENT** screens (HTML, Markdown).
- Execution requires user confirmation before transmission, with full JSON response logging for verification.

## Frequently Asked Questions

### What file types are supported when uploading local assets to a Stitch project?

The [`upload_to_stitch.py`](https://github.com/google-labs-code/stitch-skills/blob/main/upload_to_stitch.py) script accepts PNG, JPG, and WEBP files as **IMAGE** screens, and HTML or Markdown files as **DOCUMENT** screens. The `_MIME_TYPES` dictionary (lines 48‑57) maps extensions to MIME types, ensuring the correct protobuf structure is sent to the Stitch API.

### How do I find my Stitch API key for the upload script?

According to the skill documentation in [`SKILL.md`](https://github.com/google-labs-code/stitch-skills/blob/main/SKILL.md) (lines 32‑38), the API key is typically stored in local configuration files such as `~/.gemini/settings.json` or [`.gemini/antigravity/mcp_config.json`](https://github.com/google-labs-code/stitch-skills/blob/main/.gemini/antigravity/mcp_config.json). You may also provide it directly via the `--api-key` command-line argument.

### What is the difference between IMAGE and DOCUMENT screens in Stitch?

**IMAGE** screens store base‑64 encoded image data in the `screenshot` field, suitable for design mockups and screenshots. **DOCUMENT** screens store text content in the `htmlCode` field, used for HTML prototypes or Markdown documentation, and can include a `generatedBy` metadata tag to track the source of the asset.

### How do I handle SSL certificate errors when uploading to Stitch?

If you encounter `ssl.SSLCertVerificationError` on macOS, the script automatically attempts to use the `certifi` certificate bundle (lines 40‑45). Alternatively, set the `SSL_CERT_FILE` environment variable to point to a valid PEM file before running the upload command, as noted in the skill documentation (lines 67‑80).