mono/packages/ui/docs/mux-integration.md
2026-02-08 15:09:32 +01:00

7.1 KiB

Mux Video Integration

This project integrates Mux for professional video upload, processing, and streaming capabilities.

Overview

Mux provides:

  • Video Upload: Drag & drop or click to upload video files
  • Automatic Processing: Videos are automatically transcoded and optimized
  • HLS Streaming: Adaptive bitrate streaming for smooth playback
  • Thumbnail Generation: Automatic thumbnails and poster images
  • Analytics: Track video views and engagement (optional)

Architecture

Flow

  1. Client requests upload URL → Frontend calls our Supabase Edge Function
  2. Edge Function creates upload → Calls Mux API to generate signed upload URL
  3. User uploads video → Mux Uploader handles the upload with progress tracking
  4. Mux processes video → Transcodes video, creates HLS stream, generates thumbnails
  5. Get playback ID → Poll for asset creation, retrieve playback ID
  6. Play video → Use Vidstack player with Mux HLS stream URL

Components

  • MuxUploader: React component for uploading videos (@mux/mux-uploader-react)
  • VideoCard: Component for displaying videos with Vidstack player
  • mux-proxy: Supabase Edge Function that interfaces with Mux API

Setup

1. Get Mux Credentials

  1. Sign up at mux.com
  2. Navigate to SettingsAccess Tokens
  3. Create a new access token with permissions:
    • Mux Video - Read and Write
  4. Copy the Token ID and Token Secret

2. Configure Environment Variables

Add these to your Supabase Edge Function environment variables:

MUX_TOKEN_ID=your_token_id_here
MUX_TOKEN_SECRET=your_token_secret_here

To set them in Supabase:

# Using Supabase CLI
supabase secrets set MUX_TOKEN_ID=your_token_id
supabase secrets set MUX_TOKEN_SECRET=your_token_secret

# Or via Supabase Dashboard
# Project Settings → Edge Functions → Secrets

3. Deploy Edge Function

supabase functions deploy mux-proxy

Usage

Upload Video

import MuxUploader from "@mux/mux-uploader-react";
import { supabase } from "@/integrations/supabase/client";

const fetchUploadUrl = async () => {
  const response = await fetch(
    `${supabase.supabaseUrl}/functions/v1/mux-proxy`,
    {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${session.access_token}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ action: 'create-upload' }),
    }
  );
  
  const { data } = await response.json();
  return data.url;
};

function VideoUpload() {
  return (
    <MuxUploader
      endpoint={fetchUploadUrl}
      onSuccess={(event) => {
        console.log('Upload complete!', event.detail);
      }}
    />
  );
}

Play Video

Once you have the playback ID from Mux, you can play the video:

import VideoCard from "@/components/VideoCard";

function VideoPlayer({ playbackId }: { playbackId: string }) {
  const videoUrl = `https://stream.mux.com/${playbackId}.m3u8`;
  const thumbnailUrl = `https://image.mux.com/${playbackId}/thumbnail.jpg`;
  
  return (
    <VideoCard
      videoId="123"
      videoUrl={videoUrl}
      thumbnailUrl={thumbnailUrl}
      title="My Video"
      author="User"
      authorId="user-id"
      likes={0}
      comments={0}
    />
  );
}

Mux API Actions

create-upload

Creates a new direct upload URL.

Request:

{
  "action": "create-upload"
}

Response:

{
  "success": true,
  "data": {
    "id": "upload_abc123",
    "url": "https://storage.googleapis.com/...",
    "status": "waiting"
  }
}

get-upload

Get the status of an upload and check if asset was created.

Request:

{
  "action": "get-upload",
  "uploadId": "upload_abc123"
}

Response:

{
  "success": true,
  "data": {
    "id": "upload_abc123",
    "status": "asset_created",
    "asset_id": "asset_xyz789"
  }
}

get-asset

Get asset details including playback IDs.

Request:

{
  "action": "get-asset",
  "assetId": "asset_xyz789"
}

Response:

{
  "success": true,
  "data": {
    "id": "asset_xyz789",
    "status": "ready",
    "playback_ids": [
      {
        "id": "playback_def456",
        "policy": "public"
      }
    ]
  }
}

Database Schema

Store Mux video data in your videos table:

CREATE TABLE videos (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  user_id UUID NOT NULL,
  title TEXT NOT NULL,
  description TEXT,
  video_url TEXT NOT NULL,  -- https://stream.mux.com/{playback_id}.m3u8
  thumbnail_url TEXT,       -- https://image.mux.com/{playback_id}/thumbnail.jpg
  meta JSONB,               -- { mux_asset_id, mux_playback_id }
  created_at TIMESTAMP DEFAULT NOW()
);

Store in meta:

  • mux_asset_id: For managing the asset via Mux API
  • mux_playback_id: For generating stream/thumbnail URLs

Mux URLs

Stream URL (HLS)

https://stream.mux.com/{PLAYBACK_ID}.m3u8

This is an HLS stream that works with Vidstack, Mux Player, and most video players.

Thumbnail URL

https://image.mux.com/{PLAYBACK_ID}/thumbnail.jpg

Query parameters:

  • ?width=1280 - Set width
  • ?height=720 - Set height
  • ?time=10 - Thumbnail at 10 seconds

MP4 URL (if enabled)

https://stream.mux.com/{PLAYBACK_ID}/high.mp4

Available qualities: low.mp4, medium.mp4, high.mp4

Webhooks (Optional)

For production, set up Mux webhooks to get notified when:

  • Upload completes (video.upload.asset_created)
  • Video is ready (video.asset.ready)
  • Errors occur (video.asset.errored)

This is more efficient than polling. See Mux Webhooks Docs.

Playground

Test the integration at /playground/video-player:

  • Upload tab: Upload videos using Mux
  • Test with URL tab: Test Vidstack player with any video URL

Pricing

Mux charges based on:

  • Encoding: Minutes of video processed
  • Streaming: Minutes of video delivered
  • Storage: GB-months of video stored

See Mux Pricing for current rates.

Free tier includes:

  • $20/month in free credits
  • Enough for ~40 minutes of encoding + 100 hours of streaming

Troubleshooting

Upload fails immediately

  • Check that MUX_TOKEN_ID and MUX_TOKEN_SECRET are set in Supabase
  • Verify the edge function is deployed
  • Check browser console for CORS errors

Video stuck in "processing"

  • Large videos can take several minutes to process
  • Check Mux dashboard for asset status
  • Verify the upload completed successfully

Video won't play

  • Check that playback policy is set to "public"
  • Verify the HLS URL format is correct
  • Check browser console for player errors

Resources