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.
| Template | Stack | Purpose |
|---|---|---|
| Next.js Video Upload | Next.js 16 | Upload a video, queue processing, and poll for status with @streamlet/sdk. |
| Next.js Image Upload | Next.js 16 | Upload images and use the returned Streamlet CDN URLs in your app. |
| Next.js Player | Next.js 16 | Embed playback with the Streamlet React player starter. |
| Node.js Express REST API | Node.js / Express | Wrap Streamlet REST API routes in an Express backend. |
| Go REST API | Go | Proxy video upload, image upload, and status checks from Go services. |
| Python REST API | Python / FastAPI | Build Streamlet-backed upload and status endpoints with Python. |
| Rust REST API | Rust / Axum | Use Streamlet from a Rust backend service. |
| Java REST API | Java / Spring Boot | Integrate 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-domJavaScript 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;
}
}| Plan | Max video duration | Storage | Max resolution | 2K output | 4K output | Caption quota / month | Watermark |
|---|---|---|---|---|---|---|---|
free | 10 minutes | 2 GB | 480p | — | — | 10 minutes | Forced — streamletedge.com |
starter | Unlimited | 100 GB | 1080p | — | — | 10 hours | Optional custom text |
builder | Unlimited | 400 GB | 2K (1440p) | enable2kOutput | — | 30 hours | Optional custom text |
pro | Unlimited | 1 TB | 4K (2160p) | enable2kOutput | enable4kOutput | 75 hours | Optional custom text |
scale | Unlimited | 2 TB | 4K (2160p) | enable2kOutput | enable4kOutput | 150 hours | Optional / 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); // 84320Use 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 URLuploadImage() — 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); // 245760uploadDocument() — 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)"
}}
/>