> For the complete documentation index, see [llms.txt](https://docs.eyepop.ai/developer-documentation/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.eyepop.ai/developer-documentation/deployment/connecting-eyepop.ai-cloud-ai-to-video-behind-a-firewall.md).

# Connecting EyePop.ai Cloud AI to Video Behind a Firewall

**Document type:** Reference architecture (integration patterns and their trade-offs). This is not a step-by-step deployment guide; each pattern carries an integration note describing what EyePop provides versus what the customer builds.

**Intended readers:** IT and security decision-makers evaluating EyePop, and the architects or integrators who would implement the chosen pattern.

***

### Introduction — for IT and security decision-makers

While EyePop offers both cloud and on-premise deployment options, many customers choose the cloud deployment model to avoid deploying and maintaining dedicated AI infrastructure on-site. In this architecture, inference runs on EyePop-operated cloud infrastructure, where customers configure an inference workload (a “Pop”) and send video for analysis.

This architecture applies when the video sources — security cameras, NVRs, or other video resources — reside on a private network behind a firewall that permits no inbound connections. EyePop supports this deployment through three integration patterns. The patterns differ in who builds the integration and in how video travels from the private network to the cloud; they share the same security model and the same result-delivery model.

Three facts define how the architecture operates:

1. **Inference is cloud-side, and encoded video leaves the premises.** EyePop performs analysis in the cloud, so encoded video is transmitted off-premise over the encrypted channels described below. The architecture does not perform on-site inference.
2. **No inbound firewall ports are required.** Every pattern is initiated by an outbound connection from inside the network, or carried over a mutually authenticated VPN overlay.
3. **Video is encrypted in transit, and no video is retained.** Video is transmitted to EyePop over encrypted channels for inference, processed in-memory, not retained after processing, and not used to train shared AI models. Customers receive only structured prediction results in machine-readable JSON format.

***

### 2. Typical deployment requirements and how EyePop addresses them

Deployments that connect private-network video to a cloud service share a common set of requirements. EyePop provides a solution for each.

| Typical requirement                                             | EyePop's solution                                                                                                                                                                                                    |
| --------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| The firewall is not opened for inbound traffic.                 | All connectivity is initiated outbound from inside the network, or carried over a mutually authenticated VPN overlay. No port-forwarding or inbound NAT is used.                                                     |
| Video is protected whenever it crosses a network boundary.      | Video is encrypted in transit using TLS or WireGuard. Video is processed for inference, not retained after processing, not used to train shared AI models, and customers receive only structured prediction results. |
| The solution works with existing camera and VMS infrastructure. | Three integration patterns accommodate VMS plugins, standalone connectors, and direct VPN access to RTSP/ONVIF sources.                                                                                              |

Because inference is performed in the EyePop cloud, encoded video is transmitted off-premise over the encrypted channels above; the architecture does not perform on-site inference.

#### High-level context

```mermaid
flowchart LR
  subgraph CN["Customer network (private, outbound-only)"]
    CAM["IP cameras / NVR<br/>RTSP or ONVIF"]
    COMP["Integration component<br/>(plugin, connector, or control client)"]
    CAM --> COMP
  end
  FW{{"Firewall<br/>outbound TCP/443 or VPN only<br/>no inbound ports"}}
  subgraph EC["EyePop cloud"]
    SESS["Per-camera session<br/>runs the configured Pop"]
  end
  COMP -- "encrypted, outbound" --> FW
  FW --> SESS
  SESS -- "JSONL predictions" --> FW
  FW --> COMP
```

<br>

***

### 3. The three integration patterns

|                             | (a) VMS plugin                                              | (b) On-prem connector                        | (c) Tailscale (managed)                                           |
| --------------------------- | ----------------------------------------------------------- | -------------------------------------------- | ----------------------------------------------------------------- |
| **Video flow**              | Push, outbound                                              | Push, outbound                               | Pull — the cloud worker reads the camera over a VPN               |
| **What carries the video**  | The plugin                                                  | The connector                                | The encrypted tailnet (camera to cloud worker, directly)          |
| **Runs inside the network** | A plugin within the customer's VMS                          | A customer-built service                     | A thin control client and a tailnet node                          |
| **EyePop SDK call**         | `upload_stream()`                                           | `upload_stream()`                            | `load_from(rtsp://…)`                                             |
| **Transport**               | HTTPS/443, chunked MPEG-TS                                  | HTTPS/443, chunked MPEG-TS                   | RTSP over a WireGuard mesh                                        |
| **Customer builds**         | Nothing — configuration and deployment only                 | The connector                                | A thin control client                                             |
| **EyePop provides**         | The custom VMS plugin and the Python SDK                    | The Python SDK                               | VPN setup and the managed engagement                              |
| **Integration**             | EyePop provided custom VMS plugin                           | Customer managed relay code                  | Custom engagement                                                 |
| **Best fit**                | A VMS already manages the camera feeds and supports plugins | No VMS, or a custom integration is preferred | Network configuration only, no dependency on VMS or other systems |

All three patterns deliver results the same way: predictions return to the SDK client as `application/jsonl` (one JSON object per line). The customer's code decides what to do with each result — for example raising an alarm, creating a bookmark in the VMS, or forwarding the result to another system. With inference cloud-side and no server-side history component in this architecture, persistence of results is the customer's responsibility.

#### Choosing a pattern

```mermaid
flowchart TD
  Q1{"Policy: must video never<br/>leave the network?"}
  Q1 -- "Yes" --> STOP["This architecture does not apply.<br/>Cloud inference requires video egress."]
  Q1 -- "No" --> Q2{"Is there a VMS with a<br/>plugin runtime managing the feeds?"}
  Q2 -- "Yes" --> PA["Pattern (a)<br/>VMS plugin"]
  Q2 -- "No" --> Q3{"Push video out,<br/>or let EyePop pull it over a VPN?"}
  Q3 -- "Push" --> PB["Pattern (b)<br/>On-prem connector"]
  Q3 -- "Pull / managed" --> PC["Pattern (c)<br/>Tailscale (managed)"]
```

#### Pattern (a) — VMS plugin

A plugin runs inside a Video Management System that exposes live frames and a plugin runtime. The plugin holds the EyePop session, encodes the feed as MPEG-TS, and streams it to the cloud with `upload_stream()`. Predictions return on the same connection, where the plugin can act on them inside the VMS. The pattern is vendor-neutral and applies to any VMS with a live-frame plugin API. EyePop provides the plugin as a custom component for the target VMS; the customer configures and deploys it within their VMS.

```mermaid
flowchart LR
  subgraph CN["Customer network"]
    CAM["Cameras"] --> VMS["VMS"]
    VMS --> PLUG["EyePop VMS plugin<br/>holds the session<br/>encodes MPEG-TS"]
  end
  subgraph EC["EyePop cloud"]
    SESS["Session (one per camera)<br/>runs the Pop"]
  end
  PLUG -- "upload_stream · MPEG-TS · HTTPS/443" --> SESS
  SESS -- "JSONL predictions" --> PLUG
  PLUG -- "bookmarks / events / alarms" --> VMS
```

#### Pattern (b) — On-prem connector

The customer builds and hosts a standalone connector — for example a container on an on-premise host. The connector reads local RTSP, transcodes to MPEG-TS, and pushes the stream with `upload_stream()`. The transport is identical to pattern (a); the difference is that the connector is a standalone service rather than code embedded in a VMS. EyePop provides the Python SDK; the connector is customer-developed.

```mermaid
flowchart LR
  subgraph CN["Customer network"]
    CAM["Cameras"] --> CONN["On-prem connector<br/>reads RTSP<br/>transcodes to MPEG-TS"]
  end
  subgraph EC["EyePop cloud"]
    SESS["Session (one per camera)<br/>runs the Pop"]
  end
  CONN -- "upload_stream · MPEG-TS · HTTPS/443" --> SESS
  SESS -- "JSONL predictions" --> CONN
  CONN -- "forward to downstream system" --> DS["Customer application"]
```

#### Pattern (c) — Tailscale (managed engagement)

EyePop and the customer establish a Tailscale tailnet (a WireGuard mesh) that joins the cloud session to the camera subnet. A thin on-premise SDK control client drives the session — it calls `set_pop` and `load_from(rtsp://<camera-on-tailnet>)`, then consumes predictions. The video travels directly from the camera to the cloud worker over the encrypted mesh; the control client issues control commands and receives results but does not carry the video. This minimizes the customer's application code at the cost of a higher-touch setup, which is why it is delivered as a managed engagement.

```mermaid
flowchart LR
  subgraph CN["Customer network"]
    CAM["Cameras (RTSP)"]
    CTRL["Thin SDK control client"]
  end
  subgraph EC["EyePop cloud"]
    SESS["Session worker<br/>joined to the tailnet"]
  end
  CTRL -- "set_pop()<br/>load_from()" --> SESS
  CAM -. "Video over WireGuard mesh" .-> SESS
  SESS -- "JSONL predictions" --> CTRL
```

***

### 4. Transport mechanics (patterns a and b)

The push patterns use the EyePop Python SDK method `WorkerEndpoint.upload_stream(stream, mime_type)`. For a `video/*` MIME type the SDK establishes a full-duplex exchange over two concurrent, long-lived HTTPS connections:

```mermaid
sequenceDiagram
  participant C as On-prem client
  participant S as EyePop session (cloud)
  C->>S: POST prepareSource (HTTPS/443)
  S-->>C: source_id (JSONL event: prepared)
  par Upload connection
    C->>S: POST source?sourceId=… (chunked MPEG-TS request body)
  and Download connection
    S-->>C: application/jsonl predictions (streamed, one per line)
  end
  Note over C,S: Connections are open-ended (sock_read 600s),<br/>sized for indefinite live streams.
```

**Encoding.** H264 in an MPEG-TS container (`Content-Type: video/mp2t`) is the format EyePop ingests for live media.

> **Network requirement.** Each camera uses two concurrent, long-lived HTTPS/443 connections, one of which streams a chunked request body. Forward proxies that buffer request bodies, terminate idle connections, or cap connection lifetime will interrupt the stream. Permit direct outbound 443 to the EyePop session endpoints, or use a proxy that streams request bodies without buffering.

***

### 5. Sessions, lifecycle, and failure behavior

* **One persistent session per camera (default).** Each camera maps to its own session and a single streaming job. This isolates failures — one camera disconnecting does not affect another — and keeps reconnection logic simple. The trade-off is one session, and one cloud worker, per camera; plan capacity accordingly (Section 7).
* **Reconnection is handled on-premise.** *(To confirm during scoping.)* When the uplink interrupts or a cloud worker restarts, the on-premise client retries and re-attaches to the same persistent session. Each deployment defines a backoff interval and a maximum acceptable gap.
* **Results are not persisted by EyePop in this architecture.** Predictions are delivered to the SDK client as they are produced. Storing or forwarding them is the customer's responsibility.

***

### 6. Security and compliance summary

| Topic                 | Position                                                                                                                                                                                                                                                |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| In-transit encryption | TLS over HTTPS/443 for patterns (a) and (b); a WireGuard mesh for pattern (c). No cleartext video on any path.                                                                                                                                          |
| Inbound exposure      | None. All paths are outbound-initiated or use a mutually authenticated overlay. No inbound firewall ports.                                                                                                                                              |
| Authentication        | An EyePop API key authorizes each session. Per-camera sessions provide per-camera credential boundaries.                                                                                                                                                |
| RTSP credentials      | In patterns (a) and (b), camera credentials remain on-premise within the plugin or connector. In pattern (c), the cloud worker uses them over the tailnet; the tailnet ACL is the trust boundary.                                                       |
| VPN scope (pattern c) | *(To confirm during scoping.)* Tailnet ACLs are restricted to the specific camera addresses or subnet rather than the whole network. Ephemeral authorization keys are recommended so the session node joins for the session and is removed on teardown. |
| Data residency        | *(To confirm.)* Whether sessions can be pinned to a specific region.                                                                                                                                                                                    |
| Frame retention       | Frames are processed in-memory for inference and discarded immediately after; no frame data is retained, and frames are not used to train shared AI models.                                                                                             |
| Returned data         | Structured JSONL predictions only; never video.                                                                                                                                                                                                         |

***

### 7. Capacity planning *(illustrative; not a service-level commitment)*

Cloud inference produces continuous outbound egress from the customer's uplink, approximately `cameras × per-stream bitrate`, sustained.

| Resolution | Typical H264 bitrate | Suggested analytics frame rate |
| ---------- | -------------------- | ------------------------------ |
| 720p       | \~1–2 Mbps           | 2–10 fps                       |
| 1080p      | \~2–4 Mbps           | 2–10 fps                       |

For example, 16 cameras at 1080p and 2 Mbps is approximately 32 Mbps of sustained upload, plus 16 connection pairs. Reducing the frame rate to the analytics requirement before transmission (through the encoder configuration) lowers both egress and cloud cost; full sensor frame rates are generally not required for detection. EyePop will provide committed per-camera and per-session limits during scoping.

> **Note on the `fps` parameter.** The `fps` argument on `upload_stream()` controls the rate at which the cloud session samples frames for inference — the full encoded stream is still uploaded, so it reduces inference cost but does *not* reduce upload bandwidth. To save bandwidth, lower the frame rate (or bitrate) at the encoder, before the stream leaves the network.

***

### 8. Operational ownership

| Responsibility                   | (a)                                          | (b)      | (c)                                        |
| -------------------------------- | -------------------------------------------- | -------- | ------------------------------------------ |
| Build the integration            | EyePop (plugin) and customer (configuration) | Customer | EyePop (VPN) and customer (control client) |
| Operate the on-premise component | Customer                                     | Customer | Customer                                   |
| Operate the cloud session        | EyePop                                       | EyePop   | EyePop                                     |
| Reconnect and retry              | Customer                                     | Customer | Customer                                   |
| Consume and store predictions    | Customer                                     | Customer | Customer                                   |
| Monitor stream health            | Customer                                     | Customer | Customer                                   |

***

### 9. Items confirmed during a scoping engagement

1. Reconnection policy and recommended backoff and maximum-gap values (Section 5).
2. Tailscale node lifecycle and ACL scope for pattern (c) (Section 6).
3. Committed per-camera bitrate, resolution, and frame-rate envelope, and per-session camera limits (Section 7).
4. Data residency and frame-retention positions (Section 6).
5. API-key scoping and rotation policy (Section 6).

***

### Appendix A — Reference push example (patterns a and b)

```
# On-premise: push one camera's MPEG-TS feed to a per-camera EyePop session.
from eyepop import EyePopSdk

with EyePopSdk.sync_worker() as endpoint:      # one session per camera
    endpoint.set_pop(pop)                      # the configured Pop
    job = endpoint.upload_stream(
        stream=mpegts_byte_stream,             # readable MPEG-TS of the H264 feed
        mime_type="video/mp2t",
    )
    while result := job.predict():             # JSONL predictions, one per processed frame
        handle(result)                         # alarm, bookmark, or forward
```

### Appendix B — Reference pull example (pattern c)

```
# On-premise control client: direct the cloud worker to a camera reachable over the tailnet.
from eyepop import EyePopSdk

with EyePopSdk.sync_worker() as endpoint:
    endpoint.set_pop(pop)
    job = endpoint.load_from("rtsp://<camera-tailnet-address>/stream")  # worker reads over the mesh
    while result := job.predict():
        handle(result)
```

### Appendix C — Glossary

* **Pop** — the EyePop inference configuration (models and processing components) applied to a session.
* **Session** — a cloud worker instance running a Pop; one per camera in this architecture.
* **MPEG-TS** — MPEG transport stream, the H264 container EyePop ingests for live media (`video/mp2t`).
* **Tailnet** — a Tailscale WireGuard mesh network that connects devices across firewalls and NATs.
* **JSONL** — newline-delimited JSON; the format of prediction results.
* **RTSP / ONVIF** — standard protocols for streaming and discovering IP camera video.
