Streamlet Package Documentation

@streamlet/sdk

Use the official npm package when you want a simpler JavaScript client for video uploads, image hosting, PDF document hosting, and status checks — plus a clean React player around your Streamlet playback URLs.

Templates

Browse the official Streamlet starter repository for ready-to-use frontend and backend templates. Open Streamlet-Templates.

TemplateStackPurpose
Next.js Video UploadNext.js 16Upload a video, queue processing, and poll for status with @streamlet/sdk.
Next.js Image UploadNext.js 16Upload images and use the returned Streamlet CDN URLs in your app.
Next.js PlayerNext.js 16Embed playback with the Streamlet React player starter.
Node.js Express REST APINode.js / ExpressWrap Streamlet REST API routes in an Express backend.
Go REST APIGoProxy video upload, image upload, and status checks from Go services.
Python REST APIPython / FastAPIBuild Streamlet-backed upload and status endpoints with Python.
Rust REST APIRust / AxumUse Streamlet from a Rust backend service.
Java REST APIJava / Spring BootIntegrate Streamlet REST endpoints into Java backend applications.

Install

Install the package for JavaScript client usage. Add React and React DOM if you want to use the player and editor components.

Install package

Bash

# JavaScript / Node.js client only
npm install @streamlet/sdk

# With React player + editor components
npm install @streamlet/sdk react react-dom

JavaScript Client

Create one StreamletClient with your API credentials, then call uploadStandardStream() (or uploadProtectedStream()) to queue a video and getVideoStatus() to check progress. Every upload is transcoded into an adaptive HLS stream.

Use StreamletClient

JavaScript

import { StreamletClient } from "@streamlet/sdk";

const client = new StreamletClient({
  baseUrl: "https://api.streamletedge.com",
  apiKey: "your_streamlet_api_key",
  accountNumber: "your_account_id"
});

// Public adaptive HLS — returns immediately with a videoId
const result = await client.uploadStandardStream({
  file,
  videoTitle: "Launch Demo",
  enableCaption: true,
  captionLanguages: ["english", "hindi", "tamil"]
});

console.log(result.videoId);        // "Launch-Demo-1715000000000"
console.log(result.protectionMode); // "standard"

// Check status once
const status = await client.getVideoStatus(result.videoId);
console.log(status.status); // "queued" | "processing" | "completed" | "failed"

Upload Options

Both uploadStandardStream() and uploadProtectedStream() accept the same processing options — only file is required. Every upload is transcoded into an adaptive HLS stream. Both resolve immediately with { videoId, status: "queued", protectionMode, statusUrl }.

uploadStandardStream() — full options

JavaScript

await client.uploadStandardStream({
  // Required
  file,                            // File or Blob

  // Optional
  videoTitle: "My video",          // defaults to the file name
  autoAudioEnhancement: true,      // AI audio cleanup before encode
  storageSaverEncoding: false,     // smaller HLS files, slower processing
  videoOptimization: "fast",       // "fast" (default) or "storage_saver"

  // Captions
  enableCaption: true,
  captionLanguages: [
    "english",    // always the base language (Whisper)
    "hindi",      // translated from English
    "tamil", "telugu", "kannada", "malayalam",
    "spanish", "portuguese", "arabic",
    "french", "german", "chinese"
  ],

  // Resolution upgrades
  enable2kOutput: false,           // add 1440p rendition — Builder and Pro plans
  enable4kOutput: false,           // add 2160p rendition — Pro plan only

  // Watermark — paid plans (Starter, Builder, Pro) only.
  // Free plan: "streamletedge.com" is always stamped; these fields are ignored.
  // Paid plan: set enableWatermark: true for a custom overlay, false/omit for no watermark.
  enableWatermark: true,           // true = custom watermark, false = no watermark at all
  watermarkText: "© MyBrand 2024" // max 60 characters; only used when enableWatermark: true
});

Protected streams

uploadProtectedStream() takes every option above plus a securityobject of edge access rules (arrays of strings). Rules are enforced at the CDN edge and can be edited later from each video's Security & access menu in the dashboard. This method requires the Builder, Pro, or Scale plan.

uploadProtectedStream() — security rules

JavaScript

await client.uploadProtectedStream({
  file,
  videoTitle: "Internal Training",
  enableCaption: true,
  captionLanguages: ["english", "hindi"],

  // Edge access control — all fields optional
  security: {
    published: true,                       // false = unavailable to everyone
    allowedCountries: ["IN", "US", "AE"],  // 2-letter ISO codes; [] = worldwide
    allowedDomains: ["app.mybrand.com"],   // embed-allowed domains; [] = any site
    allowedIPs: [],                        // viewer IPs allowed; [] = any IP
    blockedIPs: ["203.0.113.7"]            // viewer IPs always denied
  }
});

client.uploadVideo(input) remains as a deprecated alias — it routes to uploadProtectedStream() when input.protectionMode === "protected", otherwise to uploadStandardStream(). Prefer the two dedicated methods for new code.

Plan Limits

Streamlet enforces per-plan storage and video duration limits. When a limit is exceeded the API returns an error before any processing starts — no partial charges or silent failures.

Video duration limit

Free-plan accounts may only upload videos up to 10 minutes (600 seconds). Uploads longer than this are rejected with the error code DURATION_LIMIT_EXCEEDED. Paid plans have no duration cap.

Handle duration limit error

JavaScript

import { StreamletClient } from "@streamlet/sdk";

const client = new StreamletClient({ baseUrl, apiKey, accountNumber });

try {
  const result = await client.uploadStandardStream({ file, videoTitle: "Long Video" });
  console.log(result.videoId);
} catch (err) {
  if (err.code === "DURATION_LIMIT_EXCEEDED") {
    // Free plan: video longer than 10 minutes
    console.error("Upgrade your plan to upload longer videos.");
  } else {
    throw err;
  }
}
PlanMax video durationStorageMax resolution2K output4K outputCaption quota / monthWatermark
free10 minutes2 GB480p10 minutesForced — streamletedge.com
starterUnlimited100 GB1080p10 hoursOptional custom text
builderUnlimited400 GB2K (1440p)enable2kOutput30 hoursOptional custom text
proUnlimited1 TB4K (2160p)enable2kOutputenable4kOutput75 hoursOptional custom text
scaleUnlimited2 TB4K (2160p)enable2kOutputenable4kOutput150 hoursOptional / white-label

Caption quota

Caption usage is tracked per account and resets on the 1st of each month. The quota is based on the total duration of videos processed with captions enabled. When the quota is exhausted, uploads with enableCaption: true are rejected with error code CAPTION_QUOTA_EXCEEDED.

Handle caption quota error

JavaScript

try {
  const result = await client.uploadStandardStream({
    file,
    videoTitle: "Demo",
    enableCaption: true,
    captionLanguages: ["english", "hindi"],
  });
  console.log(result.videoId);
} catch (err) {
  if (err.code === "CAPTION_QUOTA_EXCEEDED") {
    // Monthly caption quota used up — upgrade or wait for reset
    console.error("Caption quota exhausted. Upgrade your plan or wait for the monthly reset.");
  } else if (err.code === "DURATION_LIMIT_EXCEEDED") {
    console.error("Free plan: video must be under 10 minutes.");
  } else {
    throw err;
  }
}

Polling

Use pollVideoStatus() to automatically wait until processing completes instead of writing your own loop. It resolves with the final status once the job is "completed" or "failed", and throws if the timeout is exceeded.

Poll until done

JavaScript

import { StreamletClient } from "@streamlet/sdk";

const client = new StreamletClient({ baseUrl, apiKey, accountNumber });

const { videoId } = await client.uploadStandardStream({ file, videoTitle: "Demo" });

const finalStatus = await client.pollVideoStatus(videoId, {
  interval: 4000,       // check every 4 s (default)
  timeout: 600_000,     // give up after 10 min (default)
  onProgress: (status) => {
    console.log("still processing…", status.status);
  }
});

if (finalStatus.status === "completed") {
  console.log("Stream URL:", finalStatus.streamUrl);
  console.log("Thumbnail:", finalStatus.thumbnail);
  console.log("Captions:", finalStatus.captions);
  // { en: "https://…/captions.en.vtt", hi: "https://…/captions.hi.vtt", … }
} else {
  console.error("Processing failed:", finalStatus.error);
}

Image Hosting

Use uploadImage()to store images on Streamlet's CDN. The backend auto-rotates, resizes to a max of 2000 px wide, and converts every upload to WebP at quality 85. The result is a permanent, public CDN URL ready to drop into any <img> or <StreamletPlayer> posterUrl.

Accepted formats: JPEG, PNG, WebP, AVIF, GIF. Maximum file size is 20 MB. Storage counts toward the account plan quota.

Upload an image

JavaScript

import { StreamletClient } from "@streamlet/sdk";

const client = new StreamletClient({
  baseUrl: "https://api.streamletedge.com",
  apiKey: "your_streamlet_api_key",
  accountNumber: "your_account_id"
});

// Pass a File (browser) or a Buffer / ReadStream (Node.js)
const image = await client.uploadImage({ file: imageFile });

console.log(image.cdnUrl);
// "https://cdn.streamletedge.com/<accountId>/images/product-banner-1775211037986.webp"

console.log(image.width, image.height);  // 1200, 630
console.log(image.sizeBytes);            // 84320

Use the CDN URL as a video poster

JavaScript

// Upload thumbnail first, then reference it in the player
const thumb = await client.uploadImage({ file: thumbnailFile });

const { videoId } = await client.uploadStandardStream({
  file: videoFile,
  videoTitle: "Product Demo"
});

const status = await client.pollVideoStatus(videoId);

// Use the uploaded image as a custom poster
console.log(thumb.cdnUrl);      // custom thumbnail CDN URL
console.log(status.streamUrl);  // HLS stream URL

uploadImage() — response shape

TypeScript

type ImageUploadResult = {
  success: true;
  imageId: string;   // "product-banner-1775211037986"
  cdnUrl:  string;   // "https://cdn.streamletedge.com/.../images/<imageId>.webp"
  streamletKey:   string;   // "<userId>/images/<imageId>.webp"
  width:   number;   // final pixel width after resize
  height:  number;   // final pixel height after resize
  sizeBytes: number; // WebP output size in bytes
};

Document Hosting

Use uploadDocument()to store PDF files on Streamlet's CDN. The file is stored as-is and a permanent public CDN URL is returned immediately — no processing queue, no polling required.

Accepted format: PDF only. Maximum file size is 50 MB. Storage counts toward the account plan quota.

Upload a PDF document

JavaScript

import { StreamletClient } from "@streamlet/sdk";

const client = new StreamletClient({
  baseUrl: "https://api.streamletedge.com",
  apiKey: "your_streamlet_api_key",
  accountNumber: "your_account_id"
});

// Pass a File (browser) or a Buffer / ReadStream (Node.js)
const doc = await client.uploadDocument({ file: pdfFile });

console.log(doc.cdnUrl);
// "https://cdn.streamletedge.com/<accountId>/documents/product-spec-1775211037986.pdf"

console.log(doc.originalFilename); // "product-spec.pdf"
console.log(doc.sizeBytes);        // 245760

uploadDocument() — response shape

TypeScript

type DocumentUploadResult = {
  success: true;
  documentId:       string; // "product-spec-1775211037986"
  cdnUrl:           string; // "https://cdn.streamletedge.com/.../documents/<documentId>.pdf"
  streamletKey:     string; // "<userId>/documents/<documentId>.pdf"
  originalFilename: string; // "product-spec.pdf"
  sizeBytes:        number; // file size in bytes
};

React Player

<StreamletPlayer /> is a responsive Mux wrapper with a built-in chapter sidebar, progress timeline, and subtitle tracks. Pass the streamUrl returned by pollVideoStatus() and the player handles the rest.

Use StreamletPlayer

JavaScript

import { StreamletPlayer } from "@streamlet/sdk/react";

// Minimal — just play the video
<StreamletPlayer
  title="Launch Demo"
  streamUrl={status.streamUrl}
  posterUrl={status.thumbnail}
/>

// Full — captions + chapters + custom theme
<StreamletPlayer
  title="Launch Demo"
  streamUrl={status.streamUrl}
  posterUrl={status.thumbnail}
  ownerName="Shangesh"
  createdAt={status.completedAt}

  captionLanguages={["english", "hindi", "tamil"]}

  chaptersUrl={status.chapters?.json}
  chapterTrackUrl={status.chapters?.vtt}

  showMeta={true}
  showTimeline={true}
  showChapterSidebar={true}

  theme={{
    accentColor: "#38bdf8",
    progressFillColor: "#2563eb",
    primaryColor: "#f8fafc",
    surfaceColor: "rgba(4,8,15,0.94)"
  }}
/>