Python package · CLI · MCP server · API · npx

htmlship

Publish HTML from code, scripts, and coding agents. Send a page, receive a sandboxed share URL, and keep an owner key for updates or deletion.

NEW! Ship whole apps, not just pages. deploy builds your frontend locally and pushes it live in one command — a single-page app on its own sandboxed URL, or a full multi-file site (Next.js, Astro, and more) served at view.htmlship.com/{slug}/.

$ htmlship publish report.html
https://view.htmlship.com/f9a2k7m4
owner_key: ws_... saved locally

Try a live page

Demo pages expire in 1 hour. HTML is preserved as-is, while scripts are safely blocked in the preview.

Install and publish

The base package includes the Python client and CLI. Optional extras add clipboard, MCP, or server dependencies.

npx (no install)

npx htmlship publish report.html
npx htmlship publish report.html --password "demo-pass" --title "Demo" --expires-in 60
npx htmlship deploy ./my-app   # build + ship a compiled app
npx htmlship deploy ./my-app --password "demo-pass" --title "Demo" --expires-in 60
npx htmlship get <slug>
npx htmlship update <slug> report.html
npx htmlship delete <slug>
npx htmlship list-mine

Deploy built apps

# single-page app (Vite/CRA) -> one inlined sandboxed page
npx htmlship deploy ./my-app

# multi-file site (Next.js auto-detected) -> view.htmlship.com/{slug}/
npx htmlship deploy ./my-next-app
npx htmlship deploy --site --out dist   # force multi-file (Astro, etc.)

# add a title, password, and TTL — works for both kinds
npx htmlship deploy ./my-app --title "Demo" --password "demo-pass" --expires-in 60

# the build runs locally (never on the server). Each slug renders
# in its own isolated, opaque origin (no cookies, no cross-site
# access, no network egress) via a sandboxed CSP.

Python

pip install htmlship

import htmlship

page = htmlship.publish(
    "<h1>Hello</h1>",
    title="Demo",
    password="demo-pass",
    expires_in=60,  # minutes
)
print(page.url, page.owner_key)

htmlship.update(
    page.slug,
    "<h1>Updated</h1>",
    owner_key=page.owner_key,
)
htmlship.get(page.slug)
htmlship.delete(page.slug, owner_key=page.owner_key)

CLI (pip)

pip install htmlship

htmlship publish report.html
cat report.html | htmlship publish -
htmlship publish report.html --password "demo-pass" --title "Demo" --expires-in 60
htmlship deploy ./my-app   # build + ship a compiled app
htmlship deploy ./my-app --password "demo-pass" --title "Demo" --expires-in 60
htmlship get <slug>
htmlship update <slug> report.html
htmlship delete <slug>
htmlship list-mine

cURL

# publish (password gates view access, optional)
curl -X POST https://api.htmlship.com/api/v1/pages \
  -H "Content-Type: application/json" \
  -d '{"html":"<h1>Hello</h1>","title":"Demo","password":"demo-pass"}'

# update — only owner_key (returned at publish) can mutate
curl -X PATCH https://api.htmlship.com/api/v1/pages/<slug> \
  -H "Content-Type: application/json" \
  -H "X-Owner-Key: ws_..." \
  -d '{"html":"<h1>Updated</h1>"}'

# delete
curl -X DELETE https://api.htmlship.com/api/v1/pages/<slug> \
  -H "X-Owner-Key: ws_..."

MCP (Claude Desktop, Cursor, ...)

{
  "mcpServers": {
    "htmlship": {
      "command": "npx",
      "args": ["-y", "htmlship", "mcp"],
      "env": {
        "HTMLSHIP_API_URL": "https://api.htmlship.com"
      }
    }
  }
}

publish_html args:
{"html":"<h1>Hello</h1>","title":"Demo","password":"demo-pass"}

deploy_project args (build + ship; multi-file Next.js auto-detected):
{"dir":"./my-app","password":"demo-pass"}

update_html args (owner_key is the publisher-only secret):
{"slug":"<slug>","html":"<h1>Updated</h1>","owner_key":"ws_..."}

API essentials

Create responses include an owner_key once — it's the publisher-only secret and the sole credential for update and delete. The optional password is a viewer credential and gates GET on the view host; it is never used to mutate. Everything builds client-side — there is no server-side build endpoint. Single-file deploys are a POST /pages with sandbox_mode: "relaxed"; multi-file sites are uploaded to POST /sites (≤ 50 MB) and served per-slug.

POST/api/v1/pagescreate HTML with optional title, password (view gate), expiry, parent slug, and sandbox mode (strict, or relaxed for deployed apps)
POST/api/v1/sitesupload a multi-file static site (Next.js, etc.) as a file manifest — served at /{slug}/ with per-slug isolation
GET/api/v1/pages/{slug}read metadata only
PATCH/api/v1/pages/{slug}replace HTML or title — requires X-Owner-Key
DELETE/api/v1/pages/{slug}soft delete — requires X-Owner-Key
VIEWhttps://view.htmlship.com/{slug}strict pages block all scripts; relaxed pages (and multi-file sites at /{slug}/) run their JS in an isolated, opaque origin — both with isolated host routing and optional password gate