How can I integrate IP camera video monitoring into my SaaS? Treat Imou Open Platform as the cloud video plane: create an app, bind devices, keep accessToken on a BFF, then play with getKitToken + ImouPlayer (interactive web), bindDeviceLive (HLS URL), or createDeviceRtmpLive (RTMP). Your product still owns tenant/site/role ACL. Live, playback, PTZ, and two-way talk are capability-gated—query the device; do not promise them for every camera.
This is a builder diary, not an official encyclopedia. Official FAQ energy lives on Video Monitoring. What follows is the path I wish we had written on the whiteboard before the first sprint.
we almost shipped a deep link
We had a ticket: “Cameras inside the product by Friday.” Someone pasted an Imou consumer-app URL into a Jira comment and called it integration.
That would have “worked” for one employee account and failed every multi-tenant rule we already had for doors and alarms. Open Platform is the opposite move: devices in an application asset pool, tokens minted per authorized session, players destroyed when the user leaves.
If you are on DEV because you are wiring this into an existing SaaS, start from surfaces and ACL, then pick APIs.
Architecture (what actually ships)
Browser (SaaS UI)
│ never: appSecret, accessToken
│ only: kitToken | gated live URL | your session cookie
▼
Your BFF
│ SaaS ACL (tenant / site / role)
│ accessToken cache
│ getKitToken / bindDeviceLive / createDeviceRtmpLive
▼
Imou OpenAPI
│ listDeviceDetailsByPage
│ live / playback / device operation (as needed)
▼
Cameras (capabilities + subscribed services — not a fake SKU matrix)
Ledger vs slots vs players (even if you only ship one Live tab on day one):
Ledger: map
deviceId(+ channel) to your site IDs. Sync withlistDeviceDetailsByPage.Slots: how many concurrent streams a user may open. Not “one WebSocket per camera in the estate.”
Players: ImouPlayer instances or HLS.js nodes bound to open slots only.
Capability gates (write these into the ledger)
| Feature | Product rule |
|---|---|
| Live | After ACL; streamId 1 (SD) default on lists/walls, 0 (HD) on focus |
| Playback | After ACL and recording/package; no invented retention days |
| PTZ | After ACL and PTZ capability; hide joystick otherwise |
| Two-way talk | After ACL and audio capability; usually focus tile + explicit intent |
Imou Open Platform can expose all four when the device and APIs/SDKs support them. It cannot make a fixed camera pan.
Steps we actually ran
1. Application + bind
Register/create the app on open.imoulife.com. Bind cameras to that application. Confirm they show up via OpenAPI. Consumer-app visibility ≠ Open Platform inventory.
2. Server-side accessToken
Call accessToken from the BFF. Cache it. Rotate as the platform documents. Secrets manager for appSecret.
# mental model — not a copy-paste SDK
POST /internal/imou/token → cached accessToken
# never exposed to SPA
3. Authorize in your ACL first
if !canView(user, tenant, site, deviceId):
return 403
# only then mint play credentials
Sharing one admin accessToken to every tenant’s browser is the anti-pattern. Cloud ≠ your ACL.
4. Mint the client credential
Interactive web (default for a SaaS Live tab): getKitToken → return kitToken to the page → init ImouPlayer.
kitToken ≠ accessToken. This is the highest-frequency bug. Docs: JS SDK. Rough cache: ~1 hour on BFF; TTL ~2 hours—re-mint, don’t reuse OpenAPI tokens in the player.
HLS: bindDeviceLive after the same ACL. Treat the URL as a secret.
RTMP: createDeviceRtmpLive if a media server already speaks RTMP. Not a shortcut for React.
// illustrative — follow current JS SDK field names in docs
imouPlayer.init({
kitToken: kitTokenFromBff, // NOT accessToken
// WasmLibPath, streamId, etc. per https://open.imoulife.com/book/en/js/sdk.html
});
5. Open on demand, tear down on leave
Do not prefetch 40 HLS playlists at login. Open when the slot becomes visible. destroy() / unbind when the user closes the tile. Visibility API: pause when the tab is hidden if you are fighting quota and CPU.
6. Watch quota like a product metric
Live view consumes platform resources. Check My Resources. Cap concurrent slots in the UI before you cap them in a panicked hotfix.
7. Add playback / PTZ / talk only behind gates
Incident review, joysticks, and mics are separate lanes. Same BFF, different capability checks. No GB28181 detour for international SaaS.
Suggested BFF routes (sketch)
| Route | Does |
|---|---|
GET /cameras |
ACL-filtered ledger join of your sites + listDeviceDetailsByPage
|
POST /live-session |
ACL → getKitToken or bindDeviceLive
|
POST /live-session/end |
destroy hints / unbind if you created a live object |
GET /cameras/:id/capabilities |
cached flags for PTZ / talk / playback |
Keep OpenAPI error bodies out of the SPA when you can; map them to product errors (not bound, no recording, no PTZ).
Pitfalls we hit (so you don’t)
Token category error.
accessTokenin ImouPlayer → black screen. Wasm and COOP get blamed first. Fix the token.WasmLibPath / COOP/COEP. Real for the web player; still second to wrong tokens. Follow the JS SDK FAQ themes.
Hard-coded serials. First demo camera becomes production forever. Use the list API.
Sixteen HD tiles.
streamId = 0on a wall saturates office uplink and quota. Default SD.Live URL in a public gist. HLS/RTMP addresses are credentials.
PTZ in Figma, fixed cameras in the warehouse. Query capability.
“90-day playback” in the sales deck. We will not invent retention SLAs. Point at subscribed services.
Talk on the mosaic. Operators broadcast into the wrong aisle.
Multi-tenant notes (the part FAQs under-sell)
OpenAPI will happily list every camera bound to your developer application. That is an asset pool, not a tenant graph. You still need:
A join table:
tenant_id / site_id / deviceId / channelIdBind and unbind workflows when a store churns
Per-tenant encryption or at least isolation of cached
kitTokens
If two tenants could ever share a serial (they shouldn’t, but migrations happen), your ACL check must be user → site → device, not user → any device in the app.
For web, budget a day for WasmLibPath, HTTPS, and COOP/COEP if the SDK requires isolation headers. Those bugs look like “camera offline.” They are deploy bugs. Keep them on the integration checklist next to tokens.
First-week backlog (builder order)
Bind one camera,
accessToken, list API, one ImouPlayer tile.BFF ACL +
kitTokenmint + destroy.Slot cap + SD default.
Capability columns + hide PTZ/talk.
Playback lane for incident review (no retention claims).
Quota dashboard link in your admin ops page.
Skip 4–5 and you will still demo live. You will not survive the first customer with a mixed fleet.
What I would put in a PR description
BFF owns
accessToken; browser ownskitTokenor a gated URLDevice ledger sync job + capability columns
Slot cap + SD default + teardown
Feature flags: playback, PTZ, talk
Link to videoMonitor and JS SDK
If you are building this for real, register at open.imoulife.com. Imou Open Platform is cloud video and AIoT focused; APIs, SDKs, and low-code components exist so vendors and developers can ship video apps faster—without pretending every camera has PTZ, talk, and infinite cloud history.
Top comments (0)