> ## Documentation Index
> Fetch the complete documentation index at: https://docs.livepeer.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Gateway Capabilities

> What gateways can route, how they select orchestrators, and the workload types they support across video, AI, and custom pipelines.

export const CenteredContainer = ({children, maxWidth = "800px", padding = "0", preset = "default", width = "", minWidth = "", marginRight = "", marginBottom = "", textAlign = "", style = {}, className = "", ...rest}) => {
  const presets = {
    default: {},
    fitContent: {
      width: "fit-content",
      minWidth: "fit-content"
    },
    readable70: {
      width: "70%",
      minWidth: "fit-content"
    },
    readable80: {
      width: "80%",
      minWidth: "fit-content"
    },
    readable90: {
      width: "90%"
    },
    wide900: {
      maxWidth: "900px"
    }
  };
  const presetStyle = presets[preset] || presets.default;
  return <div className={className} style={{
    maxWidth: presetStyle.maxWidth || maxWidth,
    margin: "0 auto",
    padding: padding,
    ...presetStyle.width ? {
      width: presetStyle.width
    } : {},
    ...presetStyle.minWidth ? {
      minWidth: presetStyle.minWidth
    } : {},
    ...width ? {
      width
    } : {},
    ...minWidth ? {
      minWidth
    } : {},
    ...marginRight ? {
      marginRight
    } : {},
    ...marginBottom ? {
      marginBottom
    } : {},
    ...textAlign ? {
      textAlign
    } : {},
    ...style
  }} {...rest}>
      {children}
    </div>;
};

export const CustomDivider = ({color = "var(--lp-color-border-default)", middleText = "", spacing = "default", style = {}, className = "", ...rest}) => {
  const spacingPresets = {
    default: {
      margin: "24px 0"
    },
    overlap: {
      margin: "-1rem 0 -1rem 0"
    },
    tight: {
      margin: "0 0 -1rem 0"
    },
    section: {
      margin: "0 0 -2rem 0"
    },
    sectionOverlap: {
      margin: "-1rem 0 -2rem 0"
    },
    deepOverlap: {
      margin: "-1rem 0 -1.5rem 0"
    }
  };
  const spacingStyle = spacingPresets[spacing] || spacingPresets.default;
  return <div role="separator" aria-orientation="horizontal" className={className} style={{
    display: "flex",
    alignItems: "center",
    ...spacingStyle,
    fontSize: style?.fontSize || "16px",
    height: "fit-content",
    ...style
  }} {...rest}>
      <span style={{
    marginRight: "var(--lp-spacing-px-8)",
    opacity: 0.2
  }}>
        <Icon icon="/snippets/assets/logos/Livepeer-Logo-Symbol-Theme.svg" />
      </span>
      <div style={{
    flex: 1,
    height: "1px",
    background: "var(--lp-color-border-default)",
    opacity: 0.4
  }}></div>
      {middleText && <>
          <Icon icon="circle" size={2} />
          <span style={{
    margin: "0 8px",
    fontWeight: "bold",
    color: color,
    opacity: 0.7
  }}>
            {middleText}
          </span>
          <Icon icon="circle" size={2} />
        </>}
      <div style={{
    flex: 1,
    height: "1px",
    background: "var(--lp-color-border-default)",
    opacity: 0.4
  }}></div>
      <span style={{
    marginLeft: "var(--lp-spacing-px-8)",
    opacity: 0.2
  }}>
        <span style={{
    display: "inline-block",
    transform: "scaleX(-1)"
  }}>
          <Icon icon="/snippets/assets/logos/Livepeer-Logo-Symbol-Theme.svg" />
        </span>
      </span>
    </div>;
};

export const TableCell = ({children, align = "left", header = false, style = {}, className = "", ...rest}) => {
  const Component = header ? "th" : "td";
  return <Component className={className} style={{
    padding: "0.75rem 1rem",
    textAlign: align,
    border: header ? "none" : "1px solid var(--lp-color-border-default)",
    ...style
  }} {...rest}>
      {children}
    </Component>;
};

export const TableRow = ({children, header = false, hover = false, style = {}, className = "", ...rest}) => {
  const rowId = `table-row-${Math.random().toString(36).substr(2, 9)}`;
  return <>
      {hover && <style>{`
          #${rowId}:hover {
            background-color: var(--lp-color-bg-card);
          }
        `}</style>}
      <tr id={rowId} className={className} style={{
    ...header && ({
      backgroundColor: "var(--lp-color-accent-strong)",
      color: "var(--lp-color-on-accent)",
      fontWeight: "bold"
    }),
    ...style
  }} {...rest}>
        {children}
      </tr>
    </>;
};

export const StyledTable = ({children, variant = "default", style = {}, className = "", ...rest}) => {
  const wrapperVariants = {
    default: {
      border: "1px solid var(--lp-color-border-default)",
      backgroundColor: "var(--lp-color-bg-card)",
      overflow: "hidden"
    },
    bordered: {
      border: "2px solid var(--lp-color-accent)",
      backgroundColor: "var(--lp-color-bg-page)",
      overflow: "hidden"
    },
    minimal: {
      border: "none",
      backgroundColor: "transparent",
      overflow: "visible"
    }
  };
  return <div data-docs-styled-table-shell className={className} style={{
    width: "100%",
    padding: 0,
    margin: 0,
    ...wrapperVariants[variant],
    ...style
  }} {...rest}>
      <table data-docs-styled-table style={{
    width: "100%",
    borderCollapse: "collapse",
    borderSpacing: 0,
    margin: 0,
    backgroundColor: "transparent"
  }}>
        {children}
      </table>
    </div>;
};

export const LinkArrow = ({href, label, description, newline = true, borderColor, className = '', style = {}, ...rest}) => {
  const linkArrowStyle = {
    display: 'inline-flex',
    alignItems: 'center',
    justifyContent: 'center',
    gap: "var(--lp-spacing-1)",
    width: 'fit-content',
    ...borderColor && ({
      borderColor
    })
  };
  return <span className={className} style={style} {...rest}>
      {newline && <br />}
      <span style={linkArrowStyle}>
        <a href={href} target="_blank" rel="noopener noreferrer">
          {label}
        </a>
        <Icon icon="arrow-up-right" size={14} color="var(--lp-color-accent)" />
      </span>
      {description && description}
      {description && <div style={{
    height: "var(--lp-spacing-3)"
  }} />}
    </span>;
};

<CenteredContainer maxWidth="960px">
  <Tip>Gateways route work to Orchestrators; they do not perform the compute themselves. Orchestrators run the GPU workload, while the Gateway selects the route, enforces the price ceiling, and manages the session.</Tip>
</CenteredContainer>

<CustomDivider />

## Gateway Functions

A Gateway performs five core functions for every job it processes:

1. **Job intake** - accept requests from applications via RTMP (video) or HTTP API (AI, video, BYOC)
2. **Orchestrator selection** - match each job to the best available Orchestrator based on capability, price, latency, and performance history
3. **Session management** - maintain persistent connections to Orchestrators for the duration of a stream or job batch
4. **Payment handling** - generate probabilistic micropayment tickets per job segment (on-chain operational mode) or delegate payment to a remote signer (off-chain operational mode)
5. **Result delivery** - return transcoded video (HLS/DASH), inference output (JSON/binary), or stream results to the calling application

<Note>
  Orchestrators perform GPU compute, run AI models, transcode video, and execute containers. Compute providers should see <LinkArrow href="/v2/orchestrators/concepts/role" label="Orchestrator Role" newline={false} />.
</Note>

<CustomDivider />

## Workload Types

Gateways route four categories of work into the Livepeer Network. Operational mode sets the eligible categories.

<StyledTable variant="bordered">
  <thead>
    <TableRow header>
      <TableCell header>Workload</TableCell>
      <TableCell header>What it does</TableCell>
      <TableCell header>Ingest protocol</TableCell>
      <TableCell header>On-chain</TableCell>
      <TableCell header>Off-chain</TableCell>
    </TableRow>
  </thead>

  <tbody>
    <TableRow>
      <TableCell>**Video transcoding**</TableCell>
      <TableCell>Convert live video streams into multiple resolutions and formats</TableCell>
      <TableCell>RTMP (port 1935)</TableCell>
      <TableCell>Yes</TableCell>
      <TableCell>No</TableCell>
    </TableRow>

    <TableRow>
      <TableCell>**Batch AI inference**</TableCell>
      <TableCell>Single-request AI jobs: text-to-image, image-to-video, audio-to-text, captioning, segmentation</TableCell>
      <TableCell>HTTP API (port 8935)</TableCell>
      <TableCell>Yes</TableCell>
      <TableCell>Yes</TableCell>
    </TableRow>

    <TableRow>
      <TableCell>**Real-time AI (Cascade)**</TableCell>
      <TableCell>Continuous AI processing on a live video stream - style transfer, avatars, real-time agents</TableCell>
      <TableCell>HTTP API (port 8935)</TableCell>
      <TableCell>Yes</TableCell>
      <TableCell>Yes</TableCell>
    </TableRow>

    <TableRow>
      <TableCell>**LLM inference**</TableCell>
      <TableCell>Text generation, chat, instruction-following via large language models</TableCell>
      <TableCell>HTTP API (port 8935)</TableCell>
      <TableCell>Yes</TableCell>
      <TableCell>Yes</TableCell>
    </TableRow>
  </tbody>
</StyledTable>

<Warning>
  Video transcoding uses RTMP ingest and on-chain payment. Route video transcoding through an on-chain Gateway.
</Warning>

### BYOC (Bring Your Own Container)

BYOC pipelines allow applications to define custom container-based workloads that Orchestrators execute. The Gateway routes BYOC requests through the same HTTP API it uses for AI inference, and the Orchestrator runs an application-defined container instead of a standard AI model.

BYOC enables use cases like custom ML workflows, enterprise-specific processing, and novel applications (e.g. <LinkArrow href="/v2/solutions/embody" label="Embody AI avatars" newline={false} />).

See <LinkArrow href="/v2/developers/build/byoc" label="BYOC pipelines" newline={false} /> for the developer-side setup.

<CustomDivider />

## Orchestrator Selection

When a job arrives, the Gateway must decide which Orchestrator to send it to. This is the Gateway's most important function - it directly affects cost, latency, and reliability for end users.

```mermaid theme={"theme":{"light":"github-light","dark":"dark-plus"}}
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#18794E', 'primaryTextColor': '#fff', 'primaryBorderColor': '#3CB540', 'lineColor': '#3CB540', 'mainBkg': '#18794E', 'nodeBorder': '#3CB540', 'clusterBkg': 'transparent', 'clusterBorder': '#3CB540', 'titleColor': '#3CB540', 'edgeLabelBackground': 'transparent', 'textColor': '#3CB540', 'nodeTextColor': '#fff'}}}%%
flowchart TD
    A["Job arrives at gateway"] --> B["Filter: capability match"]
    B --> C["Filter: price within maxPricePerUnit"]
    C --> D["Rank: latency + performance history + stake weight"]
    D --> E["Select: best orchestrator"]
    E --> F["Dispatch job + payment ticket"]
    F --> G{Success?}
    G -->|Yes| H["Return result to application"]
    G -->|No| I["Failover: try next ranked orchestrator"]
    I --> F

    classDef default fill:#1a1a1a,color:#fff,stroke:#2d9a67,stroke-width:2px
```

The selection algorithm considers:

<StyledTable variant="bordered">
  <thead>
    <TableRow header>
      <TableCell header>Factor</TableCell>
      <TableCell header>What it means</TableCell>
    </TableRow>
  </thead>

  <tbody>
    <TableRow>
      <TableCell>**Capability**</TableCell>
      <TableCell>Does the Orchestrator support the requested pipeline, model, or transcoding profile?</TableCell>
    </TableRow>

    <TableRow>
      <TableCell>**Price**</TableCell>
      <TableCell>Is the Orchestrator's advertised price within the Gateway's configured `maxPricePerUnit`?</TableCell>
    </TableRow>

    <TableRow>
      <TableCell>**Latency**</TableCell>
      <TableCell>How fast has this Orchestrator responded to recent jobs?</TableCell>
    </TableRow>

    <TableRow>
      <TableCell>**Performance history**</TableCell>
      <TableCell>What is the Orchestrator's success rate and error rate over recent sessions?</TableCell>
    </TableRow>

    <TableRow>
      <TableCell>**Stake weight**</TableCell>
      <TableCell>How much LPT is staked to this Orchestrator? Higher stake implies greater economic commitment to good behaviour</TableCell>
    </TableRow>
  </tbody>
</StyledTable>

### Discovery Methods

Gateway discovery follows the operational mode:

<Tabs>
  <Tab title="On-chain gateway" icon="link">
    Queries the **on-chain Orchestrator registry** (ServiceRegistry contract on Arbitrum). All registered Orchestrators are discoverable automatically. The Gateway refreshes this list periodically.

    This is the default discovery method and requires no additional configuration.
  </Tab>

  <Tab title="Off-chain gateway" icon="cloud">
    Off-chain Gateways do not query the on-chain registry directly. Orchestrator discovery is handled via:

    * **Orchestrator list from the remote signer** - the signer provides a set of known Orchestrators
    * **Manual configuration** - the operator provides an explicit Orchestrator list

    See the <LinkArrow href="/v2/gateways/guides/payments-and-pricing/remote-signers" label="Remote Signers" newline={false} /> page for how discovery works in off-chain operational mode.
  </Tab>
</Tabs>

<CustomDivider />

## Sessions and Failover

Gateways maintain **sessions** with Orchestrators for the duration of a workload. For video transcoding, a session covers an entire livestream. For AI inference, a session usually covers a single request or batch.

Key session behaviours:

* **Session reuse** - the Gateway reuses an existing session with an Orchestrator when a new segment of the same stream arrives, avoiding repeated Orchestrator selection overhead
* **Automatic failover** - when an Orchestrator fails mid-session (timeout, error, disconnect), the Gateway selects the next-best Orchestrator and retries the segment
* **Session managers** - the Gateway runs separate session managers for video (`BroadcastSessionsManager`) and AI (`AISessionManager`), allowing dual-workload operation from a single node
* **Price negotiation** - session setup includes price agreement. A mid-session price change triggers renegotiation or a switch

<Note>
  Running both video and AI workloads from a single Gateway node is called **dual-workload configuration**. The Gateway handles this through separate session managers - no special setup required beyond enabling both ingest protocols. See <LinkArrow href="/v2/gateways/concepts/architecture" label="Gateway Architecture" newline={false} /> for the internal pipeline view.
</Note>

<CustomDivider />

## Gateway Marketplace Role

Gateways participate in the Livepeer marketplace as the **demand side**. They create competition among Orchestrators by routing jobs based on price, performance, and capability.

This means:

* **Better Orchestrators earn more work** - Gateways naturally route to faster, cheaper, more reliable nodes
* **Gateways compete on routing quality** - application developers choose Gateways based on supported features, latency, developer experience, and pricing
* **New capabilities are instantly routable** - when an Orchestrator adds a new AI model or pipeline, Gateways discover it and route to it without code changes

The marketplace emerges from Gateways and Orchestrators advertising capabilities and prices, with the selection algorithm matching supply to demand.

See <LinkArrow href="/v2/gateways/concepts/business-model" label="Gateway Business Model" newline={false} /> for how Gateway operators set pricing and earn margins within this marketplace.

<CustomDivider />

## Related Pages

<CardGroup cols={2}>
  <Card title="Gateway Role" icon="user-gear" href="/v2/gateways/concepts/role" arrow horizontal>
    What Gateways are and how the role has evolved.
  </Card>

  <Card title="Gateway Architecture" icon="diagram-project" href="/v2/gateways/concepts/architecture" arrow horizontal>
    Internal components, request flow, and system interactions.
  </Card>

  <Card title="Gateway Business Model" icon="chart-line" href="/v2/gateways/concepts/business-model" arrow horizontal>
    Revenue models, cost structures, and pricing.
  </Card>

  <Card title="Navigator" icon="compass" href="/v2/gateways/navigator" arrow horizontal>
    Find the right setup path for your goals.
  </Card>
</CardGroup>
