VideohatiDocs
Guides

Guide: Upload and play your first video

Install @videohati/node, upload a file in chunks, wait until it is ready, and create a playback session — end to end.

This guide takes you from an empty project to a playable video using the official Node.js SDK. Every step runs against test mode, so you can follow along without touching live data.

Before you start

You need:

  • Node.js 18 or newer (the SDK uses the built-in fetch and AbortSignal).
  • A project test API key. Create one in the dashboard under Project → API keys. A test key starts with vh_test_.
  • A short video file to upload, for example lecture-01.mp4.

Keep your API key on the server. It is project-scoped and grants write access. Never ship a vh_live_ or vh_test_ key to a browser.

1. Install the SDK

npm install @videohati/node

2. Initialize the client

The mode follows the key prefix: a vh_test_ key puts the client in test mode automatically.

import { Videohati } from "@videohati/node";

const videohati = new Videohati({
  apiKey: process.env.VIDEOHATI_API_KEY, // vh_test_...
});

console.log(videohati.mode); // "test"

3. Upload a file in chunks

videos.upload() runs the full multipart flow in one call: it creates the video, opens an upload session, PUTs every part to the upload endpoint, and completes the upload. Pass a file path, a Uint8Array/Buffer, or a Blob/File.

const uploaded = await videohati.videos.upload("./lecture-01.mp4", {
  onProgress: ({ partsCompleted, totalParts }) => {
    console.log(`Uploaded part ${partsCompleted}/${totalParts}`);
  },
});

console.log(uploaded.videoId); // 01JZ9WV3N8GQ5T2M7K4C6XBARH
console.log(uploaded.state); // "uploaded"

Want manual control instead of the one-call helper? The same flow is available as videos.create(), videos.startUpload(), the per-part PUT requests, and videos.completeUpload().

4. Wait until the video is ready

After the upload completes, encoding runs in the background. Poll the video with videos.waitForState() until it reaches ready (or failed).

const video = await videohati.videos.waitForState(uploaded.videoId, {
  targetStates: ["ready", "failed"],
});

if (video.state === "failed") {
  throw new Error(`Encoding failed: ${video.errorMessage ?? video.errorCode}`);
}

console.log("Video is ready to stream.");

5. Create a playback session

A playback session mints a short-lived, signed HLS manifest URL plus a sessionToken for the player. Create it server-side and hand only the session — never the API key — to the page.

const session = await videohati.playback.createSession({
  videoId: video.id,
  viewerDisplayText: "[email protected]", // shown in the watermark
});

console.log(session.manifestUrl); // signed master.m3u8 URL
console.log(session.sessionToken); // pass this to the player

The response includes everything the player needs:

FieldMeaning
manifestUrlSigned HLS master playlist URL.
sessionTokenOwnership token for the embedded player.
heartbeatIntervalSecondsHow often the player re-asserts the session.
expiresAtWhen the session and its signed URL expire.

6. Embed the player

Hand the videoId, projectId, and sessionToken to the web player. The framework-free bundle reads them from data- attributes:

<script src="https://cdn.videohati.com/player.js" async></script>
<div
  data-videohati-video-id="01JZ9WV3N8GQ5T2M7K4C6XBARH"
  data-videohati-project-id="01JZ9WV3N8GQ5T2M7K4C6XBARP"
  data-videohati-session-token="01JZ9WV3N8GQ5T2M7K4C6XBARK.1781485200.bXktbWFj"
></div>

For a React app, see Embed a Videohati player in a Next.js 15 app.

Full script

import { Videohati } from "@videohati/node";

async function main() {
  const videohati = new Videohati({ apiKey: process.env.VIDEOHATI_API_KEY });

  const uploaded = await videohati.videos.upload("./lecture-01.mp4", {
    onProgress: ({ partsCompleted, totalParts }) =>
      console.log(`Uploaded part ${partsCompleted}/${totalParts}`),
  });

  const video = await videohati.videos.waitForState(uploaded.videoId);
  if (video.state === "failed") {
    throw new Error(`Encoding failed: ${video.errorMessage ?? video.errorCode}`);
  }

  const session = await videohati.playback.createSession({
    videoId: video.id,
    viewerDisplayText: "[email protected]",
  });

  console.log("Manifest:", session.manifestUrl);
  console.log("Session token:", session.sessionToken);
}

main().catch((error) => {
  console.error(error);
  process.exit(1);
});