> ## Documentation Index
> Fetch the complete documentation index at: https://na-36-mintlify-aebde2c5.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Video on Livepeer

> What Livepeer provides for video developers: livestreaming, VOD transcoding, playback, and access control via the Studio API and SDKs.

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

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

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

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

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

<CenteredContainer preset="readable90">
  <Tip>The Studio API and SDKs give you full lifecycle management for livestreams and video assets with four lines of code -- no infrastructure to operate.</Tip>
</CenteredContainer>

***

Livepeer's video infrastructure handles transcoding, packaging, and delivery for both live and recorded video. The Studio API exposes this as a REST interface with official SDKs in TypeScript, Python, Go, and React. You call the API; the network provides the compute.

Video workloads on Livepeer use LPT stake-weighted routing and round-based rewards -- this is the original Livepeer use case and the most mature part of the network.

<CustomDivider middleText="What You Can Build" />

## Capabilities

The Studio API covers four workload types:

**Livestreams** -- Create a stream, get an RTMP ingest URL, and Livepeer handles transcoding to adaptive bitrate HLS for delivery. Sub-second WebRTC playback is available for latency-sensitive applications.

**VOD assets** -- Upload a video file, Livepeer transcodes it to multiple renditions. The asset is playable immediately via HLS or MP4.

**Webhooks** -- Subscribe to events (stream started, stream ended, asset ready, asset failed) via HTTP callbacks. Event-driven architectures do not need to poll the API.

**Access control** -- Gate content behind JWTs or webhook-based authorisation. JWT playback policy signs a token server-side; the player verifies it at playback.

<CustomDivider middleText="API Surface" />

## API surface

All video operations go through the Studio REST API at `https://livepeer.studio/api`. Authentication uses a Bearer token from the Studio dashboard.

<StyledTable variant="bordered">
  <thead>
    <TableRow header>
      <TableCell header>Resource</TableCell>
      <TableCell header>Key operations</TableCell>
      <TableCell header>Notes</TableCell>
    </TableRow>
  </thead>

  <tbody>
    <TableRow>
      <TableCell>**Streams**</TableCell>
      <TableCell>create, get, update, delete, list</TableCell>
      <TableCell>Returns RTMP ingest URL and playback ID</TableCell>
    </TableRow>

    <TableRow>
      <TableCell>**Assets**</TableCell>
      <TableCell>create (upload), get, update, delete, list</TableCell>
      <TableCell>Supports direct upload and URL-based import</TableCell>
    </TableRow>

    <TableRow>
      <TableCell>**Webhooks**</TableCell>
      <TableCell>create, list, delete, test</TableCell>
      <TableCell>`stream.started`, `stream.idle`, `asset.ready`, `asset.failed`</TableCell>
    </TableRow>

    <TableRow>
      <TableCell>**Signing keys**</TableCell>
      <TableCell>create, list, delete</TableCell>
      <TableCell>Used to sign JWTs for access-controlled content</TableCell>
    </TableRow>

    <TableRow>
      <TableCell>**Multistream targets**</TableCell>
      <TableCell>create, list, delete</TableCell>
      <TableCell>Simultaneously push to YouTube, Twitch, custom RTMP</TableCell>
    </TableRow>
  </tbody>
</StyledTable>

<CustomDivider middleText="SDKs" />

## SDKs

Four officially supported SDKs cover the full Studio API surface including video resources and AI inference:

```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
# TypeScript / JavaScript (npm v3.5.0)
npm install livepeer

# Python
pip install livepeer

# Go
go get github.com/livepeer/livepeer-go

# React UI components (Player, Broadcast)
npm install @livepeer/react
```

All SDKs share the same resource structure. Initialise with your API key:

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={"theme":{"light":"github-light","dark":"dark-plus"}}
    import { Livepeer } from 'livepeer';

    const client = new Livepeer({ apiKey: process.env.LIVEPEER_API_KEY });

    const stream = await client.stream.create({
      name: 'my-stream',
    });

    console.log(stream.rtmpIngestUrl); // push here from OBS / ffmpeg
    console.log(stream.playbackId);    // use in Player component
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={"theme":{"light":"github-light","dark":"dark-plus"}}
    from livepeer import Livepeer
    import os

    client = Livepeer(api_key=os.environ['LIVEPEER_API_KEY'])

    stream = client.stream.create(request={'name': 'my-stream'})
    print(stream.stream.rtmp_ingest_url)
    print(stream.stream.playback_id)
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={"theme":{"light":"github-light","dark":"dark-plus"}}
    import (
      "context"
      "github.com/livepeer/livepeer-go"
      "github.com/livepeer/livepeer-go/models/components"
    )

    client := livepeer.New(livepeer.WithSecurity(os.Getenv("LIVEPEER_API_KEY")))

    stream, err := client.Stream.Create(context.Background(), components.NewStreamPayload{
      Name: "my-stream",
    })
    ```
  </Tab>
</Tabs>

<CustomDivider middleText="Playback" />

## Playback protocols

Livepeer delivers content over two protocols:

**HLS** -- Standard adaptive bitrate streaming. Works with any HLS player: `@livepeer/react` Player, HLS.js, Video.js, or native iOS/Android players. Latency is typically 3-8 seconds.

**WebRTC** -- Sub-second latency for live interactive applications. Supported via the `@livepeer/react` Player and Broadcast components. Requires no additional configuration -- the player selects WebRTC automatically when available.

The `@livepeer/react` Player handles both protocols, fallback logic, and access-controlled playback via the `jwt` prop:

```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from '@livepeer/react/player';

export const VideoPlayer = ({ playbackId }: { playbackId: string }) => (
  <Player.Root src={`https://livepeercdn.studio/hls/${playbackId}/index.m3u8`}>
    <Player.Container>
      <Player.Video />
      <Player.Controls />
    </Player.Container>
  </Player.Root>
);
```

<CustomDivider middleText="Pricing" />

## Pricing

<StyledTable variant="bordered">
  <thead>
    <TableRow header>
      <TableCell header>Tier</TableCell>
      <TableCell header>Monthly</TableCell>
      <TableCell header>Transcoding</TableCell>
      <TableCell header>Concurrent viewers</TableCell>
    </TableRow>
  </thead>

  <tbody>
    <TableRow>
      <TableCell>**Free**</TableCell>
      <TableCell>\$0</TableCell>
      <TableCell>1,000 min/month</TableCell>
      <TableCell>30</TableCell>
    </TableRow>

    <TableRow>
      <TableCell>**Growth**</TableCell>
      <TableCell>$100 minimum</TableCell>       <TableCell>$0.33 per 60 min</TableCell>
      <TableCell>50,000</TableCell>
    </TableRow>

    <TableRow>
      <TableCell>**Enterprise**</TableCell>
      <TableCell>\$2,500 annual commit</TableCell>
      <TableCell>Custom</TableCell>
      <TableCell>Custom</TableCell>
    </TableRow>
  </tbody>
</StyledTable>

<CustomDivider />

## Related pages

<CardGroup cols={2}>
  <Card title="Transcoding Quickstart" icon="fast-forward" href="/v2/developers/get-started/transcoding-quickstart">
    Create your first stream and test end-to-end in 15 minutes.
  </Card>

  <Card title="Developer Stack" icon="layer-group" href="/v2/developers/concepts/developer-stack">
    Understand all three access layers and when to use Studio vs a self-hosted gateway.
  </Card>

  <Card title="Access Control" icon="lock" href="/v2/developers/guides/video/access-control">
    Gate content with JWTs or webhook-based authorisation.
  </Card>

  <Card title="Webhooks" icon="bell" href="/v2/developers/guides/video/webhooks">
    Subscribe to stream and asset events for event-driven applications.
  </Card>
</CardGroup>
