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

# Livepeer Nodes and Capabilities

> An introduction to the key actors of the Livepeer protocol, their roles and responsibilities, and how they interact with each other and the protocol to provide the network's core capabilities.

export const Image = ({src, alt = "", caption, icon, hint, fullwidth = true, className = "", style = {}, ...rest}) => {
  icon = icon ? icon : "arrow-turn-down-right";
  return <Frame caption={caption} hint={hint} className={className} style={style} {...rest}>
      <img src={src} alt={alt} style={{
    width: fullwidth ? "100%" : undefined
  }} />
    </Frame>;
};

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 Quote = ({children, className = "", style = {}, ...rest}) => {
  const quoteStyle = {
    fontSize: "1rem",
    textAlign: 'center',
    opacity: 1,
    fontStyle: 'italic',
    color: 'var(--lp-color-accent)',
    border: '1px solid var(--lp-color-border-default)',
    borderRadius: "8px",
    padding: "var(--lp-spacing-4)",
    margin: '1rem 0',
    ...style
  };
  return <blockquote className={className} style={quoteStyle} {...rest}>{children}</blockquote>;
};

export const FrameQuote = ({children, author, source, href, frame = true, align = 'right', borderColor, img, spacing = true, className = "", style = {}, ...props}) => {
  const alignmentMap = {
    left: 'flex-start',
    center: 'center',
    right: 'flex-end'
  };
  const content = <blockquote style={{
    display: 'flex',
    flexDirection: 'column',
    padding: '0.75rem 1rem 0.25rem 1rem',
    gap: "var(--lp-spacing-1)",
    margin: 0
  }}>
      <div style={{
    borderLeft: `4px solid var(--lp-color-accent)`,
    paddingLeft: "var(--lp-spacing-4)",
    fontStyle: 'italic'
  }}>
        {children}
      </div>
      {(author || source) && <div style={{
    display: 'flex',
    justifyContent: alignmentMap[align] || 'flex-end',
    marginLeft: align === 'left' ? "var(--lp-spacing-6)" : 0
  }}>
          <div style={{
    textAlign: align === 'center' ? 'center' : 'left'
  }}>
            {author && <div>
                {spacing && <br />}
                <Icon icon="microphone" />{' '}
                <strong>
                  <em>{author}</em>
                </strong>
              </div>}
            {source && (href ? <a href={href} target="_blank" rel="noopener noreferrer">
                  <span style={{
    opacity: 0.7,
    fontStyle: 'italic',
    borderBottom: '1px solid var(--lp-color-accent)',
    fontSize: "1rem"
  }}>
                    {source}
                  </span>{' '}
                  <Icon icon="arrow-up-right" size={12} color="var(--lp-color-accent)" />
                </a> : <span style={{
    opacity: 0.7,
    fontStyle: 'italic',
    fontSize: "1rem"
  }}>
                  {source}
                </span>)}
          </div>
        </div>}
    </blockquote>;
  return frame ? <div className={className} style={{
    border: borderColor ? `1px solid ${borderColor}` : 'none',
    borderRadius: "8px",
    overflow: 'hidden',
    ...style
  }} {...props}>
      <Frame style={{
    border: 'none'
  }}>
        {img && <img src={img.src} alt={img.alt} />}
        {content}
      </Frame>
    </div> : content;
};

export const YouTubeVideo = ({embedUrl, url, title = "", author = "", hint = "", caption, className = "", style = {}, ...rest}) => {
  const toEmbedUrl = value => {
    if (!value || typeof value !== "string") return "";
    const source = value.trim();
    if (!source) return "";
    try {
      const parsed = new URL(source);
      const host = parsed.hostname.replace(/^www\./, "");
      if (host === "youtube.com" || host === "youtube-nocookie.com") {
        if (parsed.pathname.startsWith("/embed/")) return source;
        const videoId = parsed.pathname.startsWith("/shorts/") ? parsed.pathname.split("/").filter(Boolean)[1] : parsed.searchParams.get("v");
        if (!videoId) return "";
        const params = new URLSearchParams(parsed.search);
        params.delete("v");
        const query = params.toString();
        return `https://www.youtube.com/embed/${videoId}${query ? `?${query}` : ""}`;
      }
      if (host === "youtu.be") {
        const videoId = parsed.pathname.split("/").filter(Boolean)[0];
        if (!videoId) return "";
        const query = parsed.searchParams.toString();
        return `https://www.youtube.com/embed/${videoId}${query ? `?${query}` : ""}`;
      }
    } catch (_err) {
      return "";
    }
    return "";
  };
  const resolvedEmbedUrl = toEmbedUrl(embedUrl || url);
  if (!resolvedEmbedUrl) {
    return null;
  }
  const isValidYouTubeUrl = resolvedEmbedUrl.includes("youtube.com/embed/");
  if (!isValidYouTubeUrl) {
    console.warn("Invalid YouTube embed URL:", embedUrl || url);
    return null;
  }
  const buildCaption = () => {
    if (caption) return caption;
    if (!author && !title) return null;
    return <span style={{
      display: "flex",
      flexDirection: "column",
      alignItems: "center",
      textAlign: "center",
      lineHeight: 1.2
    }}>
        <span>
          {author && <>
              <Icon icon="microphone" size={16} /> <strong>{author}</strong>
            </>}
          {author && title ? `${" "} • ${title}` : title}
        </span>
      </span>;
  };
  const captionContent = buildCaption();
  return <Frame className={className} style={style} {...hint ? {
    hint
  } : {}} {...captionContent ? {
    caption: captionContent
  } : {}} {...rest}>
      <iframe className="w-full aspect-video rounded-xl" src={resolvedEmbedUrl} title={title || author || "YouTube Video"} allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowFullScreen />
    </Frame>;
};

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 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>;
};

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 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>;
};

export const DynamicTableV2 = ({tableTitle = null, headerList = [], itemsList = [], monospaceColumns = [], columnWidths = {}, columnConfig = {}, showSeparators = false, margin, className = '', style = {}, ...rest}) => {
  if (!headerList.length) {
    return <div>No headers provided</div>;
  }
  const tableRef = useRef(null);
  const [measuredColumnWidths, setMeasuredColumnWidths] = useState({});
  const measureFitColumns = () => {
    const tableElement = tableRef.current;
    if (!tableElement) {
      return;
    }
    const nextWidths = headerList.reduce((accumulator, header, index) => {
      const config = columnConfig?.[header] || ({});
      if (!config.fitContent) {
        return accumulator;
      }
      const contentNodes = tableElement.querySelectorAll(`[data-docs-column-key="${index}"] [data-docs-fit-content]`);
      let maxContentWidth = 0;
      contentNodes.forEach(node => {
        const width = Math.ceil(node.getBoundingClientRect().width);
        if (width > maxContentWidth) {
          maxContentWidth = width;
        }
      });
      if (maxContentWidth > 0) {
        accumulator[header] = `${maxContentWidth + 16}px`;
      }
      return accumulator;
    }, {});
    setMeasuredColumnWidths(currentWidths => {
      const currentEntries = Object.entries(currentWidths);
      const nextEntries = Object.entries(nextWidths);
      if (currentEntries.length === nextEntries.length && nextEntries.every(([header, width]) => currentWidths[header] === width)) {
        return currentWidths;
      }
      return nextWidths;
    });
  };
  useLayoutEffect(() => {
    measureFitColumns();
  }, [headerList, itemsList, columnConfig]);
  useEffect(() => {
    const tableElement = tableRef.current;
    if (!tableElement || typeof ResizeObserver === 'undefined') {
      return undefined;
    }
    const resizeObserver = new ResizeObserver(() => {
      measureFitColumns();
    });
    resizeObserver.observe(tableElement);
    if (tableElement.parentElement) {
      resizeObserver.observe(tableElement.parentElement);
    }
    return () => {
      resizeObserver.disconnect();
    };
  }, [headerList, itemsList, columnConfig]);
  const fitHeaders = headerList.filter(header => columnConfig?.[header]?.fitContent);
  const hasMeasuredFitColumns = fitHeaders.length === 0 || fitHeaders.every(header => Boolean(measuredColumnWidths[header]));
  const getColumnStyle = (header, isMonospace = false) => {
    const config = columnConfig?.[header] || ({});
    const fitContent = Boolean(config.fitContent);
    const fluid = Boolean(config.fluid);
    const nowrap = Boolean(config.nowrap) || fitContent || isMonospace;
    const preferredWidth = columnWidths[header];
    const measuredWidth = measuredColumnWidths[header];
    return {
      ...fitContent && measuredWidth ? {
        width: measuredWidth,
        minWidth: measuredWidth,
        maxWidth: measuredWidth
      } : {},
      ...!fitContent && !fluid && preferredWidth ? {
        minWidth: preferredWidth
      } : {},
      ...nowrap ? {
        whiteSpace: 'nowrap'
      } : {
        wordWrap: 'break-word',
        overflowWrap: 'break-word'
      }
    };
  };
  const getColumnTrackStyle = header => {
    const config = columnConfig?.[header] || ({});
    const fitContent = Boolean(config.fitContent);
    const fluid = Boolean(config.fluid);
    const preferredWidth = columnWidths[header];
    const measuredWidth = measuredColumnWidths[header];
    if (fitContent && measuredWidth) {
      return {
        width: measuredWidth,
        minWidth: measuredWidth,
        maxWidth: measuredWidth
      };
    }
    if (fluid) {
      return {};
    }
    if (preferredWidth) {
      return {
        width: preferredWidth
      };
    }
    return {};
  };
  const renderCellContent = (header, content) => {
    const config = columnConfig?.[header] || ({});
    if (!config.fitContent) {
      return content;
    }
    return <div data-docs-fit-content style={{
      display: 'inline-flex',
      alignItems: 'center',
      whiteSpace: 'nowrap',
      width: 'max-content',
      maxWidth: 'none'
    }}>
        {content}
      </div>;
  };
  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 ref={tableRef} data-docs-dynamic-table-v2 style={{
    width: '100%',
    tableLayout: hasMeasuredFitColumns ? 'fixed' : 'auto',
    borderCollapse: 'collapse',
    fontSize: '0.9rem',
    marginTop: 0
  }}>
          <colgroup>
            {headerList.map((header, index) => <col key={index} style={getColumnTrackStyle(header)} />)}
          </colgroup>
          <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} data-docs-column-key={index} style={{
    padding: '10px 8px',
    textAlign: 'left',
    fontWeight: '600',
    color: 'var(--lp-color-on-accent)',
    verticalAlign: 'top',
    ...getColumnStyle(header)
  }}>
                  {renderCellContent(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} data-docs-column-key={colIndex} style={{
      padding: '8px 8px',
      fontFamily: isMonospace ? 'monospace' : 'inherit',
      verticalAlign: 'top',
      ...getColumnStyle(header, isMonospace)
    }}>
                          {renderCellContent(header, isMonospace ? <code>{value}</code> : value)}
                        </td>;
  })}
                  </tr>)}
          </tbody>
        </table>
      </div>
    </div>;
};

export const QuadGrid = ({children, icon = "arrows-spin", iconSize = 50, iconColor = "var(--lp-color-accent)", iconBackgroundColor = "transparent", gap, spinDuration = "10s", className = "", style = {}, ...rest}) => {
  if (children == null) {
    console.warn("[QuadGrid] Missing children");
    return null;
  }
  return <div className={className} style={{
    position: "relative",
    ...style
  }} {...rest}>
      <style>{`
        @keyframes quadGridSpin {
          from { transform: rotate(0deg); }
          to { transform: rotate(360deg); }
        }
        .lp-quad-grid-layout {
          display: grid;
          grid-template-columns: repeat(2, minmax(0, 1fr));
          grid-auto-rows: 1fr;
          gap: var(--lp-quad-grid-gap, 0);
        }
        @media (max-width: 768px) {
          .lp-quad-grid-layout {
            grid-template-columns: 1fr;
          }
        }
        @media (prefers-reduced-motion: reduce) {
          .lp-quad-grid-icon {
            animation: none !important;
          }
        }
      `}</style>
      <div className="lp-quad-grid-layout" style={{
    "--lp-quad-grid-gap": gap
  }}>
        {children}
      </div>
      <div style={{
    position: "absolute",
    top: "50%",
    left: "50%",
    transform: "translate(-50%, -50%)",
    zIndex: 10
  }}>
        <div className="lp-quad-grid-icon" style={{
    backgroundColor: iconBackgroundColor,
    borderRadius: "50%",
    padding: "var(--lp-spacing-2)",
    animation: `quadGridSpin ${spinDuration} linear infinite`
  }}>
          <Icon icon={icon} size={iconSize} color={iconColor} />
        </div>
      </div>
    </div>;
};

<YouTubeVideo url="https://www.youtube.com/watch?v=ouTvdJr9dSU" caption="DePIN Day Berlin: Real Promises of DePIN & AI with Shannon Wells [Livepeer]" />

<Accordion title="Summary: Real Promises of DePIN for AI" icon="video">
  Real promises of DePIN for AI that the panel articulates:

  * **Unlock idle GPU capacity.** Huge amounts of hardware sit underutilised across data centres, crypto miners, and consumer machines while AI demand outstrips supply. DePIN networks aggregate that latent supply into usable clusters (Aline: "we cannot have idle GPUs while we have a lot of AI demand").

  * **Pay-per-job pricing instead of pay-for-blocks.** Centralised clouds force you to rent time windows; decentralised inference networks can charge per inference task or per minute transcoded, which is far more efficient for bursty AI workloads (Shannon).

  * **Order-of-magnitude cost reduction.** Livepeer transcoding already runs around 10x cheaper than Web2 cloud equivalents, and the same economics now extend to generative inference.

  * **Make compute a tradable financial asset.** Crypto's core strength is building efficient financial markets; compute may be the largest market in the world, so putting it on-chain drives down the cost of capital and lets compute, AI models, and adjacent assets be financialised (Vincent).

  * **Aggregate the cheapest GPUs globally.** With new training methods (DiLoCo-style infrequent sync), a 20 to 30 percent training inefficiency is fine if you're sourcing GPUs 3 to 4 times cheaper than hyperscalers.

  * **Novel funding models for open-source AI.** Today AI has only two business models (closed labs raising billions, or fully open with no revenue); DePIN plus on-chain IP enables a Stable Diffusion-style middle ground where open models are collectively funded and earn licensing revenue from enterprise users (Vincent).

  * **Cryptographic guarantees for AI.** Privacy, integrity, authenticity, and provenance for data, models, and agent-to-agent interactions (Stepan).

  * **Incentive alignment via mechanism design.** Token rewards plus smart contracts to fairly compensate contributors (data, compute, training) and resist fraud, directly relevant to ongoing lawsuits about uncompensated training data.

  * **Anti-monopoly and fair access.** Keep AI from being owned by a handful of corporations (Meta, OpenAI) or a single state (US, CCP) whose preferences override everyone else's.

  * **Programmable governance for AI systems.** DAOs and on-chain agents allowing users to express preferences over what models get trained, what they optimise for, and how they're used; futarchy and prediction-market governance as an experimental frontier.

  * **Sandbox for governance experimentation.** Crypto lets you test governance mechanisms in weeks with real value at stake, instead of waiting decades (and risking revolutions) for nation-state-scale change.

  * **Geopolitical resilience.** Distributed supply across jurisdictions, not concentrated in one cluster or one country (Aline, briefly).

  * **Repurposability of existing DePIN infrastructure.** Networks built for one workload (e.g. Livepeer's video transcoding) can absorb adjacent AI workloads on the same nodes with the same payment rails, compounding value from already-deployed hardware.
</Accordion>

<CustomDivider style={{ margin: '-1rem 0 -2rem 0' }} />

The protocol's rules and incentives create a self-sustaining ecosystem of participants who provide and consume compute resources in a way that is secure, efficient, and aligned with the network's long-term health.

The network's actors (Orchestrators, Gateways, Delegators) each have distinct roles and incentives that drive the system forward, while the protocol ensures that their interactions are fair and that the network remains robust against bad actors.

<Image src="/snippets/assets/media/diagrams/livepeer_actors_bridge_protocol_network.svg" alt="Livepeer Actors Bridge Protocol Network" caption="Livepeer Protocol and Network Architecture" />

<CustomDivider style={{ margin: "-1rem 0 -2rem 0" }} />

## Livepeer Actors

<Quote>
  In protocol design, “actor” is a formal category used to describe participants with distinct responsibilities, incentives, and interactions.
  Actors are fundamental to describing how the protocol (and network) functions end-to-end.
</Quote>

The protocol defines three core actors, and implements mechanisms to coordinate their interactions and align incentives for the desired network outcomes:

<AccordionGroup>
  <Accordion title="Gateways" icon="route">
    **Function:** Ingests source video or AI inference requests from end users and routes the work to Orchestrators.

    **Purpose:** Connects demand-side applications and users to the Livepeer Network.

    **Economics:** Pays for transcoding services using ETH through the ticket system.

    **Technical role.** Probably the most demanding integration work of the three. Run Gateway software, ingest video or AI requests from end users, handle Orchestrator discovery and selection, manage payment channels and ticket issuance, deal with failover, and bridge the protocol to whatever application is actually consuming the work. This is where most of the engineering surface area lives.

    **Economic role.** They're the demand side and the only source of external revenue. They fund deposits and reserves to back probabilistic tickets, set their own quality/price tradeoffs by selecting Orchestrators, and ultimately decide whether the network's pricing is competitive against centralised alternatives. If Gateways aren't economically satisfied, no one else gets paid.

    **Community role.** Historically the quietest of the three, but increasingly important. Gateway operators are often building products on top – streaming platforms, AI apps, developer tools – and their feedback drives what capabilities Orchestrators add and what the protocol prioritises. The Livepeer AI subnet exists in large part because Gateway-side demand pulled it into existence.
  </Accordion>

  <Accordion title="Delegators" icon="user-check">
    **Function:** Bonds LPT to Orchestrators without running infrastructure directly.

    **Purpose:** Secures the network by delegating stake to Orchestrators.

    **Economics:** Earns rewards by sharing in the fees and inflationary rewards of the Orchestrator they delegate to.

    **Technical role.** Light but real – they need to evaluate Orchestrators (uptime, performance, fee history, reliability), manage their own wallet security, and periodically claim earnings or move stake. No infrastructure, but non-trivial diligence if they're doing it well.

    **Economic role.** Capital allocators. They route LPT toward Orchestrators they believe will earn the most fees and rewards relative to risk, and away from underperformers. In aggregate this is the price signal that shapes the Active Set. They also bear the opportunity cost of locked stake and unbonding periods.

    **Community role.** Lower visibility than Orchestrators but real influence – they're the constituency Orchestrators are courting. Active Delegators participate in governance polls, weigh in on Orchestrator behaviour, and (especially the larger ones) shape sentiment about which Orchestrators are trustworthy. They're the network's accountability layer.
  </Accordion>

  <Accordion title="Orchestrators" icon="microchip">
    **Function:** Runs the hardware that performs transcoding and AI inference work.

    **Purpose:** Registers on-chain, stakes LPT, and bids for work. The top-ranked subset by total stake forms the Active Set, which is eligible to receive jobs in a given round.

    **Economics:** Earns rewards and fees for performing work, after the Orchestrator's configured fee share and Reward Cut are applied.

    **Technical role.** Operate the infrastructure. Run go-livepeer, manage transcoders and GPUs, maintain uptime, keep model containers current for AI work, advertise capabilities, and actually perform jobs. This is the only role in the protocol that requires running hardware.

    **Economic role.** Price the work (`pricePerUnit`), set the split with Delegators (`feeShare`, `rewardCut`), bond self-stake as collateral, redeem winning tickets, and call reward each round. They're a small business inside the network – capex on hardware, opex on power and bandwidth, revenue in ETH and LPT.

    **Community role.** They're the most visible public face of the network. Reputation matters because Delegators are choosing them – so Orchestrators run websites, publish stats, show up on Discord, write guides, help newer operators, and participate in governance discussions. The serious ones are effectively brands.
  </Accordion>
</AccordionGroup>

A fourth specialised worker node is also used:

* **Transcoders** and **AI Workers** - often co-located on Orchestrator nodes - execute video transcoding and AI inference tasks in Docker containers or as external endpoints.

<QuadGrid icon="arrows-spin" iconSize={50} gap="0.5rem">
  <Card title="Orchestrators" icon="microchip" cta="Go to Orchestrators" href="/v2/orchestrators/portal">
    GPU nodes that perform compute operations, earn fees and staking rewards, and participate in governance.

    **Roles**: Perform Compute Operations, participate in governance

    **Types**: Video Orchestrator, AI Orchestrator, Hybrid Orchestrator

    See also: [Orchestrator-Delegate Role](https://github.com/shtukaresearch/livepeer-data-geography/blob/651a56e8c8290b30855f1393543ee9e0961c071c/roles/orchestrator-delegate.md#L3-L6)
  </Card>

  <Card title="Gateways" icon="torii-gate" cta="Go to Gateways" href="/v2/gateways/portal">
    Also known as Broadcasters, these are the clients submitting jobs (video or AI) into the network. The users and builders of the network.

    **Roles**: Submit jobs, route work, manage payment flows, connect to Orchestrators

    **Types**: Video Gateway, AI Gateway, Hybrid Gateway

    See also: [Gateway Role](https://github.com/shtukaresearch/livepeer-data-geography/blob/651a56e8c8290b30855f1393543ee9e0961c071c/roles/gateway.md#L3-L4)
  </Card>

  <Card title="Delegators" icon="coins" cta="Go to Delegators" href="/v2/delegators/portal">
    LPT holders who stake to an Orchestrator.

    **Roles**: Stake LPT, earn rewards, participate in network governance and voting

    **Types**: Individual Delegator, Institutional Delegator, DAO Delegator

    See also: [Orchestrator-Delegate Role](https://github.com/shtukaresearch/livepeer-data-geography/blob/651a56e8c8290b30855f1393543ee9e0961c071c/roles/investor-delegator.md#L3-L6)
  </Card>

  <Card title="AI Workers & Transcoders" icon="laptop-code" cta="Go to Developers" href="/v2/developers/portal">
    Specialised nodes that execute AI inference tasks or video transcoding tasks in Docker containers or as external endpoints

    **Roles**: Execute AI inference or video transcoding tasks, ensure correctness, and contribute to the overall AI & video capabilities of the network
  </Card>
</QuadGrid>

<CustomDivider style={{ margin: "-1rem 0 -2rem 0" }} />

{/* The sections below break down the current capabilities, the functionality they enable today, and the potential extensions on the horizon. */}

{/* SCOPE: every actor and stakeholder in the system, named, with their incentive and where they're documented in depth. Not how-to. Just who and why. */}

## Livepeer Capabilities

The network's workload-agnostic design, enabled by crypto-economic primitives, allows it to evolve organically based on demand and supply dynamics without requiring protocol changes for each new capability.

<CardGroup cols={2}>
  <Card title="Video & Media Streaming" icon="video">
    Adaptive bitrate transcoding, live streaming, and VOD ingest at sub-cloud cost. The original Livepeer workload, now serving production traffic for projects such as [Livepeer Studio](https://livepeer.studio) and Streamplace.
  </Card>

  <Card title="AI and Agents" icon="microchip-ai">
    Open and proprietary models running on Orchestrator GPUs: text-to-image, image-to-image, image-to-video, audio-to-text, text-to-speech, segment-anything-2, LLM, upscale, and frame interpolation pipelines.
  </Card>

  <Card title="Real-time AI Video" icon="film">
    Live video-to-video (LV2V) pipelines that apply AI effects to a webcam or stream at sub-second latency. Powers [Daydream](https://docs.daydream.live), [ComfyStream](https://github.com/livepeer/comfystream), [pytrickle](https://github.com/livepeer/pytrickle), and creator tooling such as [Storyboard](https://github.com/livepeer/storyboard).
  </Card>

  <Card title="Generalised Real-time Compute (BYOC)" icon="cubes">
    [BYOC](https://github.com/livepeer/ai-worker) - Bring Your Own Container, lets builders ship a containerised workload that runs on Orchestrator GPUs and pays through the standard payment flow.
  </Card>
</CardGroup>

<Tip> The protocol is workload-neutral. Adding a new capability does not require a hard fork or a new token. It requires a new pipeline definition, an [Orchestrator](/v2/about/network/actors) willing to run it, and a [Gateway](/v2/about/network/actors) willing to route to it. </Tip>

<CustomDivider style={{ margin: '-1rem 0 -2rem 0' }} />

## Livepeer Capability Frontier

The forward roadmap is a function of the same three properties that define current capability: supply growth, settlement scalability, and workload-runtime extensibility. Each direction below is grounded in active engineering or [LIP discussion](https://github.com/livepeer/LIPs).

<AccordionGroup>
  <Accordion title="Provenance and metadata for AI outputs" icon="fingerprint">
    Cryptographic attestation of which Orchestrator ran which model with which inputs, anchored to on-chain receipts. Combined with watermarking and signed-output flows, this makes Livepeer a candidate substrate for compliant AI generation in markets that require traceability (advertising, news, regulated industries). The building blocks already exist in the [AI subnet's](https://github.com/livepeer/ai-runner) job receipts; the remaining work is standardising the provenance schema and exposing it through the [AI Gateway API](https://github.com/livepeer/go-livepeer).
  </Accordion>

  <Accordion title="Data oracles and external integration" icon="satellite-dish">
    Inference workloads increasingly need live external data: market prices, sensor feeds, real-time event streams. The same Gateway pattern that routes a video segment can route a job that fuses on-network compute with off-network data, with the oracle relationship secured by the same stake and slashing model. This extends the network from a static-input compute provider into a real-time data-aware inference layer.
  </Accordion>

  <Accordion title="Cross-chain interoperability" icon="link">
    LPT and ETH already span [Ethereum mainnet and Arbitrum One](/v2/about/protocol/architecture), with the bridge handling deposits, withdrawals, and round-trip stake flows. Cross-chain extensions in scope include bridging payment surfaces to other rollups, exposing job settlement on alternative L2s, and enabling LPT delegation from holders on chains where they already hold positions. The protocol's modular design keeps these extensions additive.
  </Accordion>

  <Accordion title="Agent and creative-pipeline infrastructure" icon="robot">
    [Storyboard](https://github.com/livepeer/storyboard)'s agent runtime, [Daydream](https://docs.daydream.live)'s hosted creative API, and the [NaaP](https://github.com/livepeer/naap) plugin platform together point at a network surface that resembles a programmable creative studio. The combination of LV2V, BYOC, and a stable payment rail makes Livepeer a natural backend for autonomous creative agents, where model orchestration, asset persistence, and rights tracking happen across composed services on top of the same compute layer.
  </Accordion>

  <Accordion title="Generalised real-time compute" icon="bolt-lightning">
    Real-time is the niche the network is uniquely positioned for. Sub-second-latency workloads tolerate decentralised supply far better than batch training does, and the [probabilistic micropayment](/v2/about/protocol/mechanisms) design was built for high-frequency, low-value-per-job traffic. Future workload classes that fit this profile include real-time translation and dubbing, multi-agent coordination loops, embodied-AI control surfaces, and gaming-grade interactive inference. The protocol layer does not need to change to absorb them.
  </Accordion>
</AccordionGroup>

<CustomDivider style={{ margin: '-1rem 0 -2rem 0' }} />

## Livepeer Integration Capabilities

Livepeer sits inside a wider DePIN and Web3 stack. Capability extensions come from composition with adjacent infrastructure. The protocol's clean separation between on-chain coordination and off-chain execution means that storage, security, and payment layers can be plugged in without changing the core contracts.

The integration surface will continue to expand as new [Gateway](/v2/about/network/actors) operators, application platforms, and [Special Purpose Entities](/v2/about/protocol/governance-and-treasury) join the ecosystem. Recent additions include the [Network as a Platform (NaaP)](https://github.com/livepeer/naap) plugin architecture, the [Storyboard](https://github.com/livepeer/storyboard) creative SDK, and the data-MCP server that exposes network metrics through standard agent tooling.

### Current Integrations

<BorderedBox variant="accent" margin="0 0 2rem 0">
  <Tabs>
    <Tab title="Security & Verification" icon="shield-check">
      The network's security posture combines stake-weighted [Orchestrator selection](/v2/about/protocol/mechanisms) on the protocol side with verification primitives on the execution side.

      Active areas of integration include trusted execution environments for confidential inference, attestation flows for output provenance, and [remote-signer architectures](https://github.com/livepeer/go-livepeer) that separate node operation from key custody.

      These extensions matter most where workloads carry compliance, IP, or biometric sensitivity.
    </Tab>

    <Tab title="Data & Storage" icon="database">
      Livepeer does not store source media or model weights; Orchestrators pull what they need at job time.

      That neutrality has produced a strong pattern of integration with decentralised storage projects across the ecosystem, where [IPFS](https://ipfs.tech), [Arweave](https://www.arweave.org), and [Filecoin](https://filecoin.io) handle persistence while Livepeer handles compute.

      The same pattern extends to model checkpoints distributed via [Hugging Face](https://huggingface.co), with [Orchestrators](/v2/about/network/actors) downloading and warming models locally.
    </Tab>

    <Tab title="Payments & Settlement" icon="money-bill-transfer">
      All job settlement runs on [Arbitrum One](https://arbitrum.io) through the [TicketBroker contract](/v2/about/protocol/blockchain-contracts) using [Probabilistic Micropayments](/v2/about/protocol/mechanisms) denominated in ETH.

      [Gateways](/v2/about/network/actors) bridge user-friendly payment surfaces (USD pricing via oracles, prepaid credit balances, fiat on-ramps) into the protocol's ETH-native flow.

      This leaves the protocol simple and auditable, while letting individual Gateway operators serve customers in whatever currency or billing model suits their market.
    </Tab>
  </Tabs>
</BorderedBox>

{/* The three on-network roles. Use QuadGrid or similar. */}

{/* GPU operators. Stake LPT. Earn ETH from work and LPT from rewards. Link → Orchestrators tab. */}

{/* Route demand. Hold ETH deposit/reserve. Pay orchestrators via tickets. Link → Gateways tab. */}

{/* LPT holders. Stake to an orchestrator. Earn share of rewards. Vote in governance. Link → Delegators tab. */}

{/* Roles outside the protocol that matter for the system. */}

{/* Consumers of streams and AI outputs. Don't interact with the protocol directly. */}

{/* Build on Livepeer. Use gateway APIs. Link → Developers tab. */}

{/* Proposers, voters, treasury beneficiaries, SPEs, GovWorks, Foundation. Link → Community tab. */}

{/* DynamicTableV2: actor / responsibility / incentive / where to learn more. */}
