# Shipbetter > Shipbetter (https://shipbetter.net) turns single-file artifacts from the Claude app > (React JSX/TSX, HTML, SVG, Markdown, Mermaid) into live full-stack websites on > subdomains of shipbetter.net — with user accounts, a per-site SQLite database, > metered AI features, HTTPS, and phone-installable PWAs. Built for personal apps, > family tools, hobby projects, and prototypes. Plans: $19/month (1 site), > $39/month (10 sites, custom domains, 8x AI allowance), plus Enterprise by contacting > support. 7-day free trial on monthly plans. > Pro sites can charge subscriptions through the site owner's own Stripe account > (Stripe-hosted checkout; Shipbetter never touches card data). Sites cannot send > email; not intended for production businesses. This file is for AI agents. Human docs: https://shipbetter.net/docs Building an artifact for Shipbetter right now? Fetch https://shipbetter.net/skill.md — the authoring rules (SDK, accounts by default, mobile/iOS constraints, allowed imports) that make deploys instant. ## Deploying an artifact Four ways to deploy. Every deploy fully replaces the previous version of the site's frontend; the site's database and uploaded images always persist across deploys. 1. **MCP connector (preferred for agents)** — see "MCP connector" below. 2. **Dashboard upload** — https://shipbetter.net → site page → upload a .jsx/.tsx/.js/.html/.svg/.md file, or a .zip bundling code plus images. 3. **Email** — send to deploy@shipbetter.net FROM the account's email address, with subject "deploy " and the artifact attached (or pasted in the body, optionally inside a fenced code block). The sender receives a receipt email with a live-progress link. 4. **Improve with AI** — for changing an already-deployed site (below). Accepted source: max 400 KB, single file. Zips: max 200 entries / 20 MB uncompressed; images inside (png/jpeg/gif/webp/svg/ico, ≤5 MB each) become hosted site assets. Deploys containing API keys or secrets are blocked by a scanner. TypeScript is fine (types are stripped). localStorage persistence is rewritten to the real database. Artifacts calling window.claude.complete or the Anthropic API are rewired to the site's own metered AI endpoint automatically. Optional "with accounts" flag: adds sign-up/log-in to the site and scopes each visitor's data privately to them. Conversion takes roughly 1–3 minutes (an AI pass wires local state to the backend, then the site builds). A failed build gets one automatic AI repair attempt. The owner receives an email when the deploy finishes, success or failure. ## MCP connector (deploy from inside Claude) Endpoint: POST https://shipbetter.net/mcp (MCP Streamable HTTP, JSON responses). Auth: per-user token — either `Authorization: Bearer ` or `?token=`. Users generate the token on their dashboard ("Deploy from inside Claude" card), which shows a ready-to-paste connector URL: https://shipbetter.net/mcp?token=sbc_… In the Claude app: Settings → Connectors → Add custom connector → paste that URL. Tools exposed: - `deploy_artifact(subdomain, source, name?, with_accounts?, with_billing?, plans?)` — create/redeploy a site from complete artifact source. Returns live URL + progress link. `with_billing` (Pro plan and up) adds Stripe subscriptions behind a single-tier subscriber gate; `plans` declares 1–4 plans (`{key, label?, amount_cents, currency?, interval: "month"|"year", trial_days?}`), auto-created in the owner's Stripe on deploy. - `edit_site(subdomain, instruction, with_billing?, plans?)` — plain-language edit of the currently deployed site (e.g. "add a dark mode toggle"). Existing data is preserved. - `list_sites()` — the account's sites with status, URLs, and billing state (none | awaiting_keys | active). - `site_status(subdomain)` — latest deployment status, error message if failed, and billing state (awaiting_keys = subscribe buttons show "not configured" until the owner connects Stripe keys). - `schedule_list(subdomain)` / `schedule_create(subdomain, name, preset, timezone, collection, document)` / `schedule_update(subdomain, schedule_id, …)` / `schedule_pause` / `schedule_resume` / `schedule_run_now` / `schedule_runs(subdomain, schedule_id)` — manage the site's scheduled automations (see "Scheduled automations" below). All plan limits, secret scanning, and suspension rules apply through the connector. ## Improve with AI (editing a live site) Owners describe a change in plain language; Shipbetter's AI edits the currently deployed source directly — no need to re-generate the artifact. Available on the site page ("Improve with AI") and via the MCP `edit_site` tool. Instructions up to 2,000 characters. Data safety: conversions and edits receive a live-data contract (the site's real collection names, field keys, row counts) and must keep them working, so saved records survive every update. ## The backend every site gets Each deployed site serves its own API (same origin as the site): - Auth: POST /api/auth/signup {email, password}, POST /api/auth/login, POST /api/auth/logout, GET /api/auth/me. Cookie sessions, 30-day expiry. - Data: GET/POST /api/collections/:name (list newest-first limit 200 / create), GET/PATCH/DELETE /api/collections/:name/:id. `?mine=1` filters to the signed-in visitor. Documents are arbitrary JSON; docs with an owner are writable only by that owner. - AI: POST /api/ai/complete {prompt (≤8000 chars), system?, jsonSchema?} → {text, remainingToday}; a valid bounded jsonSchema also returns parsed, schema-validated {data}. Invalid/unsupported schemas fail with 400 before metering; invalid provider structured output fails with 502. SDK: ai.complete(prompt, {jsonSchema}) returns that parsed value; without a schema it remains string-returning. Always catch errors and keep non-AI features usable. Metered per site per day/month by the owner's plan (Standard 25/day, 300/month; Pro 200/day, 3000/month). 503 when disabled; 429 with a friendly message at limit. - Uploaded images serve at /assets/. - Visitor photo uploads: POST /api/uploads (raw image body, content-type image/png|jpeg|gif|webp, ≤5 MB, ?name= hint) → 201 {url, filename}; files serve at /uploads/. SDK: uploads.create(file) / uploads.remove(filename). Quotas: 500 files / 200 MB per site; anonymous visitors 40/day. Uploads are included in the site's backup zip. - Web Push: import `push` from `@/lib/sdk`. `push.subscribe()` asks permission, registers the service worker, and associates the device with the logged-in visitor; `push.unsubscribe()` removes it. Call subscribe only from an explicit user action, never on page load, and catch/display errors. iPhone/iPad requires the site installed to the Home Screen. `push.sendTest()` sends a fixed server-controlled test message only to the logged-in visitor's subscribed devices (no custom recipient/content; once per 30 seconds). Owners can still send custom notifications from the Shipbetter site dashboard; artifacts never access VAPID keys. - Realtime: WebSocket at /api/realtime (JSON protocol: subscribe/unsubscribe/publish; server pushes {type:"collection",...} change events and {type:"message",channel,data}). The SDK's useCollection is live automatically — collection changes sync to all connected visitors; realtime.publish/subscribe for custom channels; kv.get/set/del for ephemeral shared memory (TTL, in-process, gone on restart). Never poll. - Subscriptions (Pro plan and up, BYOK — the owner's own Stripe keys): POST /api/billing/checkout {plan} → {url} (redirect to Stripe-hosted Checkout), GET /api/billing/status → {active, plan, trialDaysLeft, cancelAtPeriodEnd} (+ degraded:true when Stripe is unreachable with no cache), POST /api/billing/portal → {url} (Stripe's customer portal). SDK: billing.subscribe(plan) / billing.portal() / useSubscription() hook. Single-tier gate: `active` is the whole model (trials count); requires login; 503 until the owner connects Stripe keys — render that as a friendly "not configured yet" state. Never card forms or stripe-js — Stripe hosts all card entry. No owner subscriber dashboard is provided — build an owner-gated members page into the site. Owner setup guide: https://shipbetter.net/docs/connect-stripe - Browser errors visitors hit are captured (POST /api/errors, automatic) and shown to the owner on the dashboard with a one-click "Fix with AI" that repairs and redeploys. - Optional site-wide visitor password (HTTP Basic) when the owner sets one. ## Scheduled automations (rolling out) A schedule inserts ONE document into a collection of the site's own database on a fixed rhythm or once at an exact future time. That's the whole model — the app reacts to the new document like any other data (useCollection is live, so it appears everywhere instantly). - Rhythms: hourly (on the hour), daily, weekdays, weekly (Mondays); daily variants run at 9:00 in the schedule's IANA timezone. - One-shot: `schedule_create` accepts `run_at` instead of `preset`/`timezone`, as an exact UTC RFC3339 timestamp ending in `Z` (for example `2026-07-12T18:30:00Z`). It must be in the future and within one year. It materializes once, never plans another occurrence, and becomes completed/inactive after the terminal run. `run_at` may be edited only before a run is queued; pause cancels execution and a missed stale run is recorded rather than run late. - Optional notification: provide fixed `{title, body, path}` (100/300/1024 limits; `path` must be same-origin and start with `/`). It is sent only after the document insert succeeds, to all opted-in authenticated users of that site. Delivery uses a durable at-most-once attempt marker: no automatic notification retry, so a crash may leave `attempting` but cannot duplicate the push. Run history reports delivered, failed, and expired counts; push failure does not change a successful document run. - Scheduled owner email alerts are a controlled beta, not broad availability. On an explicitly approved canary site, add `email: true` to that fixed notification to attempt one Shipbetter-branded email only to the subscribed site owner's explicitly approved Shipbetter account address after insertion succeeds. Shipbetter allowlists both the exact site and exact normalized recipient; the site cannot choose recipients, sender, HTML, or an external link. Email attempts are durable, never retried automatically, limited to 10/site/day and 100/site/month, and recorded in run history. Outbound bounce/complaint suppression is not yet complete, so do not use this for site users. - DST: a local time skipped by a DST transition is skipped; a repeated one runs once. Occurrences missed while the platform is down are recorded as `missed`, never executed late — no backfill. - Deliberately bounded: schedules run NO custom code, NO shell/packages, NO external URLs or webhooks, and NO AI calls. The only action is `collection.create` with a fixed JSON document (≤16 KB). Every run is authenticated by a short-lived signed capability bound to the site, run, action, and exact payload, with replay protection and idempotent execution. - Execution: one run at a time per site, 12-second deadline, at most 2 retries (transient failures only), immutable run history, 5 consecutive failures auto-pause the schedule and email the owner. Manual "run now" obeys the same rules. - Plan limits: Standard 3 active schedules/site (hourly minimum), Pro 10/site. History: 14 days / 100 runs (Standard), 30 days / 500 runs (Pro). Limits are starting values subject to load testing. - Status: schedules can be created and managed now (dashboard → site → Schedules, or the schedule_* connector tools); automatic execution is rolling out gradually behind a platform flag. Design pattern for artifacts: render a collection (e.g. "checklists") with useCollection and let a daily schedule create the day's document — no polling, no client-side timers needed. ## Install as a phone app (PWA) Every deployed site ships a web app manifest (standalone display, the site's name and the owner's chosen icon). Visitors: on iPhone, Share → Add to Home Screen; on Android, browser menu → Add to Home Screen / Install. The site opens full-screen like a native app. Owners set the name, description, and icon under the site's Settings (icon must first be uploaded in the Images section). Identity changes apply to the live site immediately, no redeploy. ## Remix and templates Owners can enable "Let visitors remix this app" — the live site shows a small "Remix this app" mark; any visitor can claim their own copy at https://shipbetter.net/remix/ (fresh empty database, their subdomain, live in seconds; the original's data is never shared). A public gallery of live, remixable example apps is at https://shipbetter.net/templates — deploying a template is the fastest way to start without an artifact. ## Site management - **Data browser**: dashboard → site → Data. Visitor sign-ups and every collection; row deletion; CSV export per collection. - **Stats**: 30-day daily visit chart and top pages. No cookies, no visitor tracking. - **Backup**: one click downloads a zip of the site's SQLite database + images. - **Rollback**: restore any previous finished deployment. - **Custom domains (Pro)**: point a CNAME (or A record for an apex) at shipbetter.net / 167.233.129.219, unproxied; HTTPS is automatic on first visit. - **Visitor password**: optional shared password gating the whole site. ## Plans and honest limits - $19/month: 1 site. $39/month: 10 sites, custom domains, 8x AI allowance, and monetization (charge subscriptions on your sites via your own Stripe account). Enterprise: contact support for a tailored plan. Both monthly plans include everything else. 7-day free trial, cancel anytime via Stripe billing portal. - Site payments are subscriptions only, processed by the site owner's own Stripe account (Shipbetter never touches card data). Sites cannot send email. Traffic suitability: personal scale (thousands of visits/day), not launch-day spikes. Data is the owner's: full backup anytime; deleted 30 days after cancellation. - Abuse reports: https://shipbetter.net/report. Terms: https://shipbetter.net/terms