> ## 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.

# Configure AI, Video, or Dual Gateway Services

> Configure a Livepeer Gateway for AI inference, video transcoding, or both from one consolidated setup page.

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 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 ValueResponseField = ({description, post = null, label = "value", line = true, children, className = "", style = {}, ...props}) => {
  const hasDescription = typeof description === "function" || description != null || children != null;
  if (!hasDescription) {
    console.warn("[ValueResponseField] Missing required prop: description");
    return null;
  }
  const value = post ? [<span>
          <span style={{
    color: "gray"
  }}>{label}: </span>
          <span style={{
    color: "var(--lp-color-response-field-value)"
  }}>{post[0]}</span>
        </span>] : null;
  return <div className={[!line ? "vrf-noline" : "", className].filter(Boolean).join(" ") || undefined} style={style}>
      <style>{`
        .vrf-noline > .field {
          border-bottom: none;
          margin-bottom: -0.5rem;
          padding: 0;
        }
      `}</style>
      <ResponseField {...props} post={value}>
        {typeof description === "function" ? description() : description}
        {children}
      </ResponseField>
    </div>;
};

export const DynamicTable = ({tableTitle = null, headerList = [], itemsList = [], monospaceColumns = [], columnWidths = {}, contentFitColumns = [], showSeparators = false, margin, className = "", style = {}, ...rest}) => {
  if (!headerList.length) {
    return <div>No headers provided</div>;
  }
  const safeContentFitColumns = Array.isArray(contentFitColumns) ? contentFitColumns : [];
  const usesContentFitColumns = safeContentFitColumns.length > 0;
  const isContentFitColumn = header => safeContentFitColumns.includes(header);
  const getColumnStyle = header => {
    const widthStyle = columnWidths[header] ? {
      width: columnWidths[header],
      minWidth: columnWidths[header],
      maxWidth: columnWidths[header]
    } : {};
    const contentFitStyle = !columnWidths[header] && isContentFitColumn(header) ? {
      width: "1%",
      whiteSpace: "nowrap"
    } : {};
    return {
      ...contentFitStyle,
      ...widthStyle
    };
  };
  return <div className={className} style={style} {...rest}>
      {tableTitle && <div style={{
    fontStyle: "italic",
    margin: 0
  }}>
          <strong>{tableTitle}</strong>
        </div>}
      <div style={{
    overflowX: "auto",
    ...margin != null && ({
      margin
    })
  }} role="region" tabIndex={0} aria-label={tableTitle ? `Scrollable table: ${tableTitle}` : "Scrollable table"}>
        <table data-docs-dynamic-table style={{
    width: "100%",
    tableLayout: usesContentFitColumns ? "auto" : "fixed",
    borderCollapse: "collapse",
    fontSize: "0.9rem",
    marginTop: 0
  }}>
          <thead>
            <tr style={{
    backgroundColor: "var(--lp-color-accent)",
    color: "var(--lp-color-on-accent)",
    borderBottom: "1px solid var(--lp-color-border-default)"
  }}>
              {headerList.map((header, index) => <th key={index} style={{
    padding: "10px 8px",
    textAlign: "left",
    fontWeight: "600",
    color: "var(--lp-color-on-accent)",
    ...getColumnStyle(header)
  }}>
                  {header}
                </th>)}
            </tr>
          </thead>
          <tbody>
            {itemsList.filter(item => showSeparators || !item?.__separator).map((item, rowIndex) => item?.__separator ? <tr key={rowIndex} style={{
    backgroundColor: "var(--lp-color-accent)",
    color: "var(--lp-color-on-accent)",
    borderBottom: "1px solid var(--lp-color-accent)"
  }}>
                  <td colSpan={headerList.length} style={{
    padding: "6px 8px",
    fontWeight: "700",
    color: "var(--lp-color-on-accent)",
    letterSpacing: "0.01em"
  }}>
                    {(item[headerList[0]] ?? item.Category) ?? "Category"}
                  </td>
                </tr> : <tr key={rowIndex} style={{
    borderBottom: "1px solid var(--lp-color-border-default)"
  }}>
                  {headerList.map((header, colIndex) => {
    const value = (item[header] ?? item[header.toLowerCase()]) ?? "-";
    const isMonospace = monospaceColumns.includes(colIndex);
    return <td key={colIndex} style={{
      padding: "8px 8px",
      fontFamily: isMonospace ? "monospace" : "inherit",
      wordWrap: "break-word",
      overflowWrap: "break-word",
      ...getColumnStyle(header)
    }}>
                        {isMonospace ? <code>{value}</code> : value}
                      </td>;
  })}
                </tr>)}
          </tbody>
        </table>
      </div>
    </div>;
};

export const StyledStep = ({title, icon, titleSize = 'h3', iconColor = null, titleColor = null, children, className = '', style = {}, ...rest}) => {
  const styledTitle = titleColor ? <span style={{
    color: titleColor
  }}>{title}</span> : title;
  return <Step title={styledTitle} icon={icon} iconColor={iconColor || undefined} titleSize={titleSize} className={className} style={style} {...rest}>
      {children}
    </Step>;
};

export const StyledSteps = ({children, iconColor, titleColor, lineColor, iconSize = '24px', className = '', style = {}, ...rest}) => {
  const resolvedIconColor = iconColor || 'var(--accent-dark, #18794E)';
  const resolvedTitleColor = titleColor || 'var(--lp-color-accent)';
  const resolvedLineColor = lineColor || 'var(--lp-color-accent)';
  return <div className={['docs-styled-steps', className].filter(Boolean).join(' ')} style={style} {...rest}>
      <style>{`
        .docs-styled-steps .steps > div > div.absolute > div {
          background-color: ${resolvedIconColor};
        }
        .docs-styled-steps .steps > div > div.w-full > p {
          color: ${resolvedTitleColor};
        }
        .docs-styled-steps .steps > div > div.absolute.w-px {
          background-color: ${resolvedLineColor};
        }
        .docs-styled-steps .steps > div:last-child > div.absolute.w-px::after {
          content: '';
          position: absolute;
          bottom: 0;
          left: 50%;
          transform: translateX(-50%);
          width: 6px;
          height: 6px;
          background-color: ${resolvedLineColor};
          transform: translateX(-50%) rotate(45deg);
        }
      `}</style>
      <div>
        <Steps>{children}</Steps>
      </div>
    </div>;
};

export const BlinkingIcon = ({icon = 'terminal', size = 16, color, className = '', style = {}, ...rest}) => {
  const resolvedColor = color || 'var(--lp-color-accent)';
  return <span className={className} style={{
    display: 'inline-flex',
    ...style
  }} {...rest}>
      <style>{`
        @keyframes blink {
          0%, 100% { opacity: 1; }
          50% { opacity: 0.3; }
        }
        @media (prefers-reduced-motion: reduce) {
          * { animation: none !important; }
        }
      `}</style>
      <span style={{
    display: 'inline-flex',
    animation: 'blink 3s ease-in-out infinite'
  }}>
        <Icon icon={icon} size={size} color={resolvedColor} />
      </span>
    </span>;
};

export const ScrollableDiagram = ({children, title = '', maxHeight = '500px', minWidth = '100%', showControls = false, className = '', style = {}, ...rest}) => {
  const buildDiagramKey = (currentTitle = '', currentClassName = '') => {
    const source = `${currentTitle}|${currentClassName}|scrollable-diagram`;
    let hash = 0;
    for (let index = 0; index < source.length; index += 1) {
      hash = hash * 31 + source.charCodeAt(index) >>> 0;
    }
    return `docs-diagram-${hash.toString(36)}`;
  };
  const diagramKey = buildDiagramKey(title, className);
  const zoomName = `${diagramKey}-zoom`;
  const zoomLevels = [{
    label: '75%',
    value: 0.75
  }, {
    label: '100%',
    value: 1
  }, {
    label: '125%',
    value: 1.25
  }, {
    label: '150%',
    value: 1.5
  }];
  const containerStyle = {
    overflow: 'auto',
    maxHeight,
    border: '1px solid var(--lp-color-border-default)',
    borderRadius: "8px",
    padding: "var(--lp-spacing-4)",
    background: 'var(--lp-color-bg-card)',
    position: 'relative'
  };
  return <div className={className} style={{
    position: 'relative',
    marginBottom: "var(--lp-spacing-4)",
    ...style
  }} {...rest}>
      {title && <p style={{
    textAlign: 'center',
    fontStyle: 'italic',
    color: 'var(--lp-color-text-secondary)',
    marginBottom: "var(--lp-spacing-2)",
    fontSize: '0.875rem'
  }}>
          {title}
        </p>}

      {showControls ? <style>{`
          [data-docs-diagram-key="${diagramKey}"] [data-docs-diagram-content] {
            transform: scale(1);
            transform-origin: top left;
            width: max-content;
          }
          ${zoomLevels.map(zoomLevel => `
          #${diagramKey}-${zoomLevel.label.replace('%', '')}:checked ~ [data-docs-diagram-shell] [data-docs-diagram-content] {
            transform: scale(${zoomLevel.value});
          }
          #${diagramKey}-${zoomLevel.label.replace('%', '')}:checked ~ [data-docs-diagram-controls] label[for="${diagramKey}-${zoomLevel.label.replace('%', '')}"] {
            background: var(--lp-color-accent);
            color: var(--lp-color-on-accent);
            border-color: var(--lp-color-accent);
          }`).join('\n')}
        `}</style> : null}

      {showControls ? zoomLevels.map(zoomLevel => {
    const inputId = `${diagramKey}-${zoomLevel.label.replace('%', '')}`;
    return <input key={inputId} id={inputId} type="radio" name={zoomName} defaultChecked={zoomLevel.value === 1} style={{
      position: 'absolute',
      opacity: 0,
      pointerEvents: 'none'
    }} />;
  }) : null}

      <div data-docs-diagram-key={diagramKey} data-docs-diagram-shell style={containerStyle}>
        <div data-docs-diagram-content style={{
    minWidth,
    transformOrigin: 'top left',
    width: 'max-content'
  }}>
          {children}
        </div>
      </div>

      {showControls ? <div data-docs-diagram-controls style={{
    display: 'flex',
    justifyContent: 'flex-end',
    alignItems: 'center',
    gap: "var(--lp-spacing-2)",
    marginTop: "var(--lp-spacing-2)",
    flexWrap: 'wrap'
  }}>
          <span style={{
    fontSize: "0.75rem",
    color: 'var(--lp-color-text-muted)',
    marginRight: 'auto'
  }}>
            Scroll to pan
          </span>
          {zoomLevels.map(zoomLevel => {
    const inputId = `${diagramKey}-${zoomLevel.label.replace('%', '')}`;
    return <label key={inputId} htmlFor={inputId} style={{
      background: 'transparent',
      color: 'var(--lp-color-text-secondary)',
      border: '1px solid var(--lp-color-border-default)',
      borderRadius: "4px",
      padding: '4px 10px',
      cursor: 'pointer',
      fontSize: "0.75rem",
      fontWeight: '600'
    }}>
                {zoomLevel.label}
              </label>;
  })}
        </div> : null}
    </div>;
};

export const DoubleIconLink = ({label = '', labelColor, href = '#', text = '', iconLeft = 'github', iconLeftColor, iconRight = 'arrow-up-right', iconRightColor = 'var(--lp-color-accent)', className = '', style = {}, ...rest}) => {
  return <span className={className} style={{
    whiteSpace: 'nowrap',
    display: 'inline-flex',
    alignItems: 'center',
    gap: "var(--lp-spacing-1)",
    marginLeft: '0.3rem',
    ...style
  }} {...rest}>
      {text && <span style={{
    marginRight: 8
  }}>{text}</span>}
      <Icon icon={iconLeft} color={iconLeftColor} />
      <a href={href} style={{
    color: {
      labelColor
    }
  }}>
        {label}
      </a>
      <div style={{
    marginRight: '0.3rem'
  }}>
        <Icon icon={iconRight} size={12} color={iconRightColor} />
      </div>
    </span>;
};

export const BorderedBox = ({children, variant = "default", padding = "var(--lp-spacing-4)", borderRadius = "var(--lp-spacing-px-8)", margin = "", accentBar = "", style = {}, className = "", ...rest}) => {
  const variants = {
    default: {
      border: "1px solid var(--lp-color-border-default)",
      backgroundColor: "var(--lp-color-bg-card)"
    },
    accent: {
      border: "1px solid var(--lp-color-accent)",
      backgroundColor: "var(--lp-color-bg-card)"
    },
    muted: {
      border: "1px solid var(--lp-color-border-default)",
      backgroundColor: "transparent"
    }
  };
  const accentBarColors = {
    accent: "var(--lp-color-accent)",
    positive: "var(--green-9)"
  };
  return <div data-docs-bordered-box="" data-accent-bar={accentBarColors[accentBar] ? "" : undefined} className={className} style={{
    ...variants[variant],
    padding: padding,
    borderRadius: borderRadius,
    ...margin ? {
      margin
    } : {},
    ...accentBarColors[accentBar] ? {
      position: "relative",
      '--accent-bar-color': accentBarColors[accentBar]
    } : {},
    ...style
  }} {...rest}>
      {children}
    </div>;
};

# <Icon icon="gear" size={26} /> Configure Your Gateway

Use this page to configure a Livepeer Gateway for AI inference, video transcoding, or both workloads on the same node.

## Configuration Methods

You can configure a Livepeer Gateway using:

* Command-line flags
* Environment variables prefixed with `LP_`
* A plain-text configuration file

<Card icon="book-open" title="Full Configuration Reference" href="/v2/gateways/resources/reference/technical/configuration-flags" arrow horizontal>
  Full reference for Gateway configuration flags
</Card>

<Card title="Pricing Configuration" icon="money-check-dollar" href="/v2/gateways/guides/payments-and-pricing/pricing-configuration" arrow horizontal>
  Configure pricing for your Gateway services
</Card>

<BorderedBox variant="accent">
  <Tabs>
    <Tab title="AI" icon="user-robot">
      This page will walk you through the process of deploying and configuring a Livepeer Gateway for AI inference services.

      ## Gateway Modes

      You can run a Gateway

      * **"Off-chain"** -> dev or local mode
      * **"On-chain"** -> production mode connected to the blockchain-based Livepeer Network.

      <Warning>
        If you run your Gateway **off-chain** - **you will need to run your own Orchestrator node** ie. Have access to a GPU and set it up as an Orchestrator, in order to test Gateway functionality.
      </Warning>

      <Note>
        There is currently no Livepeer "Testnet" available which has Orchestrator offerings, though there are conversations underway to enable this in the future.

        **Do you think Livepeer should have a "testnet" available for Gateways to connect to?**

        Follow & contribute to the discussion in the [Discord](https://discord.gg/livepeer) and on the [Forum](https://forum.livepeer.org)
      </Note>

      ## Deploy a Gateway for AI Inference Services

      You can run the Livepeer AI software using one of the following methods:

      * **Docker** (Recommended): The simplest and preferred method.
      * **Pre-built Binaries**: An alternative if you prefer not to use Docker.

      ## <BlinkingIcon size={20} /> Deploy an AI Gateway

      Follow the steps below to start your Livepeer AI Gateway node.

      <Note> These instructions apply to both on-chain & off-chain Gateway deployments. </Note>

      <br />

      <Tabs>
        <Tab title="Use Docker (Recommended)">
          <StyledSteps iconColor="var(--lp-color-accent-strong)" titleColor="var(--lp-color-on-accent)" lineColor="" iconSize="24px">
            <StyledStep title="Retrieve the Livepeer AI Docker Image">
              Fetch the latest <DoubleIconLink label="Livepeer AI Docker image" href="https://hub.docker.com/r/livepeer/go-livepeer" iconLeft="docker" /> with the following command:

              ```bash icon="terminal" Pull Docker Image theme={"theme":{"light":"github-light","dark":"dark-plus"}}
              docker pull livepeer/go-livepeer:master
              ```
            </StyledStep>

            <StyledStep title="Launch a Localhost (Off-chain) AI Gateway">
              Run the Docker container for your AI Gateway node:

              ```bash icon="terminal" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
              docker run \
                  --name livepeer_ai_gateway \
                  -v ~/.lpData2/:/root/.lpData2 \
                  -p 8935:8935 \
                  --network host \
                  livepeer/go-livepeer:master \
                  -datadir ~/.lpData2 \
                  -gateway \
                  -orchAddr <orchestrator list> \
                  -httpAddr 0.0.0.0:8935 \
                  -v 6 \
                  -httpIngest
              ```

              This command launches a local (**off-chain**) AI Gateway node. The flags are similar to those used for a Mainnet Transcoding Network Gateway. See the [go-livepeer CLI reference](/v2/Gateways/resources/reference/technical/go-livepeer/cli-reference) for flag details.
            </StyledStep>

            <StyledStep title="Confirm Successful Startup">
              Upon successful startup, you should see output similar to:

              ```bash icon="terminal" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
              I0501 11:07:47.609839       1 mediaserver.go:201] Transcode Job Type: [{P240p30fps16x9 600k 30 0 426x240 16:9 0 0 0s 0 0 0 0} {P360p30fps16x9 1200k 30 0 640x360 16:9 0 0 0s 0 0 0 0}]
              I0501 11:07:47.609917       1 mediaserver.go:226] HTTP Server listening on http://0.0.0.0:8935
              I0501 11:07:47.609963       1 lpms.go:92] LPMS Server listening on rtmp://127.0.0.1:1935
              ```
            </StyledStep>

            <StyledStep title="Check Port Availability">
              Ensure that port `8935` is open and accessible, and configure your router for port forwarding if necessary to make the Gateway accessible from the internet.
            </StyledStep>

            <StyledStep title="Test the AI Gateway">
              Follow the instructions in the <DoubleIconLink label="AI Gateway Testing Guide" href="/v2/gateways/quickstart/gateway-setup" iconLeft="link" /> to verify that the AI Gateway is operational.
            </StyledStep>
          </StyledSteps>
        </Tab>

        <Tab title="Use Binaries">
          <StyledSteps>
            <StyledStep title="Download the Latest Livepeer AI Binary">
              Download the latest Livepeer AI binary for your system:

              ```bash icon="terminal" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
              wget https://build.livepeer.live/go-livepeer/livepeer-<OS>-<ARCH>.tar.gz
              ```

              Replace `<OS>` and `<ARCH>` with your operating system and architecture (e.g., `linux-amd64` for Linux AMD64). For install options, see the [go-livepeer installation guide](/v2/Gateways/setup/install).

              <Warning>The Windows and MacOS (amd64) binaries of Livepeer AI are **not** available yet.</Warning>
            </StyledStep>

            <StyledStep title="Extract and Configure the Binary">
              Once downloaded, extract the binary to a directory of your choice.
            </StyledStep>

            <StyledStep title="Launch an Off-chain AI Gateway">
              Start the AI Gateway node with the following command:

              ```bash icon="terminal" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
              ./livepeer \
                  -datadir ~/.lpData2 \
                  -gateway \
                  -orchAddr <orchestrator list> \
                  -httpAddr 0.0.0.0:8935 \
                  -v 6 \
                  -httpIngest
              ```

              This command launches an **off-chain** AI Gateway node. Refer to the [go-livepeer CLI reference](/v2/Gateways/resources/reference/technical/go-livepeer/cli-reference) for more details on the flags.
            </StyledStep>

            <StyledStep title="Confirm Successful Startup">
              Check the terminal for the following output to confirm successful startup:

              ```bash icon="terminal" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
              I0501 11:07:47.609839       1 mediaserver.go:201] Transcode Job Type: [{P240p30fps16x9 600k 30 0 426x240 16:9 0 0 0s 0 0 0 0} {P360p30fps16x9 1200k 30 0 640x360 16:9 0 0 0s 0 0 0 0}]
              I0501 11:07:47.609917       1 mediaserver.go:226] HTTP Server listening on http://0.0.0.0:8935
              I0501 11:07:47.609963       1 lpms.go:92] LPMS Server listening on rtmp://127.0.0.1:1935
              ```
            </StyledStep>

            <StyledStep title="Check Port Availability">
              Ensure that port `8935` is open and accessible, and configure port forwarding if needed.
            </StyledStep>

            <StyledStep title="Test the AI Gateway">
              Follow the instructions in the <DoubleIconLink label="AI Gateway Testing Guide" href="/v2/gateways/quickstart/gateway-setup" iconLeft="link" /> to verify that the AI Gateway is operational.
            </StyledStep>
          </StyledSteps>

          <Note>
            If binaries are unavailable for your system, you can build the [master branch](https://github.com/livepeer/go-livepeer/tree/master) of [go-livepeer](https://github.com/livepeer/go-livepeer) from source. Refer to the [go-livepeer installation guide](/v2/Gateways/setup/install) or reach out to the Livepeer community on [Discord](https://discord.gg/livepeer) for assistance.
          </Note>
        </Tab>
      </Tabs>

      ## Gateway Code Links

      For AI processing, the Gateway extends its functionality to handle AI-specific workflows.

      <Card title="go-livepeer/server/ai_mediaserver.go" icon="github" href="https://github.com/livepeer/go-livepeer/blob/5691cb48/server/ai_mediaserver.go" horizontal arrow />

      Key components include:

      * **AISessionManager**: Manages AI processing sessions and selects appropriate Orchestrators with AI capabilities <DoubleIconLink label="ai_http.go" href="https://github.com/livepeer/go-livepeer/blob/5691cb48/server/ai_http.go" iconLeft="github" />
      * **MediaMTX Integration**: Handles media streaming for AI processing
      * **Trickle Protocol**: Enables efficient streaming for real-time AI video processing

      The AI workflow <DoubleIconLink label="server/ai_process.go" href="https://github.com/livepeer/go-livepeer/blob/5691cb48/server/ai_process.go" iconLeft="github" /> involves

      * authenticating AI streams,
      * selecting AI-capable Orchestrators,
      * processing payments **based on pixels**, and
      * managing live AI pipelines
    </Tab>

    <Tab title="Video" icon="film-canister">
      ## TL;DR Configuration

      If you just want a working video Gateway, use the below command:

      <Tabs>
        <Tab title="Off-Chain" icon="terminal">
          Replace <Badge color="gray">{'<ORCHESTRATOR_ADDRESSES>'}</Badge> with your locally running Orchestrator http address.

          ```bash wrap lines icon="terminal" Off-Chain Video Gateway theme={"theme":{"light":"github-light","dark":"dark-plus"}}
          livepeer -gateway \
            -network offchain \
            # Minimum required video flags
            -rtmpAddr=0.0.0.0:1935 \
            -httpAddr=0.0.0.0:8935 \
            -transcodingOptions=P240p30fps16x9,P360p30fps16x9 \
            # You will need to add your local orchestrator address if you are running off-chain
            -orchAddr=<ORCHESTRATOR_ADDRESSES> #comma separated list of orchestrator addresses
            # Example: -orchAddr=http://192.168.1.100:8935,http://192.168.1.101:8935
            # You can also use a JSON file: -orchAddr=/path/to/orchestrators/portal.json
          ```
        </Tab>

        <Tab title="On-Chain" icon="link">
          Replace <Badge color="gray">{'<ORCHESTRATOR_ADDRESSES>'}</Badge> with publicly available Orchestrator addresses.

          ```bash wrap lines icon="link" On-Chain Video Gateway theme={"theme":{"light":"github-light","dark":"dark-plus"}}
          livepeer -gateway \
            -network arbitrum-one-mainnet \
            # See the on-chain setup guide for more details on these flags
            -ethUrl=<YOUR_RPC_URL> \
            -ethAcctAddr=<YOUR_ETH_ADDRESS> \
            -ethPassword=<YOUR_PASSWORD> \
            -ethKeystorePath=<KEYSTORE_PATH> \
            # Minimum required video flags
            -rtmpAddr=0.0.0.0:1935 \
            -httpAddr=0.0.0.0:8935 \
            -transcodingOptions=P240p30fps16x9,P360p30fps16x9 \
            # Price per unit is required on-chain (see pricing guide)
            -maxPricePerUnit=1000 \
            # You will need to connect to a public orchestrator if you are running onchain
            -orchAddr=<ORCHESTRATOR_ADDRESSES> #comma separated list of orchestrators
            # Example:  -orchAddr=https://orch1.example.com:8935,https://orch2.example.com:8935
            # You can also use a JSON file: -orchAddr=/path/to/orchestrators/portal.json

          ```

          Livepeer does not currently maintain a list of publicly available Orchestrators. You need to discover them through:

          * **Livepeer CLI**: Use livepeer\_cli → Option 9: "List registered Orchestrators"
          * **Network discovery**: The Gateway discovers Orchestrators from the on-chain registry
          * **Community resources**: Check Livepeer community channels or documentation

          Jump to the <DoubleIconLink label="Connect Guide" href="/v2/gateways/setup/connect/connect-with-offerings" iconLeft="link" /> for details on connecting to Orchestrators.
        </Tab>
      </Tabs>

      <CustomDivider />

      Gateways for Video Transcoding In traditional video transcoding, the Gateway
      ingests video streams via
      [RTMP](https://en.wikipedia.org/wiki/Real-Time_Messaging_Protocol) or
      [HTTP](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol), segments
      them, and distributes transcoding work to Orchestrators{' '}

      {/* Key components include:

            - **[BroadcastSessionsManager](https://github.com/livepeer/go-livepeer/blob/5691cb48/core/broadcast.go)**: Manages transcoding sessions and selects Orchestrators
            - **[RTMP](https://en.wikipedia.org/wiki/Real-Time_Messaging_Protocol) Server**: Handles RTMP (Real-Time Message Protocol) stream ingestion
            - **[Payment Manager](https://github.com/livepeer/go-livepeer/blob/5691cb48/core/live_payment.go)**: Generates and sends payment tickets for transcoding work */}

      <ScrollableDiagram title="Video Gateway Transcoding Architecture" maxHeight="900px">
        ```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 TB
            subgraph INPUT["Video Input Sources"]
                direction LR
                RTMP["RTMP Stream<br/>:1935"]
                HTTP["HTTP Upload<br/>:8935"]
            end

            GATEWAY["Gateway Node<br/>LivepeerNode<br/>-gateway mode"]

            INPUT --> GATEWAY

            subgraph MANAGER["Broadcast Session Manager"]
                BSM["BroadcastSessionsManager<br/>Manages transcoding sessions<br/>Selects orchestrators"]
            end

            GATEWAY --> BSM

            subgraph PROCESSING["Video Processing Pipeline"]
                direction TB
                SEG["Segment Video<br/>Split into chunks"]
                TRANS["Send to Orchestrators<br/>with payment tickets"]
                ORCH["Orchestrators<br/>Transcode segments<br/>Multiple renditions"]
                RECEIVE["Receive Results<br/>Transcoded segments"]
            end

            BSM --> SEG --> TRANS --> ORCH --> RECEIVE

            subgraph OUTPUT["Output & Delivery"]
                direction LR
                HLS["HLS Manifest<br/>.m3u8"]
                RENDITIONS["Multiple Renditions<br/>240p, 360p, 720p, 1080p"]
            end

            RECEIVE --> HLS --> RENDITIONS

            subgraph PAYMENT["Payment System"]
                direction TB
                PM["Payment Manager<br/>Generate tickets"]
                TICKETS["Per-segment payments<br/>Based on pixels transcoded"]
            end

            TRANS --> PM --> TICKETS --> ORCH

            subgraph STORAGE["Storage (Optional)"]
                OBJ["Object Store<br/>S3/IPFS"]
            end

            RENDITIONS -.-> OBJ

            classDef default fill:#1a1a1a,color:#fff,stroke:#2d9a67,stroke-width:2px
            classDef video fill:#1a1a1a,color:#fff,stroke:#3b82f6,stroke-width:2px
            classDef payment fill:#1a1a1a,color:#fff,stroke:#fbbf24,stroke-width:2px
            class RTMP,HTTP,BSM,SEG,TRANS,ORCH,RECEIVE,HLS,RENDITIONS video
            class PM,TICKETS payment
            style INPUT fill:#0d0d0d,stroke:#2d9a67,stroke-width:1px
            style MANAGER fill:#0d0d0d,stroke:#3b82f6,stroke-width:1px
            style PROCESSING fill:#0d0d0d,stroke:#3b82f6,stroke-width:1px
            style OUTPUT fill:#0d0d0d,stroke:#3b82f6,stroke-width:1px
            style PAYMENT fill:#0d0d0d,stroke:#fbbf24,stroke-width:1px
            style STORAGE fill:#0d0d0d,stroke:#2d9a67,stroke-width:1px,stroke-dasharray: 5 5
        ```
      </ScrollableDiagram>

      <Card title="Code Reference" icon="github" href="https://github.com/livepeer/go-livepeer/blob/5691cb48/core/livepeernode.go" horizontal arrow>
        go-livepeer/core/livepeernode.go
      </Card>

      ## Essential Configuration Flags

      #### Required Flags

      <ResponseField name="-gateway" type="boolean" required default="false">
        Enable Gateway mode
      </ResponseField>

      <ResponseField name="-network" type="string" default="offchain">
        Set to the blockchain network for production Gateways <Badge color="gray"> `arbitrum-one-mainnet` </Badge>
      </ResponseField>

      <ResponseField name="-orchAddr" type="string" default="none" required>
        Set to <Badge color="gray"> `http://<ORCHESTRATOR_IP>:<PORT>` </Badge> to connect to Orchestrators
      </ResponseField>

      #### Network Configuration

      <ResponseField name="-rtmpAddr" type="string" default="127.0.0.1:1935">
        Set to <Badge color="gray"> `0.0.0.0:1935` </Badge> to allow external RTMP connections
      </ResponseField>

      <ResponseField name="-httpAddr" type="string" default="127.0.0.1:8935">
        Set to <Badge color="gray"> `0.0.0.0:8935` </Badge> to allow external HLS/API access
      </ResponseField>

      #### Transcoding Configuration

      <ResponseField name="-transcodingOptions" type="string" default="P240p30fps16x9,P360p30fps16x9">
        Set to <Badge color="gray"> `path/to/transcodingOptions.json` </Badge> to use a custom transcoding configuration
      </ResponseField>

      #### Additional On-Chain Flags

      Add these flags for on-chain configuration. See <DoubleIconLink label="On-Chain Setup Guide" href="/v2/gateways/setup/requirements/on-chain-setup/on-chain" iconLeft="link" /> for details.

      <ValueResponseField name="-network" type="string" default="offchain" post={['"arbitrum-one-mainnet"']} />

      <ValueResponseField name="-maxPricePerUnit" type="int" default="0" post={['"1000"']} />

      <ValueResponseField name="-ethUrl" type="string" default="none" post={['"YOUR_RPC_URL"']} required />

      <ValueResponseField name="-ethAcctAddr" type="string" default="leave empty to auto-create" post={['"YOUR_ETH_ADDRESS"']} />

      <ValueResponseField name="-ethPassword" type="string" default="leave empty to auto-create" post={['"YOUR_PASSWORD"']} />

      <ValueResponseField name="-ethKeystorePath" type="string" default="leave empty to auto-create" post={['"KEYSTORE_PATH"']} />

      <CustomDivider />

      ## Comprehensive Configuration Guide

      ### Configuration Methods

      You have three ways to configure your Livepeer Gateway after installation:

      * Command-line flags (most common)
      * Environment variables (prefixed with LP\_)
      * Configuration file (plain text key value format)

      ### Configuration Examples

      The below examples show the most common configuration methods.

      <Tabs>
        <Tab title="CLI" icon="terminal">
          .
        </Tab>

        <Tab title="Config File" icon="file">
          .
        </Tab>

        <Tab title="Env Variables" icon="variable">
          .
        </Tab>

        <Tab title="Docker" icon="docker">
          ```bash wrap icon="docker" Create docker-compose.yml theme={"theme":{"light":"github-light","dark":"dark-plus"}}
          # 1. Create a basic docker-compose.yml
          cat > docker-compose.yml << EOF
          version: '3.9'
          services:
            gateway:
              image: livepeer/go-livepeer:master
              ports:
                - 1935:1935  # RTMP ingest
                - 8935:8935  # HLS/API
              volumes:
                - gateway-data:/root/.lpData
              command: |
                -gateway
                -network offchain
                -rtmpAddr=0.0.0.0:1935
                -httpAddr=0.0.0.0:8935
                -orchAddr=https://orchestrator.example.com:8935
                -transcodingOptions=P240p30fps16x9,P360p30fps16x9,P720p30fps16x9

          volumes:
            gateway-data:
          EOF
          ```

          Start the Gateway

          ```bash wrap icon="docker" Start the gateway theme={"theme":{"light":"github-light","dark":"dark-plus"}}
          # 2. Start the gateway
          docker-compose up -d
          ```
        </Tab>

        <Tab title="Binary" icon="code">
          .
        </Tab>
      </Tabs>

      ```bash icon="terminal" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
      livepeer -gateway \
        -network offchain \
        -transcodingOptions=${env:HOME}/.lpData/offchain/transcodingOptions.json \
        -orchAddr=0.0.0.0:8935 \
        -httpAddr=0.0.0.0:9935 \
        -v=6
      ```

      <Tabs>
        <Tab title="Docker" icon="docker">
          ```bash wrap icon="docker" Create docker-compose.yml theme={"theme":{"light":"github-light","dark":"dark-plus"}}
          # 1. Create a basic docker-compose.yml
          cat > docker-compose.yml << EOF
          version: '3.9'
          services:
            gateway:
              image: livepeer/go-livepeer:master
              ports:
                - 1935:1935  # RTMP ingest
                - 8935:8935  # HLS/API
              volumes:
                - gateway-data:/root/.lpData
              command: |
                -gateway
                -network arbitrum-one-mainnet
                -rtmpAddr=0.0.0.0:1935
                -httpAddr=0.0.0.0:8935
                -orchAddr=https://orchestrator.example.com:8935
                -transcodingOptions=P240p30fps16x9,P360p30fps16x9,P720p30fps16x9
                -ethUrl <YOUR_RPC_URL> \
                -ethAcctAddr <YOUR_ETH_ADDRESS> \
                -ethPassword <YOUR_PASSWORD> \
                -ethKeystorePath <KEYSTORE_PATH> \
                -maxPricePerUnit 1000

          volumes:
            gateway-data:
          EOF
          ```

          Start the Gateway

          ```bash wrap icon="docker" Start the gateway theme={"theme":{"light":"github-light","dark":"dark-plus"}}
          # 2. Start the gateway
          docker-compose up -d
          ```
        </Tab>

        <Tab title="Binary" icon="code">
          .
        </Tab>
      </Tabs>

      ```bash icon="terminal" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
      livepeer -gateway \
        -network arbitrum-one-mainnet \
        -ethUrl=<YOUR_RPC_URL> \
        -ethAcctAddr=<YOUR_ETH_ADDRESS> \
        -ethPassword=<YOUR_PASSWORD> \
        -ethKeystorePath=<KEYSTORE_PATH> \
        -maxPricePerUnit=1000 \
        -orchAddr=<ORCHESTRATOR_ADDRESSES> \
        -monitor=true
      ```

      ## Transcoding Options JSON

      Livepeer supports JSON configuration files for transcoding options through the `-transcodingOptions` flag.

      The transcodingOptions.json file lets you precisely control the encoding ladder.

      This file is a custom configuration file containing an array of rendition objects that defines which renditions (resolutions + bitrates)
      your Gateway will produce for each incoming stream.

      It overrides the default built-in ladder (e.g., P240p30fps16x9, etc.).

      ```json wrap lines icon="brackets-curly" transcodingOptions.json example theme={"theme":{"light":"github-light","dark":"dark-plus"}}
      [
        {
          // required
          "bitrate": 1600000,
          "width": 854,
          "height": 480,
          // optional
          "name": "480p0",
          "fps": 0,
          "profile": "h264constrainedhigh",
          "gop": "1"
        },
        {
          // required
          "bitrate": 3000000,
          "width": 1280,
          "height": 720,
          // optional
          "name": "720p0",
          "fps": 0,
          "profile": "h264constrainedhigh",
          "gop": "1"
        },
        {
          // required
          "bitrate": 6500000,
          "width": 1920,
          "height": 1080,
          // optional
          "name": "1080p0",
          "fps": 0,
          "profile": "h264constrainedhigh",
          "gop": "1"
        }
      ]
      ```

      #### Notes

      * JSON configuration only applies to transcoding options, not other Gateway flags
      * The file must contain valid JSON with the specified structure
      * All fields are optional except width, height, and bitrate
      * You can mix JSON configuration with other command-line flags

      <Card title="Next Step: Pricing Configuration" href="/v2/gateways/guides/payments-and-pricing/pricing-configuration" icon="hand-holding-dollar" horizontal arrow>
        Configure pricing for your Gateway.
      </Card>

      ## Full Configuration Flag Reference

      ### Essential Changes

      <DynamicTable
        headerList={['Option', 'Recommended Change', 'Why']}
        itemsList={[
{
  Option: '-orchAddr',
  'Recommended Change': 'Set to your orchestrator URLs',
  Why: 'Required to connect to transcoding services',
},
{
  Option: '-transcodingOptions',
  'Recommended Change': 'Customize based on needs',
  Why: 'Controls output video quality profiles',
},
{
  Option: '-maxSessions',
  'Recommended Change': 'Adjust based on server capacity',
  Why: 'Limits concurrent streams',
},
]}
        monospaceColumns={[0]}
      />

      ### Network Configuration

      <DynamicTable
        headerList={['Option', 'Default', 'Recommended', 'Description']}
        itemsList={[
{
  Option: '-rtmpAddr',
  Default: '127.0.0.1:1935',
  Recommended: '0.0.0.0:1935',
  Description: 'Allow external RTMP connections',
},
{
  Option: '-httpAddr',
  Default: '127.0.0.1:8935',
  Recommended: '0.0.0.0:8935',
  Description: 'Allow external HLS access',
},
{
  Option: '-cliAddr',
  Default: '127.0.0.1:7935',
  Recommended: '0.0.0.0:5935',
  Description: 'Allow external CLI access',
},
]}
        monospaceColumns={[0, 1, 2]}
      />

      ### Transcoding Settings

      <DynamicTable
        headerList={['Option', 'Default', 'When to Change', 'Description']}
        itemsList={[
{
  Option: '-transcodingOptions',
  Default: 'P240p30fps16x9,P360p30fps16x9',
  'When to Change': 'Need different quality levels',
  Description: 'Video output profiles',
},
{
  Option: '-maxSessions',
  Default: '10',
  'When to Change': 'Based on server capacity',
  Description: 'Max concurrent streams',
},
{
  Option: '-maxAttempts',
  Default: '3',
  'When to Change': 'Unreliable network',
  Description: 'Retry attempts for failed transcodes',
},
]}
        monospaceColumns={[0, 1]}
      />

      ### Production Considerations

      <DynamicTable
        headerList={['Option', 'Recommended Setting', 'Use Case']}
        itemsList={[
{
  Option: '-monitor',
  'Recommended Setting': 'true',
  'Use Case': 'Production monitoring',
},
{
  Option: '-authWebhookUrl',
  'Recommended Setting': 'Set your auth endpoint',
  'Use Case': 'Secure stream authentication',
},
{
  Option: '-currentManifest',
  'Recommended Setting': 'true',
  'Use Case': 'Easier HLS playback',
},
]}
        monospaceColumns={[0, 1]}
      />

      <Expandable title=">_ Configuration Options">
        <DynamicTable
          headerList={['Category', 'Flag', 'Default', 'Description']}
          itemsList={[
  {
    Category: 'Basic Setup',
    Flag: '-gateway',
    Default: '-',
    Description: 'Enable gateway mode (required)',
  },
  {
    Category: '',
    Flag: '-network',
    Default: 'offchain',
    Description: 'Network type (offchain, arbitrum-one-mainnet)',
  },
  {
    Category: 'Network Binding',
    Flag: '-rtmpAddr',
    Default: '127.0.0.1:1935',
    Description: 'RTMP server address for video ingest',
  },
  {
    Category: '',
    Flag: '-httpAddr',
    Default: '127.0.0.1:8935',
    Description: 'HTTP server address for API/HLS',
  },
  {
    Category: '',
    Flag: '-cliAddr',
    Default: '127.0.0.1:7935',
    Description: 'CLI API server address',
  },
  {
    Category: 'Transcoding',
    Flag: '-transcodingOptions',
    Default: 'P240p30fps16x9,P360p30fps16x9',
    Description: 'Video output profiles',
  },
  {
    Category: '',
    Flag: '-maxSessions',
    Default: '10',
    Description: 'Maximum concurrent streams',
  },
  {
    Category: '',
    Flag: '-maxPricePerUnit',
    Default: '0',
    Description: 'Maximum price per pixel',
  },
  {
    Category: 'Orchestrator',
    Flag: '-orchAddr',
    Default: '""',
    Description: 'Orchestrator addresses',
  },
  {
    Category: '',
    Flag: '-orchWebhookUrl',
    Default: '""',
    Description: 'Discovery webhook URL',
  },
  {
    Category: 'Authentication',
    Flag: '-authWebhookUrl',
    Default: '""',
    Description: 'Stream authentication webhook',
  },
  {
    Category: 'Storage',
    Flag: '-objectStore',
    Default: '""',
    Description: 'Object storage URL',
  },
  {
    Category: 'Monitoring',
    Flag: '-monitor',
    Default: 'false',
    Description: 'Enable metrics collection',
  },
]}
          monospaceColumns={[1, 2]}
        />
      </Expandable>

      <Expandable title="old docs">
        ## Modify Config Files

        <Tabs>
          <Tab title="Docker Config (Recommended)">
            Create the transcodingOptions.json file using the above template.

            ```bash icon="docker" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
            nano -p /var/lib/docker/volumes/gateway-lpData/_data/transcodingOptions.json
            ```

            Modify the docker-compose.yml file from the root user's home directory */root/*
            and add the following below `-pixelsPerUnit=1`

            ```bash icon="docker" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
            -transcodingOptions=/root/.lpData/transcodingOptions.json
            ```
          </Tab>

          <Tab title="Linux Config">
            Create the transcodingOptions.json file using the above template.

            ```bash icon="linux" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
            sudo nano /usr/local/bin/lptConfig/transcodingOptions.json
            ```

            Modify the Linux Service file /etc/systemd/system/Livepeer.service and add the
            following below `-pixelsPerUnit=1`

            ```bash icon="linux" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
            -transcodingOptions=/usr/local/bin/lptConfig/transcodingOptions.json \
            ```
          </Tab>

          <Tab title="Windows Config">
            Create the transcodingOptions.json file using the above template.

            Open notepad (or your text editor of choice) paste the template above and save
            the transcodingOptions.json file in the following location.

            In Windows, **`%USERNAME%`** is already a built-in environment variable
            -> You can use it directly.

            ```bash icon="windows" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
            C:\Users\%USERNAME%\.lpData\transcodingOptions.json
            ```

            Modify Windows bat file to include the following command after
            `-pixelsPerUnit=1`

            ```bash icon="windows" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
            -transcodingOptions=C:\Users\%USERNAME%\.lpData\transcodingOptions.json
            ```
          </Tab>
        </Tabs>
      </Expandable>
    </Tab>

    <Tab title="Dual" icon="drone">
      The Livepeer Gateway supports a dual setup configuration that enables a single node to handle both
      traditional video transcoding and AI processing workloads simultaneously.

      This unified architecture reduces infrastructure complexity while providing
      comprehensive media processing capabilities.

      <ScrollableDiagram title="Dual Gateway Architecture: Video & AI Pipelines">
        ```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 TB
            subgraph INPUT["Input Sources"]
                direction LR
                RTMP["RTMP Stream"]
                HTTP["HTTP Upload"]
                AI_REQ["AI Request"]
            end

            GATEWAY["Gateway Node<br/>LivepeerNode"]

            INPUT --> GATEWAY

            subgraph MANAGERS["Session Managers"]
                direction LR
                BSM["BroadcastSessionsManager<br/>Video Transcoding"]
                ASM["AISessionManager<br/>AI Processing"]
            end

            GATEWAY --> BSM
            GATEWAY --> ASM

            subgraph VIDEO["Video Pipeline"]
                SEG["Segment Processing"]
                ORCH_V["Orchestrators<br/>Transcoding"]
                HLS["HLS/DASH Output"]
            end

            subgraph AI["AI Pipeline"]
                PROC["AI Processing"]
                ORCH_AI["Orchestrators<br/>AI Models"]
                OUT_AI["AI Output<br/>Images/Video"]
            end

            BSM --> SEG --> ORCH_V --> HLS
            ASM --> PROC --> ORCH_AI --> OUT_AI

            subgraph PAYMENT["Payment"]
                direction LR
                PAY_SEG["Per Segment"]
                PAY_PIX["Per Pixel"]
            end

            ORCH_V --> PAY_SEG
            ORCH_AI --> PAY_PIX

            classDef default fill:#1a1a1a,color:#fff,stroke:#2d9a67,stroke-width:2px
            classDef video fill:#1a1a1a,color:#fff,stroke:#3b82f6,stroke-width:2px
            classDef ai fill:#1a1a1a,color:#fff,stroke:#a855f7,stroke-width:2px
            class RTMP,HTTP,BSM,SEG,ORCH_V,HLS,PAY_SEG video
            class AI_REQ,ASM,PROC,ORCH_AI,OUT_AI,PAY_PIX ai
            style INPUT fill:#0d0d0d,stroke:#2d9a67,stroke-width:1px
            style MANAGERS fill:#0d0d0d,stroke:#2d9a67,stroke-width:1px
            style VIDEO fill:#0d0d0d,stroke:#3b82f6,stroke-width:1px
            style AI fill:#0d0d0d,stroke:#a855f7,stroke-width:1px
            style PAYMENT fill:#0d0d0d,stroke:#2d9a67,stroke-width:1px
        ```
      </ScrollableDiagram>

      ## Overview

      The Gateway's dual capability is enabled by its modular architecture, where different
      managers handle specific workflows while sharing common infrastructure for media ingestion,
      payment processing, and result delivery.

      The LivepeerNode struct contains fields for both traditional transcoding (Transcoder, TranscoderManager)
      and AI processing (AIWorker, AIWorkerManager) <DoubleIconLink label="livepeernode.go" href="https://github.com/livepeer/go-livepeer/blob/5691cb48/core/livepeernode.go" iconLeft="github" />

      The Gateway determines the processing type based on the request:

      * Standard transcoding requests go through the BroadcastSessionsManager
      * AI requests go through the AISessionManager with AI-specific authentication and pipeline selection <DoubleIconLink label="ai_auth.go" href="https://github.com/livepeer/go-livepeer/blob/5691cb48/server/ai_auth.go" iconLeft="github" />

      The Gateway initializes with two distinct session managers:

      ```go icon="terminal" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
      // Traditional transcoding session manager
      sessManager = NewSessionManager(ctx, s.LivepeerNode, params)
      ```

      ```go icon="terminal" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
      // AI processing session manager
      AISessionManager: NewAISessionManager(lpNode, AISessionManagerTTL)
      ```

      **Key Differences**

      <StyledTable variant="bordered">
        <thead>
          <TableRow header>
            <TableCell header>Aspect</TableCell>
            <TableCell header>Video Transcoding</TableCell>
            <TableCell header>AI Pipelines</TableCell>
          </TableRow>
        </thead>

        <tbody>
          <TableRow>
            <TableCell>Processing Type</TableCell>
            <TableCell>Format/bitrate conversion</TableCell>
            <TableCell>AI model inference</TableCell>
          </TableRow>

          <TableRow>
            <TableCell>Session Manager</TableCell>
            <TableCell><code>BroadcastSessionsManager</code></TableCell>
            <TableCell><code>AISessionManager</code></TableCell>
          </TableRow>

          <TableRow>
            <TableCell>Payment Model</TableCell>
            <TableCell>Per segment</TableCell>
            <TableCell>Per pixel processed</TableCell>
          </TableRow>

          <TableRow>
            <TableCell>Protocol</TableCell>
            <TableCell>Standard HLS/DASH</TableCell>
            <TableCell>Trickle protocol for real-time AI</TableCell>
          </TableRow>

          <TableRow>
            <TableCell>Components</TableCell>
            <TableCell>RTMP Server, Playlist Manager</TableCell>
            <TableCell>MediaMTX, Trickle Server</TableCell>
          </TableRow>
        </tbody>
      </StyledTable>

      ## Configuration

      To configure a Gateway to handle both video transcoding and AI processing, you need
      to set the appropriate flags and options when starting the Livepeer binary.

      **Essential Flags**

      To enable dual setup, configure the Gateway with the following flags:

      <StyledTable variant="bordered">
        <thead>
          <TableRow header>
            <TableCell header>Flag</TableCell>
            <TableCell header>Description</TableCell>
            <TableCell header align="center">Required</TableCell>
          </TableRow>
        </thead>

        <tbody>
          <TableRow>
            <TableCell><code>-Gateway</code></TableCell>
            <TableCell>Run as a Gateway node</TableCell>
            <TableCell align="center">✓</TableCell>
          </TableRow>

          <TableRow>
            <TableCell><code>-httpIngest</code></TableCell>
            <TableCell>Enable HTTP ingest for AI requests</TableCell>
            <TableCell align="center">✓</TableCell>
          </TableRow>

          <TableRow>
            <TableCell><code>-transcodingOptions</code></TableCell>
            <TableCell>Transcoding profiles for video</TableCell>
            <TableCell align="center">✓</TableCell>
          </TableRow>

          <TableRow>
            <TableCell><code>-AIServiceRegistry</code></TableCell>
            <TableCell>Enable AI service registry</TableCell>
            <TableCell align="center">✓</TableCell>
          </TableRow>
        </tbody>
      </StyledTable>

      See: <DoubleIconLink label="cmd/livepeer/livepeer.go" href="https://github.com/livepeer/go-livepeer/blob/5691cb48/cmd/livepeer/livepeer.go" iconLeft="github" />

      ### AI-Specific Configuration

      ```bash AI flags icon="user-robot" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
      -aiModels=${env:HOME}/.lpData/cfg/aiModels.json
      -aiModelsDir=${env:HOME}/.lpData/models
      -aiRunnerContainersPerGPU=1
      -livePaymentInterval=5s
      ```

      ### Transcoding Configuration

      Note, if the `transcodingOptions.json` file is not provided, the Gateway will use the default transcoding profiles `-transcodingOptions=P240p30fps16x9,P360p30fps16x9`.

      ```bash Transcoding flags icon="film-canister" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
      # -transcodingOptions=P240p30fps16x9,P360p30fps16x9
      -transcodingOptions=${env:HOME}/.lpData/cfg/transcodingOptions.json
      -maxSessions=10
      -nvidia=all  # or specific GPU IDs
      ```

      <Note>
        `-nvidia` and NVIDIA drivers are only required for GPU transcoding hosts. A
        Gateway-only routing setup does not require NVIDIA drivers.
      </Note>

      ## Deployment

      <Tabs>
        <Tab title="Off-Chain Developement Setup">
          For local development and testing purposes, there is no need to connect to the blockchain payments layer.

          <Note> You will need to run your own Orchestrator node for local development. </Note>

          ```bash Off-Chain Gateway Deployment with dual capabilities icon="terminal" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
          livepeer -gateway \
              -httpIngest \
              -transcodingOptions=${env:HOME}/.lpData/offchain/transcodingOptions.json \
              -orchAddr=0.0.0.0:8935 \
              -httpAddr=0.0.0.0:9935 \
              -httpIngest \
              -v=6

              # Verify these
              -aiServiceRegistry \
              -aiModels=${env:HOME}/.lpData/cfg/aiModels.json \
              -aiModelsDir=${env:HOME}/.lpData/models \
              -aiRunnerContainersPerGPU=1 \
          ```
        </Tab>

        <Tab title="On-Chain Production Setup">
          For production deployment with blockchain integration

          You will need an ETH account with funds to pay for transcoding and AI processing and set the following environment variables:
          `$ETH_SECRET`
          `$ETH_ACCT_ADDR`

          ```bash On-Chain Gateway Deployment with dual capabilities icon="terminal" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
          livepeer -gateway \
              -transcodingOptions=${env:HOME}/.lpData/offchain/transcodingOptions.json \
              -orchAddr=0.0.0.0:8935 \
              -httpAddr=0.0.0.0:9935 \
              -httpIngest \
              -v=6 \
              -network=arbitrum-one-mainnet \
              -ethUrl=https://arb1.arbitrum.io/rpc \
              -ethPassword=<ETH_SECRET> \
              -ethAcctAddr=<ETH_ACCT_ADDR> \
              -v=6

              # verfiy these
              -aiServiceRegistry \
              -aiModels=${env:HOME}/.lpData/cfg/aiModels.json \
              -aiModelsDir=${env:HOME}/.lpData/models \
              -aiRunnerContainersPerGPU=1 \
              -livePaymentInterval=5s
          ```
        </Tab>
      </Tabs>

      ## Combined Gateway/Orchestrator AI-Enabled Deployment

      For nodes that handle both orchestration and AI processing

      ```bash Combined Gateway/OrchestratorOn-Chain Deployment icon="terminal" theme={"theme":{"light":"github-light","dark":"dark-plus"}}

          livepeer -orchestrator -aiWorker -aiServiceRegistry \
              -serviceAddr=0.0.0.0:8935 \
              -nvidia=all \
              -aiModels=${env:HOME}/.lpData/cfg/aiModels.json \
              -aiModelsDir=${env:HOME}/.lpData/models \
              -network=arbitrum-one-mainnet \
              -ethUrl=https://arb1.arbitrum.io/rpc \
              -ethPassword=<ETH_SECRET> \
              -ethAcctAddr=<ETH_ACCT_ADDR> \
              -ethOrchAddr=<ORCH_ADDR>
      ```

      ## Troubleshooting

      **Common Issues**

      * **AI models not loading:** Check `-aiModelsDir` and model file permissions
      * **GPU transcoding failures:** Verify NVIDIA drivers and `-nvidia` configuration (only required for GPU transcoding hosts)
      * **Port conflicts:** Ensure `-rtmpAddr`, `-httpAddr`, and `-cliAddr` are available
      * **Memory pressure:** Monitor AI model memory usage, adjust `-aiRunnerContainersPerGPU`

      **Debug Commands**

      ```bash icon="terminal" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
          # Check transcoding capabilities
          curl http://localhost:8935/getBroadcastConfig

          # Test AI endpoint
          curl -X POST http://localhost:8935/text-to-image \
          -H "Content-Type: application/json" \
          -d '{"prompt":"test image"}'

          # Monitor logs
          livepeer -gateway -v=6 2>&1 | grep -E "(transcode|AI|segment)"
      ```

      <br />

      ## Example Setup

      The box setup for local development demonstrates running a Gateway that handles both types of processing.

      <Note>
        The embedded `box/box.md` excerpt is unavailable in this docs branch.
        Review the full example setup in the upstream repository:
        [livepeer/go-livepeer `box/box.md`](https://github.com/livepeer/go-livepeer/blob/master/box/box.md).
      </Note>
    </Tab>
  </Tabs>
</BorderedBox>
