Camera events. With the footage.

Connect your app to Ring, Arlo, Tapo, Reolink, Ubiquiti UniFi, and Hikvision. Bring camera activity, available recordings, and live video into one interface.

Camera events and recordings. Across brands.

Build camera experiences across Ring, Arlo, Tapo, Reolink, Ubiquiti UniFi, and Hikvision. Add motion alerts and available recordings to your app through a common API.

  • Motion events and Ring doorbell presses

  • Recorded clips and thumbnail images

  • Events in a common webhook format

  • Cloud recordings and local media via Seam Bridge

  • Live view inside your app

Explore the camera guides

See what triggered the event. Receive motion alerts and retrieve the footage.

A moment of motion becomes a webhook, then a clip in your app. Follow the event from the camera to the recording.

Behind the scenes
  1. Next: Detect motion
  2. Next: Receive event
  3. Next: Retrieve media
Webhook listenerPOST /webhooks/seam
Listening

Illustrative camera demo with a white security camera. Waiting for motion.

seam media get \
  --media-id $MEDIA_ID

Live view in your app. Beside the event history.

Show a live view from Ring, Arlo, and Tapo cameras next to each camera's recent events and their media. Video plays over WebRTC in a standard video element, one viewer per camera at a time.

Shipping yardTapo

Optional audio

Recent eventsShipping yard

  1. Motion · Todaycamera.activated
    Media
    media_ids[0]
    videoavailable
    media_ids[1]
    imageavailable
  2. Motion · Todaycamera.activated
    Media
  3. Motion · Todaycamera.activated
    Media
  4. Motion · Yesterdaycamera.activated
    Media

Pair what happened. With who was there.

Cameras and locks share one event stream. Show the clip next to the unlock it explains, check the door before a remote unlock, or send a Ring doorbell snapshot to the front desk.

Explore access control

Connect local cameras. With Seam Bridge.

Tapo cameras stay on the property's network. Seam Bridge connects them to your workspace, so their events, clips and live view use the same API as every other camera.

Explore Seam Bridge

Runs on

A few lines of code. Camera events across brands.

Find connected cameras, read their activity, retrieve the media behind each event, and open a live view.

Find your cameras

List camera devices connected to your workspace, across supported providers. Each one says whether it can stream live video.

Explore camera devices
1import { Seam } from "seam"
2
3const seam = new Seam() // Reads SEAM_API_KEY.
4const cameras = await seam.devices.list({
5  device_types: ["ring_camera", "arlo_camera", "tapo_camera"],
6})
7
8for (const camera of cameras) {
9  console.log(camera.display_name, camera.can_stream_live_video)
10}

Read camera activity

Retrieve motion and Ring doorbell events, or subscribe to webhooks for updates as they happen. Events can include media IDs for the captured clips and images.

Explore camera events
1import { Seam } from "seam"
2
3const seam = new Seam() // Reads SEAM_API_KEY.
4const events = await seam.events.list({
5  device_id: "9b31d4c0-8f2a-4ce6-9d17-4a65c92e0b38",
6  event_types: ["camera.activated", "device.doorbell_rang"],
7  since: new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString(),
8})
9
10for (const event of events) {
11  console.log(event.event_type, "media_ids" in event ? event.media_ids : [])
12}

Webhook payload excerpt

1{
2  "event_type": "camera.activated",
3  "device_id": "9b31d4c0-8f2a-4ce6-9d17-4a65c92e0b38",
4  "activation_reason": "motion_detected",
5  "media_ids": [
6    "01a0d985-621c-7b3e-9f2d-4a5b6c7d8e9f",
7    "01a0d985-621c-7c4f-8a3e-5b6c7d8e9f0a"
8  ]
9}

Retrieve clips and images

Use a media ID from the event to request its recording or thumbnail. When available, the response includes a short-lived signed URL, or add format=redirect to get a 302 straight to the file.

Events can arrive before a recording is ready. Retry pending media with backoff until it becomes available, unavailable, or failed.

Read the media guide
1import { Seam } from "seam"
2
3const seam = new Seam() // Reads SEAM_API_KEY.
4const media = await seam.media.get({
5  media_id: "01a0d985-621c-7b3e-9f2d-4a5b6c7d8e9f",
6})
7
8// The url expires within minutes. Call again for a fresh one.
9if (media.status === "available") console.log(media.url)

Open a live view

On your server, check the camera's can_stream_live_video flag and create a client session for that user. Your API key never leaves your backend.

Stream live video
1// On your server.
2import { Seam } from "seam"
3
4const seam = new Seam() // Reads SEAM_API_KEY.
5const camera = await seam.devices.get({
6  device_id: "9b31d4c0-8f2a-4ce6-9d17-4a65c92e0b38",
7})
8
9if (camera.can_stream_live_video) {
10  const { token } = await seam.clientSessions.create({
11    connected_account_ids: [camera.connected_account_id],
12  })
13  // Send token to the browser.
14}

Play it in the browser

With the client session token from your server, the browser creates the live view, sends its WebRTC offer, and stops the live view when the viewer closes.

Browser
1import { SeamHttp } from "@seamapi/http"
2
3// clientToken is from your server; video and closeButton are on your page.
4const { liveViews } = SeamHttp
5  .fromClientSessionToken(
6    clientToken,
7  ).cameras
8const { camera_live_view_session_id, token } =
9  await liveViews.create({ device_id: "9b31d4c0-8f2a-4ce6-9d17-4a65c92e0b38" })
10const ids = { camera_live_view_session_id, token }
11
12const peer = new RTCPeerConnection()
13peer.addTransceiver("video", { direction: "recvonly" })
14peer.ontrack = (e) => (video.srcObject = e.streams[0])
15await peer.setLocalDescription()
16
17const { sdp_answer } = await liveViews.offer({
18  ...ids,
19  sdp_offer: peer.localDescription.sdp,
20})
21await peer.setRemoteDescription({ type: "answer", sdp: sdp_answer })
22
23closeButton.onclick = async () => {
24  peer.close()
25  await liveViews.stop(ids)
26}

What each brand supports. During the public beta.

Cameras are devices in your workspace, with the same connected accounts, events and webhooks you already use for locks and thermostats. Your users connect them in Connect Webview: set provider_category to cameras to show camera providers.

Camera connection methods and capabilities by brand, during the public beta
BrandRing guideArlo guideTapo guide
Connects throughRing partner pairingThe user links Ring through the Ring App Store.Arlo cloudArlo email and password, then an SMS or email code.Seam BridgeOn the local network, with a Camera Account set up in the Tapo app.
Motion eventscamera.activatedYesYesYes
Doorbell pressesdevice.doorbell_rangYesNoNo
Clips and thumbnails/media/getYes1Yes2From microSD3
Live viewcan_stream_live_videoYes5Yes4Yes4
  1. Ring clips and thumbnails need an active Ring Protect subscription.
  2. Arlo clips need an Arlo subscription that includes cloud recording.
  3. Tapo clips come from the camera's microSD card, with recording turned on. They also need the password for the Tapo app, entered in the optional Tapo account password field when the camera is connected. This is separate from the Camera Account. Third-Party Compatibility must also be on in the Tapo app, under Me > Tapo Lab.
  4. Live view can include audio on both brands. Set include_audio when you create the live view.
  5. Ring live view sessions last up to 30 seconds on battery-powered cameras or 60 seconds on wired cameras. Check can_stream_live_video on the device before offering live view.

Bring cameras into your app. Start with Seam.

Cameras are in public beta and available in every workspace. Request and response shapes may change before general availability; we announce changes in the changelog.

Smart Locks
Access Systems
Knowledge
Lock Capabilities
Thermostats
Sensors
© 2026 Seam Labs, Inc.