Skip to main content

Overview

An App is a fully hosted, versioned web application that you own and deploy through Mixpeek. Upload your code as a .zip bundle, configure a domain, and your app is live — no infrastructure required. Apps replace the legacy Pages concept. While Pages were managed templates, Apps give you full control: write any frontend code, call Mixpeek APIs via the canvas SDK, and ship it under your own brand.

Bring your own code

Upload any React, vanilla JS, or static site. Mixpeek builds and serves it automatically.

Custom domains

Point any subdomain via CNAME. TLS is provisioned automatically.

Built-in auth

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

Deploy history & rollback

Every deploy is versioned. Rollback to any previous build in one click.

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}.apps.mixpeek.com 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.

Creating an App

Via Studio

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

Via API

from mixpeek import Mixpeek

client = Mixpeek(api_key="your-api-key", namespace_id="ns_...")

app = client.apps.create(
    slug="product-search",
    meta={"title": "Product Search"},
    auth_config={"mode": "public"},
)
print(f"App created: {app.app_id}")
print(f"URL: https://{app.slug}.apps.mixpeek.com")

Deploy lifecycle

Every deploy creates a new versioned build. The lifecycle is:
StageDescription
pendingBundle uploaded, build queued
buildingMixpeek is building and packaging your bundle
successBuild complete — app is live
failedBuild failed — check logs, previous version stays live

Draft vs Published

Edits to app config (tabs, auth, meta) are saved as drafts and are not visible to end-users until you click Publish. Code deploys go live immediately after a successful build.
  • Publish — makes the current config draft live (POST /v1/apps/{id}/publish)
  • Rollback — restores the previous published config (POST /v1/apps/{id}/rollback)

Authentication modes

ModeDescription
publicAnyone can access — no login required
passwordShared password gate
api_keyRequires X-App-Key header
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

Add a custom domain in the Domains panel on the App details page:
  1. Enter your subdomain (e.g., search.yourdomain.com)
  2. Add a CNAME record pointing to {slug}.pages.dev
  3. Mixpeek provisions a TLS certificate automatically via Cloudflare
Once the DNS propagates and the certificate is issued, the domain status changes to active.

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.