Player and library in the API.
Drive the player through events. Manage videos, collections and analytics through the versioned REST API.
player.on("timeupdate", ({ currentTime }) =>
setBar(currentTime / player.duration));See it in depthDrive the player through a complete event API. Manage your library through the versioned REST API. Receive a signed, granular webhook for every step of the video. Protect content with short-lived tokens your backend signs. All documented, with examples that actually run. Built by a developer with 15+ years in the field, for developers.
I've been coding for over 15 years. A good chunk of that integrating video into other people's products.
I know where it breaks. APIs that do half the job. Webhooks that warn you little and late. Security treated as a roadmap item, not as the foundation.
Moviie is the tool I wish I'd been handed ready. Not because I'm special. Because I got burned enough to know what can't be missing.
You don't have to take my word for it. Read the docs. Play with the player above. Check the webhook signatures. The product speaks for me.
You're the one who decides. The rest of this page is the list of reasons to decide on Moviie.
It ships the basics and locks the rest out of your reach. No versioning, no OpenAPI, no automation where it matters. Everything the API doesn't cover turns into manual work that comes back every week.
How Moviie solves itYou style it as far as they let you. Past that, the CSS overrides begin, the DOM hacks, the fork that breaks on the next update. With no event API, your UI is never in sync.
How Moviie solves itFew events, no signature, no retry. You end up polling, building makeshift queues, and finding out the video's state by asking, not by being told. And when the notice does come, it comes with no way to trust its origin.
How Moviie solves itOpen link, embed that runs anywhere, key with no scope. Protection becomes backlog until the day the video leaks. Then it's no longer a detail.
How Moviie solves itDrive the player through events. Manage videos, collections and analytics through the versioned REST API.
player.on("timeupdate", ({ currentTime }) =>
setBar(currentTime / player.duration));See it in depthYou subscribe to only what matters. Every delivery comes signed, with retry and an attempt counter.
{ "type": "video.ready",
"data": { "video": { "id": "…" } } }See it in depthPrivate video, minute-long token tied to a single video, ephemeral asset URL.
jwt.sign({ sub: videoId }, signingKey, {
algorithm: "HS256", expiresIn: "5m" });See it in depthThe REST API lives at api.moviie.ai/v1, versioned by prefix. You authenticate with a Bearer key created in the dash, under Settings → API Keys. List, search, update, delete and upload video. Organize it into collections. Pull audience metrics. There's a published OpenAPI spec, so you generate a client in your language without guessing the contract. And the dash mirrors all of it, with the key two clicks away.
# chave secreta criada no dash: Settings > API Keys
curl https://api.moviie.ai/v1/me \
-H "Authorization: Bearer mvi_sua_chave"
# { "organization": { "id": "...", "name": "Acme", "plan": "pro" } }First authenticated call in one line.
Load the embed with controls=0 and build your own controls. The player exposes the API with methods for everything: play, pause, seek, volume, speed, fullscreen, picture-in-picture. And a complete event API keeps your interface in sync, even when the viewer uses a keyboard shortcut, a media key, or the system controls. The difference from a locked player: here the UI is yours, and it never lies about the state.
<iframe src="https://watch.moviie.ai/embed/EMBED_ID?controls=0"
allow="autoplay; fullscreen; picture-in-picture" allowfullscreen></iframe>// sua UI dirige o player; os eventos mantem ela em sincronia
const player = Moviie.getPlayer(iframe);
player.on("play", () => paintPlaying());
player.on("pause", () => paintPaused());
player.on("timeupdate", ({ currentTime }) =>
setBar(currentTime / player.duration));
seekBar.oninput = (e) =>
player.seek(player.duration * (e.target.value / 100));It's the same model as the demo up top.
A granular event catalog: upload, encoding, publishing, captions, chapters, CTA, plus telemetry with milestones at 25, 50, 75 and 100 percent, completion rate, view milestones and bandwidth and storage thresholds. You enable only what matters, per endpoint. Every delivery arrives signed with HMAC-SHA256 in the header, with an attempt counter, and automatic retry of up to six attempts with backoff that respects your system. And a real failure only becomes an event after it's confirmed, with no false alarm from an unstable callback.

A slice of the catalog. You turn on only what you need, per endpoint.
Mark the video as private and it serves nothing without a valid token. Your backend signs a short JWT, tied to a single video, with the signing key that stays on the server. The asset comes back as a signed, ephemeral URL. You rotate the signing key with no downtime and revoke it instantly. Add to that allowed domains and keys separated by role: publishable on the client, secret on the server, signing for tokens. No promising Hollywood DRM. Protection by token, signed URL and domain, stated plainly.
import jwt from "jsonwebtoken";
// chave de assinatura (mvi_sign_) fica no backend
const token = jwt.sign({ sub: videoId }, signingKeySecret, {
algorithm: "HS256",
keyid: signingKeyId,
expiresIn: "5m", // token curto, por sessao
});<iframe src="https://watch.moviie.ai/embed/EMBED_ID?token=THE_JWT"></iframe>Wrong token for the wrong video? 403. No exceptions.
You're not evaluating a plugin. It's the same delivery mesh that holds launches, membership areas and VSLs at peak. Rate limits and SLA
It's all in the docs. It's not a promise, it's a reference. Open the documentation
14 days of full trial. Card at signup, cancel in one click. No sales call. You leave the trial knowing whether Moviie solves your problem.