DEV Community

Cover image for Integrate an IP camera into a web app with ImouPlayer
Imou-OpenPlatform
Imou-OpenPlatform

Posted on

Integrate an IP camera into a web app with ImouPlayer

To integrate an IP camera into a web application, keep OpenAPI on the server and the player in the browser: obtain accessToken on your BFF, authorize the signed-in user against your ACL, mint a short-lived kitToken with getKitToken, then initialize ImouPlayer with that kitToken plus a correct Wasm library path. Serve the page and player assets over HTTPS. Host Wasm/JS on your origin or a CDN that preserves paths and MIME types. Never put appSecret or accessToken in the SPA—ImouPlayer consumes kitToken, not admin credentials.

Official JS guide: JavaScript development. Product overview: Video Monitoring.

Why this walkthrough is a deploy problem, not a <video src> problem

A web app is an origin, a CDN, a set of response headers, and a session cookie. Imou cameras already know how to talk to the cloud; your job is to prove the user may watch, then hand the browser a play credential and loadable Wasm. Teams that skip HTTPS, ship Wasm 404s, or paste accessToken into init() spend a week “debugging cameras” that were never offline.

This is a Hashnode-style longform for the full web path: checklist, steps, a minimal sample, and production hosting notes (HTTPS, Wasm on CDN, cache, destroy). It is not a native OpenSDK guide and not an HLS-only recipe—though bindDeviceLive remains the escape hatch if you already standardized on an HLS client.

Prerequisites

  • Developer account and application on open.imoulife.com
  • Camera bound to the Open Platform developer asset pool
  • Player / JS SDK package from Resource download
  • A BFF that can call OpenAPI (Node, Java, Go—does not matter)
  • HTTPS in any environment that is not a throwaway localhost experiment
  • Product ACL: which logged-in user may see which deviceId / channelId

If binding or secrets are wrong, no amount of frontend polish will produce a first frame.

Web application checklist (print this)

Check Why
Secrets only on BFF appSecret / accessToken in the bundle = compromise
ACL before getKitToken Tenant isolation is your job
kitToken in player Wrong token type → black screen
WasmLibPath loadable 404 on .wasm → player never starts
HTTPS (prod + most staging) Mixed content and Secure cookies will bite you
CDN path = package layout Trailing slash / folder depth must match the SDK zip
streamId policy 1 = SD default; 0 = HD focus
Destroy on route change SPA leaks = lag + quota
On-demand mint Do not prefetch live for every row on a list page

Steps

1. Server: accessToken

Call the documented accessToken API from the BFF. Cache it. Rotate according to platform guidance. This authenticates OpenAPI, including getKitToken and inventory APIs.

2. Server: authorize the web session

Your web app already has login. Reuse it. POST /api/live-session should verify the session cookie/JWT, then check tenant/site/role/camera. Return 403 with a generic body if denied. Do not leak whether another tenant’s camera exists.

3. Server: getKitToken

After ACL, mint kitToken for that deviceId / channelId. Cache roughly 1 hour on the BFF; documented TTL is about 2 hours. Return { kitToken, expiresAt } only. Optionally include streamId so the UI does not invent quality.

4. Client: host player JS + Wasm

Copy the SDK package into public/imou/ (or equivalent). The browser must fetch both the player script and WasmLib. In production, that fetch is over HTTPS from your origin or a CDN.

5. Client: init ImouPlayer

Mount a DOM node, then init with kitToken, WasmLibPath, and streamId. Prefer SD for dashboards.

6. Client: lifecycle

Destroy the player on unmount, camera switch, and (if UX allows) hidden tabs. Refresh kitToken via BFF before expiry on long sessions.

7. Optional HLS branch

If the same web app already uses a standard HLS player, the BFF can call bindDeviceLive after the same ACL check and return an HLS URL. Treat that URL as a secret. ImouPlayer remains the default for interactive Light App controls.

RTMP (createDeviceRtmpLive) is for media pipelines, not a typical SPA <video> tag.

Minimal HTML / JS sample

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>ImouPlayer web app</title>
  <style>
    #player { width: 100%; max-width: 960px; aspect-ratio: 16 / 9; background: #111; }
  </style>
</head>
<body>
  <h1>Site live</h1>
  <div id="player"></div>
  <!-- Path must match how you deploy the SDK package -->
  <script src="/static/imou/imouPlayer.js"></script>
  <script>
    let player;

    async function createLiveSession(deviceId, channelId) {
      const res = await fetch("/api/live-session", {
        method: "POST",
        credentials: "include",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ deviceId, channelId })
      });
      if (!res.ok) throw new Error("live-session " + res.status);
      return res.json(); // { kitToken, expiresAt }
    }

    async function startLive() {
      const { kitToken } = await createLiveSession("YOUR_DEVICE_ID", "YOUR_CHANNEL_ID");
      // Option names: align with the SDK version in the JS book.
      player = new ImouPlayer({
        el: "#player",
        kitToken,
        WasmLibPath: "/static/imou/WasmLib/",
        streamId: 1
      });
    }

    window.addEventListener("beforeunload", () => {
      if (player && player.destroy) player.destroy();
    });

    startLive().catch((err) => console.error(err));
  </script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Illustrative BFF contract:

POST /api/live-session
Cookie: session=...
Body: { "deviceId": "...", "channelId": "..." }

200 { "kitToken": "...", "expiresAt": "..." }
403 { "error": "forbidden" }
Enter fullscreen mode Exit fullscreen mode

The BFF holds accessToken, calls getKitToken, and never echoes appSecret.

Deploy notes: HTTPS, Wasm, CDN

HTTPS is not optional in production

Browsers treat mixed content harshly. If the app is https://app.example.com and Wasm or the player script is http://..., load fails. Cookies marked Secure will not attach on HTTP. Use HTTPS on staging that resembles prod. Localhost HTTP is acceptable for a laptop demo; do not use that as the production mental model.

Wasm hosting

ImouPlayer depends on Wasm assets next to (or at a configured) WasmLibPath. Failures look like a black rectangle with “camera offline” in Slack. Check the Network tab for 404 on .wasm / related files, wrong MIME types, or a path that does not match the unzipped SDK.

Rules of thumb:

  • Keep the folder layout from the download package unless you rewrite paths and test.
  • Set WasmLibPath to a URL the browser can GET, not a server-internal disk path.
  • If you put assets on a CDN, either:
    • host the whole player folder as a versioned prefix (https://cdn.example.com/imou/vX/WasmLib/), or
    • same-origin /static/imou/ behind your app CDN with cache keyed on file hash.
  • Avoid HTML pages and Wasm on different sites without a CORS and isolation plan. Same-origin is the boring, correct default.

CDN cache

Fingerprint or version the folder (/static/imou/2026-03/). A long Cache-Control on hashed Wasm is fine; a long cache on imouPlayer.js without a version bump will strand users on an old player. Do not HTML-cache the Live route so aggressively that a token refresh never happens.

Headers (awareness, not a Wasm essay)

Some Wasm setups need cross-origin isolation headers (COOP/COEP or related). If localhost works and production does not, compare response headers and the JS book—not the camera firmware first. This tutorial’s failure mode #1 remains wrong token type and Wasm 404.

SPA routers

Init only when the Live route’s DOM node exists. Destroy when leaving. Frameworks (React/Vue/Svelte) should destroy in useEffect cleanup / onUnmounted. Leaving a player alive in a hidden stack of routes burns CPU and live-view quota.

Quality and quota

Default streamId = 1 (SD) for list previews and multi-tile walls. Use 0 (HD) when the user focuses one camera. Watch live-view quota in My Resources. Capabilities such as PTZ, playback, and talk remain device-dependent; hide buttons until you know the model supports them.

What you are not doing

You are not stuffing a national-standard ingest protocol into the browser. International Open Platform live for web is ImouPlayer + kitToken or HLS/RTMP APIs after server accessToken. You are not putting accessToken in localStorage “for convenience.”

Imou Open Platform provides cloud video and AIoT APIs, SDKs, and low-code pieces so you can ship camera live inside your web app. Create an application at https://open.imoulife.com, then follow JavaScript development and Video Monitoring.

Top comments (0)