Skip to main content
By the end of this quickstart you’ll have a custom Docker container running as a Bring Your Own Container (BYOC) pipeline on a local Livepeer Network, a job routed to it through a Gateway and Orchestrator, and verified output coming back. The path uses a green-tint frame processor (the simplest possible BYOC contract) and -network offchain mode. Once this works, you understand the full BYOC lifecycle; production deployment is the same architecture against a registered Orchestrator with on-chain payment attached. This is the Persona 3 activation moment. The transcoding quickstart proved the Gateway-Orchestrator-pipeline lifecycle; this quickstart plugs arbitrary compute into it. The reference applications live at and the SDK at .

Required Tools

Four things on one Linux amd64 machine:
  • go-livepeer binary or Docker (from the )
  • Docker Engine 24 or later
  • Python 3.10 or later with pip
  • Four free terminals
No GPU, no Arbitrum wallet, no API keys.
This quickstart assumes you completed the or have go-livepeer installed and verified. Run ./livepeer -version to confirm.

Container Build

The simplest BYOC contract is one Python class with one method: receive raw bytes, return raw bytes. PyTrickle wraps that class in an HTTP server speaking the trickle protocol.
1

Create a project directory

2

Write the processor

Save as processor.py. This boosts the green channel on every frame.
Three methods, one required. process() is the only method the contract demands; initialize() and shutdown() are useful for model loading and cleanup.
3

Write the Dockerfile

Save as Dockerfile.
python:3.11-slim keeps the image small. For GPU inference, swap the base to nvidia/cuda:12.x-runtime-ubuntu22.04 and add --gpus all to your docker run commands.
4

Build and verify

The image should show in the list with a latest tag and a recent timestamp.

Container Isolation Test

Before wiring into the network, confirm the container starts cleanly and accepts a frame.
1

Run the container

First terminal:
Expected output:
Leave it running.
2

Hit the status endpoint

Second terminal:
A 200 OK confirms the trickle server is accepting requests. The body shape varies; what matters is the status code.
3

Stop the test container

Container logic verified. Any failure from here is a wiring problem.

Network Wiring

The container is a capability. The Orchestrator advertises that capability to the Gateway. The Gateway routes matching jobs to the Orchestrator, which routes them to the container.
1

Start the BYOC container in host mode

First terminal:
--network host lets the Orchestrator reach the container at localhost:8000. Acceptable for local development; production deployments use a Docker network or Kubernetes service.
2

Start the orchestrator with the BYOC capability

Second terminal:
3

Start the gateway

Third terminal:
-httpIngest enables the HTTP job-submission endpoint used by BYOC jobs.

First Job

1

Send a BYOC job

Fourth terminal. Save as send_job.py:
Run it:
2

Inspect the result

Expected output:
The green-channel sum is non-zero. The job routed through Gateway → Orchestrator → container → Orchestrator → Gateway and back to the client. The container applied its transformation.
3

Watch the orchestrator logs

The Orchestrator terminal shows the BYOC routing path:

Job Lifecycle

The full job lifecycle ran with custom compute in the middle. The only piece off-chain mode skips is the payment envelope; routing and execution are identical to a production Gateway. Four ideas underpin what just happened. Capability. A named identifier (green-tint-cpu) that the Orchestrator advertises and the Gateway routes against. Any unique string works. Production Orchestrators publish their capability set to the on-chain registry. Trickle protocol. The HTTP convention the Orchestrator uses to push frames to the container and pull results back. PyTrickle implements both sides so the processor only writes the process() method. FrameProcessor contract. One required method: process(bytes) -> bytes. Optional initialize() runs once on container start; optional shutdown() runs on job end. Any Python library that runs in the container can be loaded in initialize(). Per-second compute. In on-chain mode, BYOC jobs are paid per second of GPU compute under . Off-chain mode skips payment but exercises the same routing.

Common Errors

The Orchestrator started without the BYOC flags, or the Gateway started before the Orchestrator registered. Confirm the Orchestrator log shows BYOC capability registered: green-tint-cpu. If not, check the -byoc, -byocContainerURL, and -byocModelID flags match what the Gateway expects.
The Orchestrator can’t reach the container. With --network host, the container must bind to 0.0.0.0:8000 and the Orchestrator must use 127.0.0.1:8000. Confirm the container log shows Trickle server listening on port 8000. If using a custom Docker network, the container hostname goes in -byocContainerURL.
The X-Model-Id header doesn’t match any advertised capability. Confirm the header value matches -byocModelID exactly. Capability names are case-sensitive.
The frame size sent to the container doesn’t match what process() expects. Black frames at 640x480x3 = 921600 bytes work with the green-tint processor. For live video, the Gateway negotiates frame format; for direct testing, the bytes-in must match bytes-out.
Kill the conflicting process, or change -byocContainerURL, -httpAddr, and -serviceAddr to free ports.

Next Steps

BYOC Architecture

Trickle protocol, container contract, capability discovery, payment flow.

BYOC Production

Public registry, container hosting, scaling, monitoring.

BYOC SDK

@muxionlabs/byoc-sdk for browser clients with WebRTC streaming.

Per-Second Compute

Pricing, settlement, the production billing model.
For ComfyUI-based real-time pipelines, ComfyStream is already BYOC-compatible. See .
Last modified on May 22, 2026