Overview
Deploy any React app, vanilla JS site, or static bundle to a Canvas app. Upload a .zip of your build output and Mixpeek handles hosting, CDN distribution, and versioning — no infrastructure needed.
Every deploy creates an immutable version record with a commit message, asset manifest, and content hashes. See Version History for the full version control system.
Quickstart
Build your frontend
Build your app to a static output directory.# React / Vite
npm run build
# Output: dist/
# Next.js (static export)
npm run build && npm run export
# Output: out/
Zip the output directory
The zip should contain an index.html at the root (or inside a single top-level folder). Mixpeek auto-detects the entry point. Get a presigned upload URL
curl -X POST https://api.mixpeek.com/v1/apps/$APP_ID/deploy/upload-url \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"filename": "my-app.zip", "content_type": "application/zip"}'
Response:{
"upload_url": "https://...",
"bundle_s3_key": "apps/.../my-app.zip"
}
Upload the zip
curl -X PUT "$UPLOAD_URL" \
-H "Content-Type: application/zip" \
--data-binary @my-app.zip
Trigger the deploy
A commit message is required — it describes what changed in this version.curl -X POST https://api.mixpeek.com/v1/apps/$APP_ID/deploy \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"source": "cli_upload",
"bundle_s3_key": "$BUNDLE_KEY",
"environment": "production",
"message": "Initial deploy"
}'
Optionally include source_files (a {path: content} map) for source-level version diffs. Include git_commit_sha / git_author for CI/CD traceability.
Your app is live at https://{slug}.mxp.co within seconds of a successful build.
Environments
Each app supports two independent environments with separate URLs and asset prefixes:
| Environment | URL pattern | Deploy field |
|---|
| Production | {slug}.mxp.co | "environment": "production" |
| Staging | staging-{slug}.mxp.co | "environment": "staging" |
Staging and production can serve different versions simultaneously. Deploy to staging first to test, then promote to production.
Deploying to staging
curl -X POST https://api.mixpeek.com/v1/apps/$APP_ID/deploy \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"source": "cli_upload",
"bundle_s3_key": "$BUNDLE_KEY",
"environment": "staging",
"message": "Test new search layout"
}'
Your staging build is live at https://staging-{slug}.mxp.co.
Once you’ve verified staging, promote it to production by deploying the same bundle to the production environment, or use the restore endpoint to point production at the staging version:
curl -X POST https://api.mixpeek.com/v1/apps/$APP_ID/versions/$STAGING_VERSION/restore \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"environment": "production"}'
Restore is instant — no rebuild required.
Deploy lifecycle
| Stage | Description |
|---|
queued | Bundle uploaded, deploy queued |
building | Mixpeek is validating, packaging, and uploading assets |
complete | Deploy complete — new version is live |
failed | Deploy failed — previous version stays live, error returned |
Poll deploy status:
curl https://api.mixpeek.com/v1/apps/$APP_ID/deploys/$DEPLOY_ID \
-H "Authorization: Bearer $API_KEY"
Multi-file output
Your zip can contain any number of files — HTML, JS, CSS, images, fonts. The only requirement is an index.html at the root. All files are uploaded to S3 and served with appropriate cache headers:
index.html — no-cache (always fresh)
- Content-hashed files (e.g.,
app-a1b2c3.js) — immutable, permanent cache
- Other assets — standard cache headers
Canvas SDK
Your app runs inside the Mixpeek canvas runtime. Call Mixpeek APIs through the built-in /api proxy — credentials are injected server-side, so your API key never reaches the browser:
// src/App.jsx — no auth headers needed
async function search(query) {
const res = await fetch('/api/v1/retrievers/ret_abc123/execute', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ inputs: { query }, settings: { limit: 20 } }),
})
return res.json()
}
Use /api/v1/... (relative path) instead of https://api.mixpeek.com/v1/... — the canvas proxy injects Authorization and X-Namespace headers automatically, avoiding CORS and keeping API keys out of your bundle.
Pre-deploy validation
Mixpeek runs automatic checks on every bundle before deploying:
| Check | What it catches |
|---|
| index.html exists | Missing entry point (zip structure wrong) |
| Script tags present | Blank page (no executable code) |
| Asset references valid | Broken src/href links in index.html |
No bare process.env | Runtime crash in browser (use window.__MIXPEEK__ instead) |
| Bundle size < 50 MB | Accidentally included node_modules or large assets |
| JS bundles non-empty | Failed build that produced empty files |
If any check fails, the deploy is rejected with a descriptive error message.
Deploy via Studio
In the App details page, drag & drop your .zip file onto the Deploy panel and click Deploy. The build is queued immediately and status updates in real time.
Rollback
Every deploy is versioned. You have two rollback options:
Quick rollback — restore the previous config:
curl -X POST https://api.mixpeek.com/v1/apps/$APP_ID/rollback \
-H "Authorization: Bearer $API_KEY"
Restore any version — point an environment to a specific version’s assets:
curl -X POST https://api.mixpeek.com/v1/apps/$APP_ID/versions/3/restore \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"environment": "production"}'
Restore is instant — no rebuild required. All previous assets are retained in S3.
See Version History for the full version control system including diffs, downloads, and git metadata.
Source files
When you include source_files in your deploy request, those files are stored alongside the version record. This enables:
- Source-level diffs — compare actual source code between versions, not just built output
- Download and re-deploy — download a version’s source files and deploy modified code
curl -X POST https://api.mixpeek.com/v1/apps/$APP_ID/deploy \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"source": "cli_upload",
"bundle_s3_key": "$BUNDLE_KEY",
"environment": "production",
"message": "Add dark mode",
"source_files": {
"src/App.tsx": "import React from ...",
"src/components/Header.tsx": "export function Header() ...",
"src/styles.css": "body { ... }"
}
}'