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.
This guide wires the official Laravel SDK into a Laravel 11 app. You will upload a video from the server, create a playback session, and render the player with the bundled Blade directive.
Before you start
You need:
- A Laravel 11 app running on PHP 8.2 or newer.
- A project API key in test mode (
vh_test_...). - Your project id (used by the player embed).
1. Install the package
composer require videohati/laravelThe package auto-discovers its service provider and the Videohati facade —
no manual registration is needed.
2. Configure your environment
Add your credentials to .env:
VIDEOHATI_API_KEY=vh_test_xxxxxxxxxxxxxxxxxxxxx
VIDEOHATI_PROJECT_ID=01JZ9WV3N8GQ5T2M7K4C6XBARPOptionally publish the config file to tune the base URL, player URL, or timeout:
php artisan vendor:publish --tag=videohati-configKeep VIDEOHATI_API_KEY out of version control. The key is project-scoped
and grants write access.
3. Upload a video
videos()->upload() runs the full multipart flow: create the video, open the
upload session, PUT each part to the upload endpoint, and complete the upload.
It returns the completion payload, including the videoId.
use Videohati\Laravel\Facades\Videohati;
$result = Videohati::videos()->upload(
storage_path('app/lectures/lecture-01.mp4'),
onProgress: function (int $uploaded, int $total) {
logger()->info("Uploaded {$uploaded} / {$total} bytes");
},
);
$videoId = $result['videoId'];Prefer manual control? 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
Encoding runs after the upload completes. Poll with videos()->get() and
check the DTO's state until it is ready:
use Videohati\Laravel\Facades\Videohati;
do {
sleep(3);
$video = Videohati::videos()->get($videoId);
} while (!in_array($video->state, ['ready', 'failed'], true));
abort_if($video->state === 'failed', 422, 'Encoding failed');5. Create a playback session
Create the session on the server, then pass only the sessionToken to the
view — never the API key.
use Videohati\Laravel\Facades\Videohati;
$session = Videohati::playback()->createSession(
videoId: $videoId,
viewerDisplayText: auth()->user()->email, // shown in the watermark
);
return view('watch', [
'videoId' => $videoId,
'sessionToken' => $session->sessionToken,
]);The returned PlaybackSessionDto exposes sessionId, manifestUrl,
sessionToken, watermarkToken, expiresAt, and heartbeatIntervalSeconds.
6. Embed the player in a Blade view
The package ships a @videohatiPlayer Blade directive that emits the player
<script> plus its mount <div>. The projectId defaults to
VIDEOHATI_PROJECT_ID.
{{-- resources/views/watch.blade.php --}}
<!doctype html>
<html lang="en" dir="ltr">
<body>
@videohatiPlayer([
'videoId' => $videoId,
'sessionToken' => $sessionToken,
'lang' => 'en',
'autoplay' => 'muted',
])
</body>
</html>For Arabic, set 'lang' => 'ar' and dir="rtl" on <html>:
<html lang="ar" dir="rtl">
<body>
@videohatiPlayer([
'videoId' => $videoId,
'sessionToken' => $sessionToken,
'lang' => 'ar',
])
</body>
</html>That is the full path: upload on the server, mint a session, and embed the player — all without exposing your API key to the browser.
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.
Guide: Embed on any site (plain HTML, WordPress, any CMS)
Play a Videohati video on a plain HTML page, in WordPress, or in any CMS by pasting one script tag and a mount element.