Skip to main content

Overview

Canvas is Mixpeek’s application hosting platform. Build a web app using any frontend framework — React, Vue, Svelte, vanilla JS, or plain HTML — and deploy it as a zip bundle. Mixpeek handles hosting, CDN, auth, versioning, and the entire backend. Your app is live at {slug}.mxp.co the moment you deploy. No servers to manage, no infrastructure to configure, no API keys in your frontend code.

How it works

You write frontend code. Mixpeek provides everything else:
  • Hosting — your built assets (HTML, JS, CSS, images) are stored on S3 and served via CDN with immutable caching
  • Backend proxy — all /api/* requests are forwarded to api.mixpeek.com with your org’s API key and namespace injected server-side. Your credentials never reach the browser.
  • Runtime injection — the Canvas runtime injects window.__MIXPEEK__ into your HTML at serve time with auth config, environment variables, and monitoring hooks
  • Auth — optionally enable Clerk-powered sign-in (Google, GitHub, email) with per-app user management. The auth SDK is auto-injected — no libraries to install.
  • Environments — deploy to staging (staging-{slug}.mxp.co) or production ({slug}.mxp.co) independently
  • Versioning — every deploy creates an immutable version with content hash, commit message, and source files. Rollback instantly.
  • Monitoring — error boundaries, Sentry, and PostHog are auto-injected for crash detection and usage analytics
You bring the UI, Mixpeek brings search, retrieval, ingestion, and multimodal AI.

Deploy from code

Upload any React, vanilla JS, or static site. Mixpeek serves it from S3 with CDN caching.

Custom domains

Default domain at {slug}.mxp.co. Add your own subdomain via CNAME with auto TLS.

Built-in auth

Clerk-powered sign-in (Google, GitHub, email) — auto-injected into your app with zero config.

User management

Invite members, assign roles, and control per-app access — powered by Clerk organizations.

Git-like version control

Every publish and deploy creates an immutable version with a content hash, message, and diffable snapshot.

Architecture

When a user visits {slug}.mxp.co, here’s the request lifecycle:
  1. DNS — resolves to the Canvas runtime (Cloudflare-proxied, DDoS protected)
  2. Routing — the Express server maps the hostname to your app_id (cached in Redis). Supports {slug}.mxp.co, staging-{slug}.mxp.co, and custom domains.
  3. HTMLindex.html is fetched from S3 and dynamically injected with window.__MIXPEEK__ (runtime config, auth, monitoring)
  4. Assets — JS, CSS, and images are served from S3 via CDN with immutable cache headers (content-hashed filenames → permanent caching)
  5. SPA routing — non-asset paths fall through to index.html so client-side routing (React Router, etc.) works out of the box
  6. API proxy/api/* requests are forwarded to api.mixpeek.com with Authorization and X-Namespace headers injected server-side
Your API key is never sent to the browser. The /api proxy runs server-side and injects credentials on every request. Your frontend code only calls relative paths like /api/v1/retrievers/execute.

Runtime config injection

The canvas runtime injects a window.__MIXPEEK__ object into your app’s HTML at serve time:
window.__MIXPEEK__ = {
  apiUrl: "https://api.mixpeek.com",  // Always present
  // Your custom env vars from build_config.env_vars
  MY_CUSTOM_VAR: "value",
  // Auth config (if enabled)
  auth: {
    mode: "clerk",
    publishableKey: "pk_live_...",
    orgId: "org_xyz",
    providers: ["google", "github", "email"],
  },
}
Access these values in your app code:
const apiUrl = window.__MIXPEEK__?.apiUrl
const customVar = window.__MIXPEEK__?.MY_CUSTOM_VAR
Do not use process.env in your app — it will crash in the browser. Use window.__MIXPEEK__ for runtime config or import.meta.env for Vite build-time variables.

Quickstart

1

Create an App in Studio

Go to AppsCreate App. Give it a name and a globally-unique slug — this becomes your default URL at https://{slug}.mxp.co.
2

Build your frontend

Write a React app (or any static site) that calls Mixpeek APIs via the canvas proxy. See the example below.
# Bootstrap a React app
npm create vite@latest my-search-app -- --template react
cd my-search-app
npm install
npm run build
# Zip the dist/ folder
zip -r my-search-app.zip dist/
3

Deploy the bundle

In the App details page, drag & drop your .zip onto the Deploy panel and click Deploy. Your build is queued immediately.Or via API:
# 1. 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"}'

# 2. PUT the zip to the returned upload_url
curl -X PUT "$UPLOAD_URL" \
  -H "Content-Type: application/zip" \
  --data-binary @my-app.zip

# 3. Trigger the build
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"}'
4

Visit your App

Your app is live at https://{slug}.mxp.co within seconds of a successful build. Add a custom domain to use your own URL.

Canvas SDK

The canvas runtime injects credentials server-side — your API key never reaches the browser. Call any Mixpeek API through the /api proxy:
// src/App.jsx — a minimal React search app
import { useState } from 'react'

async function search(query) {
  // No auth headers needed — the canvas proxy injects them server-side
  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()
}

export default function App() {
  const [query, setQuery] = useState('')
  const [results, setResults] = useState([])
  const [loading, setLoading] = useState(false)

  const handleSearch = async (e) => {
    e.preventDefault()
    setLoading(true)
    const data = await search(query)
    setResults(data.results ?? [])
    setLoading(false)
  }

  return (
    <div style={{ maxWidth: 800, margin: '0 auto', padding: 24 }}>
      <h1>Search</h1>
      <form onSubmit={handleSearch}>
        <input
          value={query}
          onChange={(e) => setQuery(e.target.value)}
          placeholder="Search..."
          style={{ width: '100%', padding: 8, fontSize: 16 }}
        />
        <button type="submit" disabled={loading}>
          {loading ? 'Searching...' : 'Search'}
        </button>
      </form>
      <ul>
        {results.map((r) => (
          <li key={r.document_id}>
            <strong>{r.fields?.title ?? r.document_id}</strong>
            <p>{r.fields?.description}</p>
          </li>
        ))}
      </ul>
    </div>
  )
}

What /api supports

The proxy forwards all Mixpeek API methods with your org’s credentials injected:
CategoryExample paths
Retrievers/api/v1/retrievers/{id}/execute, /api/v1/retrievers/list
Collections/api/v1/collections/list, /api/v1/collections/{id}
Documents/api/v1/documents/{id}, /api/v1/documents/list
Namespaces/api/v1/namespaces/list
Batches/api/v1/batches/list, /api/v1/batches/{id}
Tasks/api/v1/tasks/{id}, /api/v1/tasks/list
Marketplace/api/v1/marketplace/catalog/{name}/execute
Taxonomies/api/v1/taxonomies/list, /api/v1/taxonomies/{id}/classify
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.

Using the Mixpeek JS SDK

You can also use the mixpeek npm package pointed at /api:
import { Mixpeek } from 'mixpeek'

// apiKey is a placeholder — the proxy injects the real key server-side
const client = new Mixpeek({ apiKey: 'canvas', baseUrl: '/api' })

// Execute a retriever
const results = await client.request({
  method: 'POST',
  url: '/v1/retrievers/ret_abc123/execute',
  data: { inputs: { query: 'red shoes' }, settings: { limit: 10 } },
})

// Execute a marketplace retriever
const marketplace = await client.request({
  method: 'POST',
  url: '/v1/marketplace/catalog/brand-safety/execute',
  data: { inputs: { query: 'test content' }, settings: { limit: 5 } },
})

Billing

All API calls through /api are billed to the organization that owns the canvas app. End-users don’t need their own Mixpeek API keys or accounts — usage is attributed to your org automatically.

Environments

Each app supports two independent environments:
EnvironmentURLUse case
Stagingstaging-{slug}.mxp.coTest changes before going live
Production{slug}.mxp.coLive, user-facing deployment
Each environment has its own S3 asset prefix, so staging and production can serve different versions simultaneously. Deploy to either environment from Studio or via the API.

Deploying to staging

Set "environment": "staging" in the deploy request. Your staging build is live at https://staging-{slug}.mxp.co.

Promoting to production

Deploy the same bundle to production, or use the restore endpoint to point production at a staging version’s assets:
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"}'

Creating an App

Via Studio

Go to AppsCreate App. The wizard collects:
  1. Name + Slug — the name is display-only; the slug becomes your URL ({slug}.mxp.co) and must be globally unique
  2. Access Control — choose how end-users authenticate (public, password, API key, JWT, or SSO)

Via API

Only slug and meta are required. After creation, deploy your code via the deploy pipeline.
from mixpeek import Mixpeek

client = Mixpeek(api_key="your-api-key")

app = client.apps.create(
    slug="product-search",
    meta={"title": "Product Search"},
    auth_config={"mode": "clerk"},  # optional — enable Clerk auth
)
print(f"App created: {app.app_id}")
print(f"URL: https://{app.slug}.mxp.co")

Deploy lifecycle

Every deploy creates a new versioned build. The lifecycle is:
StageDescription
queuedBundle uploaded, build queued
buildingMixpeek is packaging and deploying your bundle
completeBuild complete — app is live
failedBuild failed — previous version stays live, check error message

Operations

OperationWhat it doesCreates a version?
Deploy (POST /v1/apps/{id}/deploy)Upload and serve a new code bundleYes — with asset manifest and message
Restore (POST /v1/apps/{id}/versions/{v}/restore)Roll back to any previous version’s assetsNo — instant redirect
Promote (POST /v1/apps/{id}/promote)Promote staging deploy to productionNo — swaps environments
Update (PATCH /v1/apps/{id})Update app config (auth, meta, etc.)No
Each deploy requires a commit message describing what changed. See Version History for the full version control system.

Authentication modes

ModeDescription
publicAnyone can access — no login required
passwordShared password gate
api_keyRequires X-App-Key header
clerkClerk-powered sign-in with per-app user management
jwtCustomer-managed tokens
sso_oidcOkta, Auth0, Azure AD
sso_samlEnterprise SAML 2.0 IdP
Auth enforcement activates when the canvas runtime is deployed. Config is stored now and takes effect automatically.

Custom domains

Every app gets a default URL at https://{slug}.mxp.co. You can also add your own subdomain:
  1. Enter your subdomain (e.g., search.yourdomain.com) in the Domains panel
  2. Add a DNS CNAME record pointing to the target shown in the response
  3. Click Verify — Mixpeek provisions a TLS certificate automatically via Cloudflare
See Custom Domains for the full setup guide.

Example apps

E-commerce product search

React app with multimodal search — text queries, image upload, and faceted filters backed by a Mixpeek retriever.

Internal knowledge base

Password-protected semantic search over company documents, PDFs, and meeting transcripts.

Media library

Video + image search portal with scene-level results, thumbnails, and timestamp previews.

Content moderation dashboard

Real-time moderation queue pulling from alert webhooks and showing flagged content with similarity scores.