Guide: Embed a player in a Next.js 15 app
Install @videohati/react, create a playback session on the server, and render the player in a client component — with RTL support.
This guide embeds the Videohati player in a Next.js 15 App Router project.
The session is created on the server with the Node SDK; the browser only ever
sees a short-lived sessionToken.
Before you start
You need:
- A Next.js 15 app using the App Router.
- A project API key in test mode (
vh_test_...) on the server. - A video that has finished encoding. See Upload and play your first video.
1. Install the SDKs
The React SDK renders the player; the Node SDK creates the session on the server.
npm install @videohati/react @videohati/node2. Create the playback session on the server
In a Server Component (or a route handler / server action), mint a session with the Node SDK. Keep the API key server-side.
// app/watch/[videoId]/page.tsx
import { Videohati } from "@videohati/node";
import { Watch } from "./watch";
export default async function WatchPage({
params,
}: {
params: Promise<{ videoId: string }>;
}) {
const { videoId } = await params;
const videohati = new Videohati({ apiKey: process.env.VIDEOHATI_API_KEY });
const session = await videohati.playback.createSession({
videoId,
viewerDisplayText: "[email protected]",
});
return (
<Watch
videoId={videoId}
projectId={process.env.VIDEOHATI_PROJECT_ID!}
sessionToken={session.sessionToken}
/>
);
}playback.createSession() must run on the server. Passing a vh_live_ or
vh_test_ API key into a client component would expose it in the browser
bundle.
3. Render the player in a client component
<VideohatiPlayer /> is a client component. Pass the videoId, projectId,
and the server-created sessionToken.
// app/watch/[videoId]/watch.tsx
"use client";
import { VideohatiPlayer } from "@videohati/react";
export function Watch({
videoId,
projectId,
sessionToken,
}: {
videoId: string;
projectId: string;
sessionToken: string;
}) {
return (
<VideohatiPlayer
videoId={videoId}
projectId={projectId}
sessionToken={sessionToken}
lang="en"
autoplay="muted"
onStateChange={(state) => console.log("player state:", state)}
onError={(error) => console.error(error.code, error.message)}
style={{ width: "100%", maxWidth: 960 }}
/>
);
}The player handles HLS playback, the session heartbeat, and the watermark on its own — you do not call the playback endpoints again from the browser.
4. RTL and Arabic
Set lang="ar" to render the player chrome in Arabic with a right-to-left
layout. The player mirrors its own controls; you only need to make sure the
surrounding page direction is correct:
<VideohatiPlayer
videoId={videoId}
projectId={projectId}
sessionToken={sessionToken}
lang="ar"
/>In a localized Next.js layout, set dir="rtl" on <html> (or the player's
container) for the Arabic locale so the page around the player mirrors too.
5. Optional: configure a shared base URL
If you point at a staging API, wrap the part of your tree that uses the React
hooks with VideohatiProvider:
"use client";
import { VideohatiProvider } from "@videohati/react";
export function Providers({ children }: { children: React.ReactNode }) {
return (
<VideohatiProvider baseUrl="https://api.staging.videohati.com">
{children}
</VideohatiProvider>
);
}For client-side uploads from the dashboard session, the useVideohatiUpload
hook drives the same chunked flow inside the browser.
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.
Guide: Integrate Videohati into a Laravel 11 project
Install the videohati/laravel package, configure your key, upload a video, create a playback session, and embed the player in a Blade view.