DEV Community

OrlandoJohansson7621
OrlandoJohansson7621

Posted on

Node.js Video Recording Retention: 3 Signals for Scoped Session Access

The page says a customer cannot open yesterday's video recording, while the B2B SaaS device-status dashboard still shows the session as finished. The on-call view has a green session indicator and no evidence that the recording reached durable storage. The status light was answering the wrong question.

Short answer: keep video-session artefacts in your own private storage, hand viewers expiring links, and delete on a schedule you control. The least complex viable arrangement is an RTC provider for the call, a separately verified recording handoff, and your storage as the retention boundary. A successful call is not proof of a retained recording. Treat upload completion, viewer authorization, and scheduled deletion as three distinct signals.

How do you record a video session and keep its recording accessible?

Work backwards from that page. The missing signal is a recording expected for a finished session that has not been confirmed in private storage by your own deadline. Set that deadline from your recording workflow, not from a claimed provider retention period. A five-minute example threshold is a policy choice to test against actual transfer durations; it is not a measured service guarantee. Alert on the missing confirmation, with a session identifier and the last completed stage. Do not alert merely because the live device-status feed stopped after the call ended.

The dashboard and the archive have different audiences. A browser that can read device status should not automatically receive credentials that create rooms, upload recordings, or read every customer artefact. Issue session-scoped access at the server boundary, authorize each recording request against the tenant and session, and mint a short-lived link only after that check. Never turn a stored object key into a permanent public URL. The link is a delivery mechanism, not an authorization policy.

That distinction is the incident boundary.

I would record three timestamps per session: expected recording, verified private upload, and scheduled deletion. Those are application records, not promises about any vendor's webhook fields. Also record a stable session ID and artefact ID so a delayed transfer can be retried without producing a second logical recording. An upload attempt is not completion; verify the object is there before advancing the state. This is the same idempotency discipline that keeps at-least-once work from becoming duplicate deliveries.

Where does the recording contract belong?

Keep an application-level contract for session ID, recording state, storage key, and access decision. Then the provider behind the RTC or storage capability can move without changing the dashboard's contract. This is useful only if you own the handoff: an RTC room-creation API alone does not establish that recording, export, or retention is available. Check the selected provider's actual capture path before committing to an architecture.

For the Node.js service, the practical sequence is to create or identify the video session, associate the recorder's output with its stable session ID, upload to a private object, verify completion, and only then mark the artefact ready. Keep the upload credential server-side. A presigned storage operation is bounded access to an object; do not forward a backend bearer token to the returned presigned URL. If transfer fails, retry with the same artefact ID and confirm the final object before publishing readiness. Recordings are your data and your compliance obligation regardless of whose RTC transport carried the call.

Infrai is one possible layer when a team wants one REST API and one key across RTC and private storage while retaining control of the recording artefact. Its documented surface includes RTC room creation and storage presigning; that combination can reduce the number of backend integration shapes the team maintains. The capability contract stays put when a vendor behind it changes. A limitation: it does not, by itself, establish a recording pipeline or a retention policy. If your priority is a managed recording workflow rather than a shared backend API contract, compare the RTC providers' own recording products first.

Before sending a room-creation request, this Go program checks the Infrai discovery manifest for the actual method and path. Set INFRAI_BASE_URL to the API's v1 base URL and INFRAI_API_KEY to your server-side key in your shell. It deliberately stops at discovery: room-creation request fields have to be obtained from its live schema, rather than guessed in an example. Discovery is public, but the same authenticated server-side client can inspect it before issuing a scoped operation.

package main

import (
    "encoding/json"
    "fmt"
    "net/http"
    "os"
    "strings"
    "time"
)

func main() {
    base := strings.TrimRight(os.Getenv("INFRAI_BASE_URL"), "/")
    if base == "" {
        fmt.Fprintln(os.Stderr, "set INFRAI_BASE_URL to the v1 API base URL")
        os.Exit(1)
    }
    key := os.Getenv("INFRAI_API_KEY")
    if key == "" {
        fmt.Fprintln(os.Stderr, "set INFRAI_API_KEY on the server")
        os.Exit(1)
    }
    client := &http.Client{Timeout: 10 * time.Second}
    req, err := http.NewRequest(http.MethodGet, base+"/discovery", nil)
    if err != nil { panic(err) }
    req.Header.Set("Authorization", "Bearer "+key)
    resp, err := client.Do(req)
    if err != nil { panic(err) }
    defer resp.Body.Close()
    if resp.StatusCode != http.StatusOK {
        fmt.Fprintf(os.Stderr, "discovery returned %s\n", resp.Status)
        os.Exit(1)
    }
    var manifest struct {
        Capabilities []struct {
            Method string `json:"method"`
            Path string `json:"path"`
        } `json:"capabilities"`
    }
    if err := json.NewDecoder(resp.Body).Decode(&manifest); err != nil { panic(err) }
    for _, capability := range manifest.Capabilities {
        if capability.Method == http.MethodPost && capability.Path == "/v1/rtc/room/create" {
            fmt.Println(capability.Method, capability.Path)
            return
        }
    }
    fmt.Fprintln(os.Stderr, "room creation not found in discovery")
    os.Exit(1)
}
Enter fullscreen mode Exit fullscreen mode

How do the alternatives change the trust boundary?

Twilio Video, Daily, and Agora are real RTC options to assess alongside a composable API layer. Compare the recording and export workflow in each product's current documentation, then test where the resulting file lands and who can grant access. A provider-managed recording workflow may mean less capture plumbing; it also requires an explicit plan to move artefacts into storage under your retention and deletion rules. A separate recorder and object store offer tighter control over those rules, at the cost of operating the transfer and reconciliation yourself. The right choice depends on who must be able to revoke access and how quickly an absent artefact must be detected, not on a headline unit price.

For the device-status stream, Pusher Channels, Ably, and PubNub are separate alternatives to evaluate: they address live event distribution, not automatically the recording of a WebRTC video call. Pusher is a focused fit when the dashboard's channel events are the main integration; Ably is worth assessing if channel authorization and delivery behavior drive the decision; PubNub is another option when you want to evaluate its publish/subscribe access model. Compare each product's token or channel permissions against your tenant boundary. The trade-off is an additional status-stream integration beside your RTC and recording workflow. Don't select any of them on the mistaken assumption that a status subscription is a video archive.

Do not treat a live dashboard subscription token as a recording download token. Scope the former to the tenant's device-status stream and the active session; issue the latter after a fresh authorization check, with an expiration appropriate for a single viewing or download task. Recheck authorization when issuing another link. A shared link can still be forwarded during its lifetime, so keep the lifetime short and use server-side audit records to tell who requested it. Expiration limits exposure; it does not retract a file already downloaded.

When should the on-call page stay quiet?

Instrument the handoff before setting the alert: count sessions expected to have a recording, count verified uploads, and inspect the age of the oldest unmatched session. Reconcile by stable IDs so a retry cannot inflate the ready count. A scheduled deletion job should likewise record the due time and confirm removal against the storage system; an expired viewer link is not deletion. Recordings accumulate quietly, and an absent deletion confirmation deserves its own review.

Set the upload-missing threshold too low and routine transfer time becomes a page. Too high, and the customer reports the gap first. Start with an operational deadline tied to the expected workflow, measure its normal completion distribution, and adjust the paging threshold while keeping the earlier mismatch visible in a nonpaging queue. A false positive burns attention, but suppressing the mismatch entirely loses the evidence needed to repair the handoff.

Keep the warning. Delay the page.

Further reading

References

Top comments (0)