🎬 3Speak Embed Upload

Decentralized Video Upload & Encoding Service

🚀

Try Demo

Test the upload system with a live demo

🔑

Admin Panel

Manage API keys (password protected)

📚

Documentation

Integration guide and API reference

✨ Features

TUS Resumable Uploads

Robust uploads with pause/resume support for large video files

IPFS Storage

Decentralized storage with automatic pinning to IPFS

Multi-Encoder Support

Load balancing across multiple encoding nodes

Instant Embeds

Get embed URLs immediately, watch videos as they encode

Job Tracking

Monitor encoding progress and status in real-time

Upload Tokens

Short-lived signed tokens for secure client-side uploads without exposing API keys

Progress Tracking

Real-time encoding progress via simple polling — build custom progress UI

📖 Integration Guide

⚠️ API Key Required: Contact the 3Speak team to get your API key before integrating this service.

Authentication

The service supports two authentication methods. Both are fully supported — choose the one that fits your architecture:

Option 1: Direct API Key (Server / Mobile)

The simplest integration — pass your API key directly in the upload request:

import * as tus from 'tus-js-client';

const file = document.getElementById('video-input').files[0];

const upload = new tus.Upload(file, {
  endpoint: 'https://embed.3speak.tv/uploads',
  headers: {
    'X-API-Key': 'your-api-key-here'
  },
  metadata: {
    filename: file.name,
    owner: 'username',
    frontend_app: 'your-app-name',
    short: 'false'  // 'true' for 60s clips
  },
  onError: (error) => console.error('Upload failed:', error),
  onProgress: (bytesUploaded, bytesTotal) => {
    console.log(`${(bytesUploaded / bytesTotal * 100).toFixed(2)}%`);
  },
  onSuccess: () => console.log('Upload complete!'),
  onAfterResponse: (req, res) => {
    const embedUrl = res.getHeader('X-Embed-URL');
    console.log('Embed URL:', embedUrl);
  }
});

upload.start();

Option 2: Upload Tokens (Web Apps — Recommended for Browsers)

For web apps, use upload tokens so your API key never reaches the browser.

Step 1 — Your backend requests a token:

// Server-side (Node.js, Python, etc.)
const response = await fetch('https://embed.3speak.tv/uploads/token', {
  method: 'POST',
  headers: {
    'X-API-Key': process.env.EMBED_API_KEY,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    owner: 'username',
    frontend_app: 'your-app-name',
    short: false,
    allowed_origins: ['https://your-app.com'],
    max_file_size: 1073741824,  // 1GB
    ttl: 600                    // 10 minutes
  })
});

const { token, upload_url, expires_at } = await response.json();
// Send token and upload_url to your frontend

Step 2 — Your frontend uploads with the token:

// Client-side (browser) — API key never appears here
const upload = new tus.Upload(file, {
  endpoint: uploadUrl,   // from your backend
  headers: {
    'Authorization': `Bearer ${token}`  // from your backend
  },
  metadata: {
    filename: file.name,
    filetype: file.type,
    // owner, frontend_app, short are already in the token
  },
  onError: (error) => console.error('Upload failed:', error),
  onProgress: (bytesUploaded, bytesTotal) => {
    console.log(`${(bytesUploaded / bytesTotal * 100).toFixed(2)}%`);
  },
  onSuccess: () => console.log('Upload complete!'),
  onAfterResponse: (req, res) => {
    const embedUrl = res.getHeader('X-Embed-URL');
    console.log('Embed URL:', embedUrl);
  }
});

upload.start();

Token properties:

Tracking Progress

After starting an upload, poll GET /video/:permlink to track encoding progress. This endpoint is public (no auth required). Extract the permlink from the X-Embed-URL response header.

const permlink = embedUrl.split('/').pop(); // e.g. "yn77aj9g"

async function pollProgress() {
  const res = await fetch(`https://embed.3speak.tv/video/${permlink}`);
  const video = await res.json();

  console.log(`Status: ${video.status}, Progress: ${video.encodingProgress}%`);

  if (video.status === 'published') {
    console.log('Video ready! CID:', video.manifest_cid);
    return;
  }
  if (video.status === 'failed') {
    console.error('Encoding failed');
    return;
  }

  setTimeout(pollProgress, 5000); // poll every 5s
}

pollProgress();

Status lifecycle: uploadingprocessingpublished (or failed)

The embed player handles all states automatically (showing upload/processing animations), so the embed URL is usable immediately — but polling lets your app show custom progress UI.

Embed URL Format

Videos are instantly accessible via:

https://play.3speak.tv/embed?v={username}/{videoId}

For Blog Composers (Peakd/Ecency)

Simple HTML5 video tag:

<video src="play.3speak.tv/watch?v={username}/{videoId}" controls></video>

For Websites (Full Iframe)

Full featured player with controls:

<iframe
  src="https://play.3speak.tv/embed?v={username}/{videoId}"
  width="100%"
  height="500"
  frameborder="0"
  allowfullscreen>
</iframe>

Video Types

API Endpoints

Update Thumbnail

Set a custom thumbnail for your video after upload:

fetch('https://embed.3speak.tv/video/ABC123XY/thumbnail', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-API-Key': 'your-api-key'
  },
  body: JSON.stringify({
    thumbnail_url: 'https://your-cdn.com/thumbnail.jpg'
  })
});

Required Metadata

🔐 Getting Access

To integrate this service into your application:

  1. Contact the 3Speak development team
  2. Provide your application name and use case
  3. Receive your unique API key
  4. Start uploading videos!
Contact: Reach out to the 3Speak team at 3speak.tv