# Delete an asset
Source: https://docs.livepeer.org/v1/api-reference/asset/delete
DELETE /asset/{assetId}
# Retrieve an asset
Source: https://docs.livepeer.org/v1/api-reference/asset/get
GET /asset/{assetId}
# Retrieve assets
Source: https://docs.livepeer.org/v1/api-reference/asset/get-all
GET /asset
# Overview
Source: https://docs.livepeer.org/v1/api-reference/asset/overview
The Assets API is used to create, retrieve, update, delete assets object from pipeline.
### Asset object
This is a unique identifier for the asset.
Type of the asset. This can be either 'video' or 'audio'.
Used to form playback URL and storage folder.
Whether to generate MP4s for the asset.
Attach Livepeer Studio C2PA Attestation in the output mp4 video.
URL for HLS playback.
URL to manually download the asset if desired.
Reference to the playback-policy schema.
Source of the asset, which can be URL, recording, directUpload, or clip.
Reference to the creator-id schema.
Information about the storage of the asset, particularly on IPFS.
Status of the asset, including its phase, update time, and any error message.
Name of the asset. This is not necessarily the filename, can be a custom name
or title.
Timestamp (in milliseconds) at which asset was created.
Size of the asset in bytes.
Hash of the asset.
Video metadata including format, duration, bitrate, and tracks information.
```json Response theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"id": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"type": "video",
"playbackId": "eaw4nk06ts2d0mzb",
"staticMp4": "boolean",
"c2pa": "boolean",
"playbackUrl": "https://livepeercdn.com/asset/ea03f37e-f861-4cdd-b495-0e60b6d753ad/index.m3u8",
"downloadUrl": "https://livepeercdn.com/asset/eaw4nk06ts2d0mzb/video",
"playbackPolicy": {
"type": "public",
"webhookId": "3e02c844-d364-4d48-b401-24b2773b5d6c",
"webhookContext": {
"foo": "bar"
}
},
"source": {
"type": "url",
"url": "https://example.com/video.mp4",
"gatewayUrl": "https://example.com/video.mp4"
},
"creatorId": "object",
"storage": {
"ipfs": {
"spec": {
"nftMetadataTemplate": "file",
"nftMetadata": {
"name": "My NFT",
"description": "My NFT description"
}
}
}
},
"status": {
"phase": "ready",
"updatedAt": 1587667174725,
"progress": 100
},
"name": "filename.mp4",
"createdAt": 1587667174725,
"size": 84934509,
"hash": [
{
"hash": "9b560b28b85378a5004117539196ab24e21bbd75b0e9eb1a8bc7c5fd80dc5b57",
"algorithm": "sha256"
}
],
"videoSpec": {
"format": "mp4",
"duration": 23.8328,
"bitrate": 1000000,
"tracks": [
{
"type": "video",
"codec": "h264",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"width": 1920,
"height": 1080,
"pixelFormat": "yuv420p",
"fps": 30
},
{
"type": "audio",
"codec": "aac",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"channels": 2,
"sampleRate": 44100,
"bitDepth": 16
}
]
}
}
```
# Update an asset
Source: https://docs.livepeer.org/v1/api-reference/asset/update
PATCH /asset/{assetId}
# Upload an asset
Source: https://docs.livepeer.org/v1/api-reference/asset/upload
POST /asset/request-upload
To upload an asset, your first need to request for a direct upload URL
and only then actually upload the contents of the asset.
\
\
Once you created a upload link, you have 2 options, resumable or direct
upload. For a more reliable experience, you should use resumable uploads
which will work better for users with unreliable or slow network
connections. If you want a simpler implementation though, you should
just use a direct upload.
## Direct Upload
For a direct upload, make a PUT request to the URL received in the url
field of the response above, with the raw video file as the request
body. response above:
## Resumable Upload
Livepeer supports resumable uploads via Tus. This section provides a
simple example of how to use tus-js-client to upload a video file.
\
\
From the previous section, we generated a URL to upload a video file to
Livepeer on POST /api/asset/request-upload. You should use the
tusEndpoint field of the response to upload the video file and track the
progress:
```
# This assumes there is an `input` element of `type="file"` with id
`fileInput` in the HTML
const input = document.getElementById('fileInput');
const file = input.files[0];
const upload = new tus.Upload(file, {
endpoint: tusEndpoint, // URL from `tusEndpoint` field in the
`/request-upload` response
metadata: {
filename,
filetype: 'video/mp4',
},
uploadSize: file.size,
onError(err) {
console.error('Error uploading file:', err);
},
onProgress(bytesUploaded, bytesTotal) {
const percentage = ((bytesUploaded / bytesTotal) * 100).toFixed(2);
console.log('Uploaded ' + percentage + '%');
},
onSuccess() {
console.log('Upload finished:', upload.url);
},
});
const previousUploads = await upload.findPreviousUploads();
if (previousUploads.length > 0) {
upload.resumeFromPreviousUpload(previousUploads[0]);
}
upload.start();
```
> Note: If you are using tus from node.js, you need to add a custom URL
storage to enable resuming from previous uploads. On the browser, this
is enabled by default using local storage. In node.js, add urlStorage:
new tus.FileUrlStorage("path/to/tmp/file"), to the UploadFile object
definition above.
# Upload asset via URL
Source: https://docs.livepeer.org/v1/api-reference/asset/upload-via-url
POST /asset/upload/url
# Audio To Text
Source: https://docs.livepeer.org/v1/api-reference/generate/audio-to-text
POST /api/beta/generate/audio-to-text
# Image To Image
Source: https://docs.livepeer.org/v1/api-reference/generate/image-to-image
POST /api/beta/generate/image-to-image
# Image To Video
Source: https://docs.livepeer.org/v1/api-reference/generate/image-to-video
POST /api/beta/generate/image-to-video
# LLM
Source: https://docs.livepeer.org/v1/api-reference/generate/llm
## Overview
The `llm` pipeline provides an OpenAI-compatible interface for text generation,
designed to integrate seamlessly into media workflows.
## Models
The `llm` pipeline supports **any Hugging Face-compatible LLM model**. Since
models evolve quickly, the set of warm (preloaded) models on Orchestrators
changes regularly.
To see which models are currently available, check the
[Network Capabilities dashboard](https://tools.livepeer.cloud/ai/network-capabilities).\
At the time of writing, the most commonly available model is
[meta-llama/Meta-Llama-3.1-8B-Instruct](https://huggingface.co/meta-llama/Llama-3.1-8B-Instruct).
For faster responses with different
[LLM](https://huggingface.co/models?pipeline_tag=text-generation) diffusion
models, ask Orchestrators to load it on their GPU via the `ai-video` channel
in [Discord Server](https://discord.gg/livepeer).
## Basic Usage Instructions
For a detailed understanding of the `llm` endpoint and to experiment with the
API, see the [Livepeer AI API Reference](/ai/api-reference/llm).
To generate text with the `llm` pipeline, send a `POST` request to the Gateway's
`llm` API endpoint:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -X POST "https:///llm" \
-H "Authorization: Bearer " \
-H "Content-Type: application/json" \
-d '{
"model": "meta-llama/Meta-Llama-3.1-8B-Instruct",
"messages": [
{ "role": "user", "content": "Tell a robot story." }
]
}'
```
In this command:
* `` should be replaced with your AI Gateway's IP address.
* `` should be replaced with your API token.
* `model` is the LLM model to use for generation.
* `messages` is the conversation or prompt input for the model.
For additional optional parameters such as `temperature`, `max_tokens`, or
`stream`, refer to the [Livepeer AI API Reference](/ai/api-reference/llm).
After execution, the Orchestrator processes the request and returns the response
to the Gateway:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"id": "chatcmpl-abc123",
"model": "meta-llama/Meta-Llama-3.1-8B-Instruct",
"choices": [
{
"message": {
"role": "assistant",
"content": "Once upon a time, in a gleaming city of circuits..."
}
}
]
}
```
By default, responses are returned as a single JSON object. To stream output
token-by-token using **Server-Sent Events (SSE)**, set `"stream": true` in the
request body.
## Orchestrator Configuration
To configure your Orchestrator to serve the `llm` pipeline, refer to the
[Orchestrator Configuration](/ai/orchestrators/get-started) guide.
### Tuning Environment Variables
The `llm` pipeline supports several environment variables that can be adjusted
to optimize performance based on your hardware and workload. These are
particularly helpful for managing memory usage and parallelism when running
large models.
Enables 8-bit quantization using `bitsandbytes` for lower memory usage. Set to
`true` to enable. Defaults to `false`.
Number of pipeline parallel stages. Should not exceed the number of model
layers. Defaults to `1`.
Number of tensor parallel units. Must divide evenly into the number of
attention heads in the model. Defaults to `1`.
Maximum number of tokens per input sequence. Defaults to `8192`.
Maximum number of tokens processed in a single batch. Should be greater than
or equal to `MAX_MODEL_LEN`. Defaults to `8192`.
Maximum number of sequences processed per batch. Defaults to `128`.
Target GPU memory utilization as a float between `0` and `1`. Higher values
make fuller use of GPU memory. Defaults to `0.97`.
### System Requirements
The following system requirements are recommended for optimal performance:
* [NVIDIA GPU](https://developer.nvidia.com/cuda-gpus) with **at least 16GB** of
VRAM.
## Recommended Pipeline Pricing
We are planning to simplify the pricing in the future so orchestrators can set
one AI price per compute unit and have the system automatically scale based on
the model's compute requirements.
The `/llm` pipeline is currently priced based on the **maximum output tokens**
specified in the request — not actual usage — due to current payment system
limitations. We're actively working to support usage-based pricing to better
align with industry standards.
The LLM pricing landscape is highly competitive and rapidly evolving.
Orchestrators should set prices based on their infrastructure costs and
[market positioning](https://llmpricecheck.com/). As a reference, inference on
`llama-3-8b-instruct` is currently around `0.08 USD` per 1 million **output
tokens**.
## API Reference
Explore the `llm` endpoint and experiment with the API in the Livepeer AI API
Reference.
# Overview
Source: https://docs.livepeer.org/v1/api-reference/generate/overview
The Generate API is used to run generative AI models.
These APIs implement the [Livepeer AI Gateway API spec](/ai/api-reference) and
are served under the Studio platform suite. They are prefixed with
`/api/beta/generate` and are used to run AI models to generate content.
# Segment Anything 2
Source: https://docs.livepeer.org/v1/api-reference/generate/segment-anything-2
POST /api/beta/generate/segment-anything-2
# Text To Image
Source: https://docs.livepeer.org/v1/api-reference/generate/text-to-image
POST /api/beta/generate/text-to-image
# Upscale
Source: https://docs.livepeer.org/v1/api-reference/generate/upscale
POST /api/beta/generate/upscale
# Create a multistream
Source: https://docs.livepeer.org/v1/api-reference/multistream/create
POST /multistream/target
# Delete a multistream
Source: https://docs.livepeer.org/v1/api-reference/multistream/delete
DELETE /multistream/target/{id}
Make sure to remove any references to the target on existing
streams before actually deleting it from the API.
# Retrieve a multistream
Source: https://docs.livepeer.org/v1/api-reference/multistream/get
GET /multistream/target/{id}
# Retrieve all multistreams
Source: https://docs.livepeer.org/v1/api-reference/multistream/get-all
GET /multistream/target
# Overview
Source: https://docs.livepeer.org/v1/api-reference/multistream/overview
The Multistream target API is used to create, retrieve, update, delete multi-stream targets object from pipeline.
### Multistream target object
Unique identifier for the multistream target.
Name of the multistream target.
Livepeer-compatible multistream target URL (RTMP(S) or SRT). This URL is used
for streaming to the target platform.
Indicates if this multistream target is disabled. If true, it will not be used
for pushing even if configured in a stream object.
Timestamp (in milliseconds) at which the multistream target object was
created.
```json Response theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"id": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"name": "My Multistream Target",
"url": "rtmps://live.my-service.tv/channel/secretKey",
"disabled": "boolean",
"createdAt": 1587667174725
}
```
# Update a multistream
Source: https://docs.livepeer.org/v1/api-reference/multistream/update
PATCH /multistream/target/{id}
# Authentication
Source: https://docs.livepeer.org/v1/api-reference/overview/authentication
Learn more about Livepeer's API.
Livepeer API uses API keys to verify and authorize requests. You can manage and
review your API keys through Livepeer Studio. You need to pass your API key in
the `Authorization` header with a `Bearer` prefix while sending a request.
```
Bearer YOUR_API_KEY
```
It's important to note that your API keys come with significant privileges, so
it's essential to keep them safe and secure! Refrain from sharing your secret
API keys in GitHub or other publicly accessible places.
By default, API keys can only be used from a backend server. This is to ensure
maximum security and prevent that you accidentally expose your account by
including the secret API key in a public web page.
### CORS-Enabled Keys
Please read the below documentation in its entirety before using CORS-enabled
API keys. **There is a different security model for CORS keys.**
Studio supports the creation of CORS-enabled API keys. This is a special option
when generating an API key which allows a webpage to make requests **directly**
to Studio, as opposed to coming from your backend.
#### Security with CORS Keys
**The security model is different for CORS-enabled API keys.** Since any user
has access to these keys, the IDs of assets and streams **must** be kept secret
from anyone who should not have admin control over them. For instance, a viewer
should only have access to the playback ID, since knowing the asset ID (together
with the CORS-enabled API key, which is embedded in the webpage) allows them to
make changes to the asset.
This is the same for streams - if a user has access to a stream ID alongside the
CORS API key, they can modify the stream or view the stream key. If a viewer had
access to the stream ID + CORS API key, they could hijack the stream. **A
`playbackId` should be exposed to the viewer only.**
# Introduction
Source: https://docs.livepeer.org/v1/api-reference/overview/introduction
Learn more about Livepeer's API.
Welcome to the Livepeer API reference docs! Here you'll find all the endpoints
exposed on the standard Livepeer API, learn how to use them and what they
return.
The Livepeer API is organized around REST, has predictable resource-oriented
URLs, accepts JSON request bodies, returns JSON-encoded responses, and uses
standard HTTP response codes, authentication, and verbs.
# Overview
Source: https://docs.livepeer.org/v1/api-reference/playback/overview
The Playback API is used to retrieve playback object from pipeline.
### Playback Object
Type of playback, such as live, vod, or recording.
Metadata for the playback information. This includes details about the source,
playback policy, and attestation.
Indicates if the playback is live (1) or not (0).
Reference to the playback-policy schema.
Array of source objects detailing the playback sources. Each source includes
HRN, type, URL, size, width, height, and bitrate.
Human-readable name (HRN) for the playback source format.
MIME type of the playback source.
URL for the playback source.
Size of the playback source file.
Width of the video in pixels.
Height of the video in pixels.
Bitrate of the playback source.
Reference to the attestation schema.
```json Response theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"type": "vod",
"meta": {
"live": 0,
"playbackPolicy": {
"type": "public",
"webhookId": "3e02c844-d364-4d48-b401-24b2773b5d6c",
"webhookContext": {
"foo": "bar"
}
},
"source": [
{
"hrn": "MP4",
"type": "html5/video/mp4",
"url": "https://asset-cdn.lp-playback.studio/hls/1bde4o2i6xycudoy/static360p0.mp4",
"size": 494778,
"width": 204,
"height": 360,
"bitrate": 449890
}
],
"attestation": {
"id": "5b9e63bb-6fd0-4bea-aff2-cc5d4eb9cad0",
"primaryType": "VideoAttestation",
"domain": {
"name": "Verifiable Video",
"version": "1"
},
"message": {
"video": "string",
"attestations": [
{
"role": "string",
"address": "string"
}
],
"signer": "string",
"timestamp": "number"
},
"signature": "string",
"createdAt": 1587667174725,
"signatureType": "eip712",
"storage": {
"ipfs": {
"cid": "bafybeihoqtemwitqajy6d654tmghqqvxmzgblddj2egst6yilplr5num6u",
"url": "ipfs://bafybeihoqtemwitqajy6d654tmghqqvxmzgblddj2egst6yilplr5num6u",
"gatewayUrl": "https://ipfs.io",
"updatedAt": 1587667174725
},
"status": {
"phase": "ready",
"progress": 0.5,
"errorMessage": "Failed to export to IPFS",
"tasks": {
"pending": "string",
"last": "string",
"failed": "string"
}
}
}
}
}
}
```
# Retrieve a session
Source: https://docs.livepeer.org/v1/api-reference/session/get
GET /session/{id}
# Retrieve all sessions
Source: https://docs.livepeer.org/v1/api-reference/session/get-all
GET /session
# Retrieve clips of a session
Source: https://docs.livepeer.org/v1/api-reference/session/get-clip
GET /session/{id}/clips
# Retrieve recorded sessions
Source: https://docs.livepeer.org/v1/api-reference/session/get-recording
GET /stream/{parentId}/sessions
# Overview
Source: https://docs.livepeer.org/v1/api-reference/session/overview
The Sessions API is used to retrieve sessions object from pipeline.
### Session Object
Unique identifier for the session.
Name of the session.
Timestamp of the last activity in the session.
Number of source segments in the session.
Number of transcoded segments in the session.
Duration of all the source segments in seconds.
Duration of all the transcoded segments in seconds.
Total bytes of source segments.
Total bytes of transcoded segments.
Rate at which sourceBytes increases (bytes/second).
Rate at which transcodedBytes increases (bytes/second).
Reference to the stream-health-payload schema for health status.
Reference to the stream-health-payload schema for human-readable issues.
Timestamp (in milliseconds) at which the session was created.
Identifier of the parent stream object.
Indicates whether the stream should be recorded.
Status of the recording process of this stream session.
URL for accessing the recording of this stream session.
URL for the stream session recording packaged in an MP4 format.
Identifier used to form the playback URL.
Array of profiles detailing various streaming qualities.
```json Response theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"id": "de7818e7-610a-4057-8f6f-b785dc1e6f88",
"name": "test_session",
"lastSeen": 1587667174725,
"sourceSegments": 1,
"transcodedSegments": 2,
"sourceSegmentsDuration": 1,
"transcodedSegmentsDuration": 2,
"sourceBytes": 1,
"transcodedBytes": 2,
"ingestRate": 1,
"outgoingRate": 2,
"isHealthy": true,
"issues": [
"Buffer underflow",
"Network congestion"
],
"createdAt": 1587667174725,
"parentId": "de7818e7-610a-4057-8f6f-b785dc1e6f88",
"record": "boolean",
"recordingStatus": "waiting",
"recordingUrl": "https://lp-playback.com/hls/29eb9byolvwdbkue/index.m3u8",
"mp4Url": "https://lp-playback.com/hls/29eb9byolvwdqkue/720.mp4",
"playbackId": "eaw4nk06ts2d0mzb",
"profiles": [
{
"name": "720p",
"width": 1280,
"height": 720,
"bitrate": 3000,
"fps": 30
}
]
}
```
# Create a signing key
Source: https://docs.livepeer.org/v1/api-reference/signing-key/create
POST /access-control/signing-key
The publicKey is a representation of the public key, encoded as base 64 and is passed as a string, and the privateKey is displayed only on creation. This is the only moment where the client can save the private key, otherwise it will be lost. Remember to decode your string when signing JWTs.
Up to 10 signing keys can be generated, after that you must delete at least one signing key to create a new one.
# Delete a signing key
Source: https://docs.livepeer.org/v1/api-reference/signing-key/delete
DELETE /access-control/signing-key/{keyId}
# Retrieve a signing key
Source: https://docs.livepeer.org/v1/api-reference/signing-key/get
GET /access-control/signing-key/{keyId}
# Retrieve signing keys
Source: https://docs.livepeer.org/v1/api-reference/signing-key/get-all
GET /access-control/signing-key
# Overview
Source: https://docs.livepeer.org/v1/api-reference/signing-key/overview
The Access control API is used to create, retrieve, update, delete signing keys object from pipeline.
### Signing key Object
Unique identifier for the signing key.
Name of the signing key.
Timestamp (in milliseconds) at which the signing key was created.
Timestamp of the last activity with the signing key.
The public key portion of the signing key.
Indicates whether the signing key is disabled.
The private key portion of the signing key.
```json Response theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"id": "78df0075-b5f3-4683-a618-1086faca35dc",
"name": "My signing key",
"createdAt": 1587667174725,
"lastSeen": 1587667174725,
"publicKey": "LS0tLS1CRUdJTiBQUklWQVRFIBtFWS0tLS0tCk1JR0hBZ0VBTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEJHMHdhd0lCQVFRZ1RDRzhRWDZKdkR0eC95ZDMKdlpkUHJKR25LcjhiWHRsdXNIL2FOYW5XdHEraFJBTkNBQVE0QnZ6ODI2L2lDaXV1U0NiZVkwc3FmOXljYWh0OApDRFYyUFF2bDFVM1FLSVRBcWRpaktLa0FSUFVkcWRrYWZzR21PMzBDeElPaDBLNWJSQW5XQzd4KwotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tCg==",
"disabled": "boolean",
"privateKey": "LS0tLS1CRUdJTiBQUklWQVRFIBtFWS0tLS0tCk1JR0hBZ0VBTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEJHMHdhd0lCQVFRZ1RDRzhRWDZKdkR0eC95ZDMKdlpkUHJKR25LcjhiWHRsdXNIL2FOYW5XdHEraFJBTkNBQVE0QnZ6ODI2L2lDaXV1U0NiZVkwc3FmOXljYWh0OApDRFYyUFF2bDFVM1FLSVRBcWRpaktLa0FSUFVkcWRrYWZzR21PMzBDeElPaDBLNWJSQW5XQzd4KwotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tCg=="
}
```
# Update a signing key
Source: https://docs.livepeer.org/v1/api-reference/signing-key/update
PATCH /access-control/signing-key/{keyId}
# Add a multistream target
Source: https://docs.livepeer.org/v1/api-reference/stream/add-multistream-target
POST /stream/{id}/create-multistream-target
# Create a livestream
Source: https://docs.livepeer.org/v1/api-reference/stream/create
POST /stream
The only parameter you are required to set is the name of your stream,
but we also highly recommend that you define transcoding profiles
parameter that suits your specific broadcasting configuration.
\
\
If you do not define transcoding rendition profiles when creating the
stream, a default set of profiles will be used. These profiles include
240p, 360p, 480p and 720p.
\
\
The playback policy is set to public by default for new streams. It can
also be added upon the creation of a new stream by adding
`"playbackPolicy": {"type": "jwt"}`
# Create a clip
Source: https://docs.livepeer.org/v1/api-reference/stream/create-clip
POST /clip
# Delete a livestream
Source: https://docs.livepeer.org/v1/api-reference/stream/delete
DELETE /stream/{id}
This will also suspend any active stream sessions, so make sure to wait
until the stream has finished. To explicitly interrupt an active
session, consider instead updating the suspended field in the stream
using the PATCH stream API.
# Remove a multistream target
Source: https://docs.livepeer.org/v1/api-reference/stream/delete-multistream-target
DELETE /stream/{id}/multistream/{targetId}
# Retrieve a livestream
Source: https://docs.livepeer.org/v1/api-reference/stream/get
GET /stream/{id}
# Retrieve all livestreams
Source: https://docs.livepeer.org/v1/api-reference/stream/get-all
GET /stream
# Retrieve clips of a livestream
Source: https://docs.livepeer.org/v1/api-reference/stream/get-clip
GET /stream/{id}/clips
# Overview
Source: https://docs.livepeer.org/v1/api-reference/stream/overview
The Livestream API is used to create, retrieve, update, delete stream object from pipeline.
### Stream Object
Unique identifier for the stream.
Name of the stream.
Reference to the creator-id schema.
Timestamp of the last activity on the stream.
Number of source segments.
Number of transcoded segments.
Duration of all the source segments in seconds.
Duration of all the transcoded segments in seconds.
Total bytes of source segments.
Total bytes of transcoded segments.
Rate at which sourceBytes increases (bytes/second).
Rate at which transcodedBytes increases (bytes/second).
Indicates if the stream is currently active.
Reference to the stream-health-payload schema for health status.
Reference to the stream-health-payload schema for human-readable issues.
Name of the token used to create this stream.
Timestamp (in milliseconds) of when the stream object was created.
Identifier for the parent stream object.
Key used to form the RTMP ingest URL.
Identifier used to form the playback URL.
Reference to the playback-policy schema.
Array of profiles detailing various streaming qualities.
Indicates if the stream should be recorded.
Details about multistreaming targets and their configurations.
Indicates if the stream is currently suspended.
```json Response theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"id": "de7818e7-610a-4057-8f6f-b785dc1e6f88",
"name": "test_stream",
"creatorId": "object",
"lastSeen": 1587667174725,
"sourceSegments": 1,
"transcodedSegments": 2,
"sourceSegmentsDuration": 1,
"transcodedSegmentsDuration": 2,
"sourceBytes": 1,
"transcodedBytes": 2,
"ingestRate": 1,
"outgoingRate": 2,
"isActive": "boolean",
"isHealthy": true,
"issues": ["Buffer underflow", "Network congestion"],
"createdByTokenName": "staging key",
"createdAt": 1587667174725,
"parentId": "de7818e7-610a-4057-8f6f-b785dc1e6f88",
"streamKey": "hgebdhhigq",
"playbackId": "eaw4nk06ts2d0mzb",
"playbackPolicy": {
"type": "public",
"webhookId": "3e02c844-d364-4d48-b401-24b2773b5d6c",
"webhookContext": {
"foo": "bar"
}
},
"profiles": [
{
"name": "720p",
"width": 1280,
"height": 720,
"bitrate": 3000,
"fps": 30
}
],
"record": "boolean",
"multistream": {
"targets": [
{
"id": "PUSH123",
"profile": "720p"
}
]
},
"suspended": "boolean"
}
```
# Terminates a livestream
Source: https://docs.livepeer.org/v1/api-reference/stream/terminate
DELETE /stream/{id}/terminate
`DELETE /stream/{id}/terminate` can be used to terminate an ongoing
session on a live stream. Unlike suspending the stream, it allows the
streamer to restart streaming even immediately, but it will force
terminate the current session and stop the recording.
\
\
A 204 No Content status response indicates the stream was successfully
terminated.
# Update a livestream
Source: https://docs.livepeer.org/v1/api-reference/stream/update
PATCH /stream/{id}
# Retrieve a task
Source: https://docs.livepeer.org/v1/api-reference/task/get
GET /task/{taskId}
# Retrieve tasks
Source: https://docs.livepeer.org/v1/api-reference/task/get-all
GET /task
# Overview
Source: https://docs.livepeer.org/v1/api-reference/task/overview
The Tasks API is used to retrieve tasks object from pipeline.
### Task Object
Task ID.
Type of the task, such as upload, import, export, etc.
Timestamp (in milliseconds) at which the task was created.
Timestamp (in milliseconds) at which the task was scheduled for execution.
ID of the input asset for the task.
ID of the output asset for the task.
Parameters of the task, which vary depending on the task type.
Status of the task, including phase, update time, and error message.
Output of the task, specifics depend on the task type.
```json Response theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"id": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"type": "upload",
"createdAt": 1587667174725,
"scheduledAt": 1587667174725,
"inputAssetId": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"outputAssetId": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"params": {
"upload": {
"url": "https://cdn.livepeer.com/ABC123/filename.mp4",
"encryption": {
"encryptedKey": "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JR0hBZ0VBTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEJHMHdhd0lCQVFRZ1RDRzhRWDZKdkR0eC95ZDMKdlpkUHJKR25LcjhiWHRsdXNIL2FOYW5XdHEraFJBTkNBQVE0QnZ6ODI2L2lDaXV1U0NiZVkwc3FmOXljYWh0OApDRFYyUFF2bDFVM1FLSVRBcWRpaktLa0FSUFVkcWRrYWZzR21PMzBDeElPaDBLNWJSQW5XQzd4KwotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tCg=="
},
"recordedSessionId": "78df0075-b5f3-4683-a618-1086faca35dc"
},
"import": {
"url": "https://cdn.livepeer.com/ABC123/filename.mp4",
"encryption": {
"encryptedKey": "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JR0hBZ0VBTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEJHMHdhd0lCQVFRZ1RDRzhRWDZKdkR0eC95ZDMKdlpkUHJKR25LcjhiWHRsdXNIL2FOYW5XdHEraFJBTkNBQVE0QnZ6ODI2L2lDaXV1U0NiZVkwc3FmOXljYWh0OApDRFYyUFF2bDFVM1FLSVRBcWRpaktLa0FSUFVkcWRrYWZzR21PMzBDeElPaDBLNWJSQW5XQzd4KwotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tCg=="
},
"recordedSessionId": "78df0075-b5f3-4683-a618-1086faca35dc"
},
"exportData": {
"content": "object",
"ipfs": {
"nftMetadataTemplate": "file",
"nftMetadata": "object",
"pinata": {
"jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MDI4NjQwNzcsImlhdCI6MTYwMjI3NjA3NywiaXNzIjoiYXBpLmlzc3VlciIsInN1YiI6I"
}
},
"type": "string",
"id": "string"
},
"transcode": {
"profile": {
"width": 1280,
"name": "720p",
"height": 720,
"bitrate": 4000,
"fps": 30,
"fpsDen": 1,
"gop": "60",
"profile": "H264High",
"encoder": "h264"
}
},
"transcode-file": {
"input": {
"url": "https://cdn.livepeer.com/ABC123/filename.mp4"
},
"storage": {
"url": "s3+https://accessKeyId:secretAccessKey@s3Endpoint/bucket"
},
"outputs": {
"hls": {
"path": "/samplevideo/hls"
},
"mp4": {
"path": "/samplevideo/mp4"
}
},
"profiles": [
{
"width": 1280,
"name": "720p",
"height": 720,
"bitrate": 4000,
"fps": 30,
"fpsDen": 1,
"gop": "60",
"profile": "H264High",
"encoder": "h264"
}
],
"targetSegmentSizeSecs": "number",
"c2pa": "boolean"
}
},
"clip": {
"url": "string",
"clipStrategy": {
"startTime": "number",
"endTime": "number",
"playbackId": "string"
},
"catalystPipelineStrategy": "catalyst",
"sessionId": "string",
"inputId": "string"
},
"status": {
"phase": "pending",
"updatedAt": 1587667174725,
"progress": "number",
"errorMessage": "string",
"retries": "number",
"step": "string"
},
"output": {
"upload": {
"videoFilePath": "string",
"metadataFilePath": "string",
"assetSpec": {
"id": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"type": "video",
"playbackId": "eaw4nk06ts2d0mzb",
"staticMp4": "boolean",
"c2pa": "boolean",
"playbackUrl": "https://livepeercdn.com/asset/ea03f37e-f861-4cdd-b495-0e60b6d753ad/index.m3u8",
"downloadUrl": "https://livepeercdn.com/asset/eaw4nk06ts2d0mzb/video",
"playbackPolicy": {
"type": "public",
"webhookId": "3e02c844-d364-4d48-b401-24b2773b5d6c",
"webhookContext": {
"foo": "bar"
}
},
"source": {
"type": "url",
"url": "https://example.com/video.mp4",
"gatewayUrl": "https://example.com/video.mp4"
},
"creatorId": "object",
"storage": {
"ipfs": {
"spec": {
"nftMetadataTemplate": "file",
"nftMetadata": {
"name": "My NFT",
"description": "My NFT description"
}
}
}
},
"status": {
"phase": "ready",
"updatedAt": 1587667174725,
"progress": 100
},
"name": "filename.mp4",
"createdAt": 1587667174725,
"size": 84934509,
"hash": [
{
"hash": "9b560b28b85378a5004117539196ab24e21bbd75b0e9eb1a8bc7c5fd80dc5b57",
"algorithm": "sha256"
}
],
"videoSpec": {
"format": "mp4",
"duration": 23.8328,
"bitrate": 1000000,
"tracks": [
{
"type": "video",
"codec": "h264",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"width": 1920,
"height": 1080,
"pixelFormat": "yuv420p",
"fps": 30
},
{
"type": "audio",
"codec": "aac",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"channels": 2,
"sampleRate": 44100,
"bitDepth": 16
}
]
}
}
},
"import": {
"videoFilePath": "string",
"metadataFilePath": "string",
"assetSpec": {
"id": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"type": "video",
"playbackId": "eaw4nk06ts2d0mzb",
"staticMp4": "boolean",
"c2pa": "boolean",
"playbackUrl": "https://livepeercdn.com/asset/ea03f37e-f861-4cdd-b495-0e60b6d753ad/index.m3u8",
"downloadUrl": "https://livepeercdn.com/asset/eaw4nk06ts2d0mzb/video",
"playbackPolicy": {
"type": "public",
"webhookId": "3e02c844-d364-4d48-b401-24b2773b5d6c",
"webhookContext": {
"foo": "bar"
}
},
"source": {
"type": "url",
"url": "https://example.com/video.mp4",
"gatewayUrl": "https://example.com/video.mp4"
},
"creatorId": "object",
"storage": {
"ipfs": {
"spec": {
"nftMetadataTemplate": "file",
"nftMetadata": {
"name": "My NFT",
"description": "My NFT description"
}
}
}
},
"status": {
"phase": "ready",
"updatedAt": 1587667174725,
"progress": 100
},
"name": "filename.mp4",
"createdAt": 1587667174725,
"size": 84934509,
"hash": [
{
"hash": "9b560b28b85378a5004117539196ab24e21bbd75b0e9eb1a8bc7c5fd80dc5b57",
"algorithm": "sha256"
}
],
"videoSpec": {
"format": "mp4",
"duration": 23.8328,
"bitrate": 1000000,
"tracks": [
{
"type": "video",
"codec": "h264",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"width": 1920,
"height": 1080,
"pixelFormat": "yuv420p",
"fps": 30
},
{
"type": "audio",
"codec": "aac",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"channels": 2,
"sampleRate": 44100,
"bitDepth": 16
}
]
}
}
},
"export": {
"ipfs": {
"videoFileCid": "string",
"videoFileUrl": "string",
"videoFileGatewayUrl": "string",
"nftMetadataCid": "string",
"nftMetadataUrl": "string",
"nftMetadataGatewayUrl": "string"
}
},
"exportData": {
"ipfs": {
"cid": "string"
}
},
"transcode": {
"asset": {
"videoFilePath": "string",
"metadataFilePath": "string",
"assetSpec": {
"id": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"type": "video",
"playbackId": "eaw4nk06ts2d0mzb",
"staticMp4": "boolean",
"c2pa": "boolean",
"playbackUrl": "https://livepeercdn.com/asset/ea03f37e-f861-4cdd-b495-0e60b6d753ad/index.m3u8",
"downloadUrl": "https://livepeercdn.com/asset/eaw4nk06ts2d0mzb/video",
"playbackPolicy": {
"type": "public",
"webhookId": "3e02c844-d364-4d48-b401-24b2773b5d6c",
"webhookContext": {
"foo": "bar"
}
},
"source": {
"type": "url",
"url": "https://example.com/video.mp4",
"gatewayUrl": "https://example.com/video.mp4"
},
"creatorId": "object",
"storage": {
"ipfs": {
"spec": {
"nftMetadataTemplate": "file",
"nftMetadata": {
"name": "My NFT",
"description": "My NFT description"
}
}
}
},
"status": {
"phase": "ready",
"updatedAt": 1587667174725,
"progress": 100
},
"name": "filename.mp4",
"createdAt": 1587667174725,
"size": 84934509,
"hash": [
{
"hash": "9b560b28b85378a5004117539196ab24e21bbd75b0e9eb1a8bc7c5fd80dc5b57",
"algorithm": "sha256"
}
],
"videoSpec": {
"format": "mp4",
"duration": 23.8328,
"bitrate": 1000000,
"tracks": [
{
"type": "video",
"codec": "h264",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"width": 1920,
"height": 1080,
"pixelFormat": "yuv420p",
"fps": 30
},
{
"type": "audio",
"codec": "aac",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"channels": 2,
"sampleRate": 44100,
"bitDepth": 16
}
]
}
}
}
}
}
}
```
# Create a webhook
Source: https://docs.livepeer.org/v1/api-reference/webhook/create
POST /webhook
To create a new webhook, you need to make an API call with the events you want to listen for and the URL that will be called when those events occur.
# Delete a webhook
Source: https://docs.livepeer.org/v1/api-reference/webhook/delete
DELETE /webhook/{id}
# Retrieve a webhook
Source: https://docs.livepeer.org/v1/api-reference/webhook/get
GET /webhook/{id}
# Retrieve all webhooks
Source: https://docs.livepeer.org/v1/api-reference/webhook/get-all
GET /webhook
# Overview
Source: https://docs.livepeer.org/v1/api-reference/webhook/overview
The Webhooks API is used to create, retrieve, update, delete webhooks object from pipeline.
### Webhook Object
Unique identifier for the webhook.
Name of the webhook.
Timestamp (in milliseconds) at which the webhook object was created.
List of events that the webhook subscribes to. Possible events include
stream.started, stream.detection, recording.ready, etc.
URL of the webhook endpoint.
Shared secret used to sign the webhook payload.
StreamId of the stream to which the webhook is applied.
Status of the webhook, including last failure and last triggered timestamp.
Details about the last failure of the webhook, including timestamp, error
message, response, and status code.
Timestamp (in milliseconds) at which the webhook was last triggered.
```json Response theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"id": "de7818e7-610a-4057-8f6f-b785dc1e6f88",
"name": "My webhook",
"createdAt": 1587667174725,
"events": [
"stream.started",
"recording.ready"
],
"url": "https://webhook.example.com",
"sharedSecret": "mySharedSecret",
"streamId": "de7818e7-610a-4057-8f6f-b785dc1e6f88",
"status": {
"lastFailure": {
"timestamp": 1587667174725,
"error": "Error message",
"response": "Response body",
"statusCode": 500
},
"lastTriggeredAt": 1587667174725
}
}
```
# Update a webhook
Source: https://docs.livepeer.org/v1/api-reference/webhook/update
PUT /webhook/{id}
# Control access using JWTs
Source: https://docs.livepeer.org/v1/developers/guides/access-control-jwt
Learn how to add access control to a content with Livepeer UI Kit, using JWTs
Using JSON Web Tokens (JWTs) provides a robust way to control access to both
your assets and livestreams. The JWTs can be signed and validated to ensure that
only authorized users can access the content. Below are examples for both assets
and livestreams.
Adding access control to a content only takes a few lines of code.
This guide is written for developers using `@livepeer/react` in a React
application.
## Create Gated Content
### For livestreams
Create your gated stream, with the stream key returned once we create it
(styling has been removed for simplicity)
```tsx accessControl.tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Livepeer } from "livepeer";
import { TypeT } from "livepeer/dist/models/components";
const livepeer = new Livepeer({
apiKey: process.env.STUDIO_API_KEY ?? "",
});
await livepeer.stream.create({
name: "...",
playbackPolicy: {
type: TypeT.Jwt,
},
});
```
### For assets
Create your gated asset, with the jwt playback policy type.
```tsx accessControl.ts theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Livepeer } from "livepeer";
import { TypeT } from "livepeer/dist/models/components";
const livepeer = new Livepeer({
apiKey: process.env.STUDIO_API_KEY ?? "",
});
await livepeer.asset.create({
name: "...",
playbackPolicy: {
type: TypeT.Jwt,
},
});
```
## Sign a JWT (Node.JS API Route)
Next, we add an API route - since we are using Next.JS, we add a custom
[Next.js API route](https://nextjs.org/docs/api-routes/introduction). We add a
check in the API route for a special "secret" that must be passed in the POST
body for the user to gain access to the stream.
Make sure to [create a signing key](/api-reference/signing-key/create) - those
values will be used as the environment variables `ACCESS_CONTROL_PRIVATE_KEY`
and `NEXT_PUBLIC_ACCESS_CONTROL_PUBLIC_KEY`.
```typescript /api/sign-jwt.ts theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { signAccessJwt } from "@livepeer/core/crypto";
import { NextApiRequest, NextApiResponse } from "next";
import { ApiError } from "../../lib/error";
export type CreateSignedPlaybackBody = {
playbackId: string;
secret: string;
};
export type CreateSignedPlaybackResponse = {
token: string;
};
const accessControlPrivateKey = process.env.ACCESS_CONTROL_PRIVATE_KEY;
const accessControlPublicKey =
process.env.NEXT_PUBLIC_ACCESS_CONTROL_PUBLIC_KEY;
const handler = async (
req: NextApiRequest,
res: NextApiResponse
) => {
try {
const method = req.method;
if (method === "POST") {
if (!accessControlPrivateKey || !accessControlPublicKey) {
return res
.status(500)
.json({ message: "No private/public key configured." });
}
const { playbackId, secret }: CreateSignedPlaybackBody = req.body;
if (!playbackId || !secret) {
return res.status(400).json({ message: "Missing data in body." });
}
// we check that the "supersecretkey" was passed in the body
// this could be a more complex check, like taking a signed payload,
// getting the address for that signature, and fetching if they own an NFT
//
// https://docs.ethers.io/v5/single-page/#/v5/api/utils/signing-key/-%23-SigningKey--other-functions
if (secret !== "supersecretkey") {
return res.status(401).json({ message: "Incorrect secret." });
}
// we sign the JWT and return it to the user
const token = await signAccessJwt({
privateKey: accessControlPrivateKey,
publicKey: accessControlPublicKey,
issuer: "https://docs.livepeer.org",
// playback ID to include in the JWT
playbackId,
// expire the JWT in 1 hour
expiration: "1h",
// custom metadata to include
custom: {
userId: "user-id-1",
},
});
return res.status(200).json({
token,
});
}
res.setHeader("Allow", ["POST"]);
return res.status(405).end(`Method ${method} Not Allowed`);
} catch (err) {
console.error(err);
return res
.status(500)
.json({ message: (err as Error)?.message ?? "Error" });
}
};
export default handler;
```
### Configure the Player
Lastly, when the content is created, we make a POST request to the
`/api/create-signed-jwt` API route we created in the previous step.
The React Player passes the JWT with a header, `Livepeer-Jwt`, to the backend,
for WebRTC and HLS playback. For MP4 playback, it uses a query parameter,
`jwt`.
Then, we pass the JWT to the Player using the
[`jwt`](/sdks/react/player/Root#jwt) prop, which will use that JWT to prove
access to the content!
```tsx access-control.tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
export const AccessControl = () => {
return (
);
};
```
### Using a custom player
If you are not using the player, you will need to pass a header, `Livepeer-Jwt`,
when you perform WebRTC SDP negotiation, or when you play back from a m3u8 URL.
For WebRTC SDP negotiation, here is an example of the header being passed:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -X POST \
-H "Content-Type: application/sdp" \
-H "Livepeer-Jwt: your-jwt" \
--data-binary "@sdpfile.sdp" \
"https://livepeercdn.studio/webrtc/abcd1234"
```
You can also append the JWT to the WebRTC URL as a query parameter, similar to:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -X POST \
-H "Content-Type: application/sdp" \
--data-binary "@sdpfile.sdp" \
"https://livepeercdn.studio/webrtc/abcd1234?jwt=your-jwt"
```
Similarly, for HLS playback, you can pass the JWT in a header:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -X GET \
-H "Livepeer-Jwt: your-jwt" \
"https://playback.livepeer.studio/asset/hls/abcd1234/index.m3u8"
```
If you are using HLS.js for your own custom player, you can set the JWT header like this:
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const hlsConfig = {
xhrSetup: function (xhr, url) {
xhr.setRequestHeader("Livepeer-Jwt", "your-jwt");
},
};
```
Finally, you can append the JWT to the m3u8 URL as a query parameter:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -X GET \
"https://playback.livepeer.studio/asset/hls/abcd1234/index.m3u8?jwt=your-jwt"
```
# Control access using webhooks
Source: https://docs.livepeer.org/v1/developers/guides/access-control-webhooks
Learn how to add access control to a content with React, using webhooks
Webhooks offer a versatile and dynamic approach to access control for both
assets and livestreams. By setting up a webhook, you can validate access
requests on the fly, allowing for real-time, context-sensitive decisions.
When a user requests access to content, the webhook you've specified will be
called. This webhook can then decide whether to grant or deny access based on
custom logic, such as user authentication, subscription status, or any other
criteria.
This guide is written for developers using `@livepeer/react` in a React
application.
The example below uses webhook to create and watch a gated content.
## Create an Access Control Webhook Handler
Set up an endpoint (e.g., [https://yourdomain.com/api/check-access](https://yourdomain.com/api/check-access)) to handle the
logic for granting or denying access to your assets. This endpoint should accept
a POST request with a JSON payload containing the access key and webhook
context.
This is an example of a payload this endpoint would receive:
```json POST /api/check-access theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"accessKey": "your-access-key",
"context": {
"assetId": "abcd1234",
"userId": "user5678"
},
"timestamp": 1680530722502
}
```
The payload in `context` is defined by your application.
### Register the Access Control Webhook
Use the
[Livepeer Studio dashboard](https://livepeer.studio/dashboard/developers/webhooks)
to create a new webhook with the type `playback.accessControl` and specify the
URL of your access control endpoint.
You can then use the ID of the webhook in the next step.
## Create content with a playback policy webhook
### For assets
Create an asset with a playback policy webhook, passing the ID of the webhook
you created in the previous step.
```tsx accessControl.ts theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Livepeer } from "livepeer";
import { TypeT } from "livepeer/dist/models/components";
const livepeer = new Livepeer({
apiKey: process.env.STUDIO_API_KEY ?? "",
});
await livepeer.asset.create({
name: "...",
playbackPolicy: {
type: TypeT.Webhook,
// This is the id of the webhook you created in step 2
webhookId: "",
webhookContext: {
// This is the context you want to pass to your webhook
// It can be anything you want, and it will be passed back to your webhook
},
},
});
```
You can then use the [returned TUS URL](/api-reference/asset/upload) to upload
the asset.
### For livestreams
Create a stream with a playback policy webhook, passing the ID of the webhook
you created in the previous step.
```tsx accessControl.ts theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Livepeer } from "livepeer";
import { TypeT } from "livepeer/dist/models/components";
const livepeer = new Livepeer({
apiKey: process.env.STUDIO_API_KEY ?? "",
});
await livepeer.stream.create({
name: "...",
playbackPolicy: {
type: TypeT.Webhook,
// This is the id of the webhook you created in step 2
webhookId: "",
webhookContext: {
// This is the context you want to pass to your webhook
// It can be anything you want, and it will be passed back to your webhook
},
},
});
```
### Configure the Player
If you are using the Livepeer UI Kit Player, you can use the
[`accessKey`](/sdks/react/player/Root#accesskey) prop to provide your custom
access key, which is then passed to the webhook you created to verify that it is
valid.
The React Player passes the access key with a header, `Livepeer-Access-Key`,
to the backend, for WebRTC and HLS playback. For MP4 playback, it uses a query
parameter, `accessKey`.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
export const CreateAndViewAsset = () => {
const accessKey = getAccessKeyForYourApplication();
return (
);
};
```
### Using a custom player
If you are not using the player, you will need to pass a header,
`Livepeer-Access-Key`, when you perform WebRTC SDP negotiation, or when you play
back from a m3u8 URL.
For WebRTC SDP negotiation, here is an example of the header being passed:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -X POST \
-H "Content-Type: application/sdp" \
-H "Livepeer-Access-Key: your-access-key" \
--data-binary "@sdpfile.sdp" \
"https://livepeercdn.studio/webrtc/abcd1234"
```
You can also append the access key to the WebRTC URL as a query parameter,
similar to:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -X POST \
-H "Content-Type: application/sdp" \
--data-binary "@sdpfile.sdp" \
"https://livepeercdn.studio/webrtc/abcd1234?accessKey=your-access-key"
```
Similarly, for HLS playback, you can pass the access key in a header:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -X GET \
-H "Livepeer-Access-Key: your-access-key" \
"https://playback.livepeer.studio/asset/hls/abcd1234/index.m3u8"
```
If you are using HLS.js for your own custom player, you can set the access key header like this:
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const hlsConfig = {
xhrSetup: function (xhr, url) {
xhr.setRequestHeader("Livepeer-Access-Key", "your-access-key");
},
};
```
Finally, you can append the access key to the m3u8 URL as a query parameter:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -X GET \
"https://playback.livepeer.studio/asset/hls/abcd1234/index.m3u8?accessKey=your-access-key"
```
### Receive the Webhook from Livepeer
When a user attempts to access the content, Livepeer will call your access
control endpoint with the access key and webhook context. Your endpoint should
process the request and return a response indicating whether the stream access
should be allowed or disallowed.
Here is an example request sent to your access control endpoint:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"context": {
// Same value from the `asset.playbackPolicy.webhookContext` field
},
"accessKey": "" // this is exact value of the prop passed to the Player, or the query parameter
}
```
In your access control endpoint, implement the logic to verify the access key
and decide whether to grant access to the content. If the access is allowed,
return a `2XX` response. Otherwise, the playback will be disallowed.
# Clip a livestream
Source: https://docs.livepeer.org/v1/developers/guides/clip-a-livestream
Learn how to create clips from your livestream
## Introduction
You can use Livepeer Studio to create clips of active streams provided via API.
Currently, you can create clips from the most recent N seconds of a given
stream. You may also clip specific sections of a long-running stream, such as a
particular session from a live-streamed conference.
This guide offers a comprehensive walkthrough of the clipping functionality.
Clipping is currently *only* supported by livestreams and livestream
recordings. Check back later for further support.
## Create a stream
Follow our previous guide on
[creating a stream](/developers/guides/create-livestream) to get a stream key to
provide to the creator on your platform. They can then start broadcasting to
that stream.
## Create a clip
Clips are created from the perspective of the user who initiates the clip. For
example, if a viewer clips the most recent 30 seconds, it will be the most
recent 30 seconds that they saw.
Submit a request to the [Create Clip API](/api-reference/stream/create-clip)
using the following request parameters:
UNIX timestamp (in milliseconds) of clip's starts from the browser’s playhead
(commonly supplied by HLS players).
UNIX timestamp (in milliseconds) of clip's end from the browser’s playhead
(commonly supplied by HLS players).
Active stream's Playback ID
(Optional) Output clip's name
Ensure the `startTime` aligns with or postdates the stream's initiation, and
that the `endTime` isn't set in the future.
### API + Player Integration
If you are using HLS.js, it provides an API for getting the program date time,
`hls.playingDate`, which can be used to get the browser’s current playhead. This
returns a Date object which is used similar to:
HLS players typically provide a `Program-Date-Time` for each segment when
parsing an HLS manifest. You can utilize `Program-Date-Time` to create a
clipping user interface (UI) and generate the correct timestamps.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import Hls from "hls.js";
const hls = new Hls();
// Assuming you have already connected HLS.js to a video element
const endTime = hls.playingDate.getTime(); // This retrieves the current playing date from HLS.js
const startTime = endTime - 30000; // 30 seconds before the endTime in milliseconds
const playbackId = process.env.PLAYBACK_ID_OF_RUNNING_STREAM;
const result = await livepeer.stream.createClip({
startTime,
endTime,
playbackId,
name: "Your clip name",
});
```
If you are using the Livepeer Player, you use the
[Clip Trigger](/sdks/react/player/Clip), which abstracts this functionality into
an easy-to-use primitive. **You will need to call the Livepeer Clip API from
your backend, and perform sanitization on the user input.**
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
// use the start/end time to call the Livepeer API, from your backend
// e.g. this should be a fetch to your /api/clip endpoint, which then
// makes a request to Livepeer's Clip endpoint, after validating the
// input parameters (e.g. clip is less than 60 seconds, etc)
}}
>
```
## Monitor the clip's status
After calling the clip API, Livepeer generates an asset. You'll receive the
asset's details in the response.
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"task": {
"id": "635cbcbb-30cb-4136-a7f0-ec5ea2ac39d0"
},
"asset": {
"id": "e28c63c6-ffe8-4f0f-8ae0-4fbbe5c7b493",
"playbackId": "e28crdyrtxjkx836",
"userId": "8f175616-1a6d-4481-86f5-7351c041b5ca",
"createdAt": 1695835443441,
"status": {
"phase": "waiting",
"updatedAt": 1695835443441
},
"name": "My Clip",
"source": {
"type": "clip",
"sessionId": "e0d88141-8ade-4274-9039-360245283645"
},
"objectStoreId": "9b526cee-bd25-44d2-9fda-f98db3a38a48"
}
}
```
There are two approaches to track the clip's status:
* **using the `/api/asset/$ASSET_ID` API**
You can poll this endpoint to retrieve the current status of the asset. Keep
polling until the `asset.status` field is `ready`.
* **using webhooks**
If you have configured a webhook in Livepeer to listen for the `asset.ready`
event, you will receive a notification when the clip processing is complete. You
can use the `assetId` received in the previous response to determine when your
clip is ready.
To determine if an asset you are polling or receiving as an event is a clip, you
can check the `source` field. If the `source` field contains a `clip` type and
the relative session ID, then it is indeed a clip.
You can always fetch clips by stream using the
[Clips for Livestream API](/api-reference/stream/get-clip):
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const playbackId = process.env.PLAYBACK_ID_OF_RUNNING_STREAM;
const livepeer = new Livepeer({
apiKey: "your_api_key_here",
});
const id = "08eeeda4-681f-46e5-a760-63d6cac91d91";
await livepeer.stream.getAllClips(id);
// Alternatively, you can use the streamId or fetch the clips
// by session using the /api/session/$sessionId/clips endpoint.
```
Clips offer source playback just like other assets. On completion, a transcode
job is triggered. Even before this job concludes, the source playback becomes
available. The `playbackUrl` field in the asset gets populated when the
playback is ready, and the `sourcePlayback` field is set to true.
## Get your clip!
A clip generated in Livepeer is the same as any other Livepeer asset. You are
able to get the playback URLs in your asset object, or fetching them from the
[Playback Info API](/api-reference/playback/get), providing the playbackId of
the output asset representing the clip.
# Create a livestream
Source: https://docs.livepeer.org/v1/developers/guides/create-livestream
Learn how to create a livestream
Creating and watching a livestream is easy! The example below uses
[Create Stream API](/api-reference/stream/create) to create and watch a
livestream.
### Stream Creation
We can use the Livepeer SDK to create a stream. The example below uses the
[Create Stream API](/api-reference/stream/create).
```javascript theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Livepeer } from "livepeer";
const apiKey = 'YOUR_API_KEY';
const livepeer = new Livepeer({apiKey});
const streamData = {
name: "test_stream"
};
livepeer
.stream.create(streamData)
.then((response) => {
console.log("Stream created:", response);
})
.catch((error) => {
console.error("Error creating stream:", error);
});
```
```python theme={"theme":{"light":"github-light","dark":"dark-plus"}}
from livepeer import Livepeer
# Initialize the Livepeer client with your API key
api_key = "YOUR_API_KEY"
livepeer = Livepeer(api_key)
stream_data = {
"name": "test_stream"
}
try:
# Create the stream
response = livepeer.stream.create(stream_data)
print("Stream created:", response)
except Exception as e:
print("Error creating stream:", e)
```
```go theme={"theme":{"light":"github-light","dark":"dark-plus"}}
package main
import (
"fmt"
"os"
"github.com/livepeer/livepeer-go"
)
func main() {
// Initialize the Livepeer client with your API key
apiKey := "YOUR_API_KEY"
client := livepeer.NewLivepeerClient(apiKey)
streamData := map[string]interface{}{
"name": "test_stream",
}
// Create the stream
response, err := client.Stream.Create(streamData)
if err != nil {
fmt.Printf("Error creating stream: %v\n", err)
os.Exit(1)
}
fmt.Printf("Stream created: %+v\n", response)
}
```
You can find all the information required to broadcast to the stream in the
[response object](/api-reference/stream/overview).
The RTMP ingest URL of Livepeer Studio is `rtmp://rtmp.livepeer.com/live`, and
the `streamKey` is present in the response object. You can use these two values
to broadcast to the stream.
You can also use WebRTC WHIP to broadcast, using the URL
`https://playback.livepeer.studio/webrtc/{streamKey}`. This is used for
[in-browser broadcasting](/developers/guides/livestream-from-browser).
To learn more about other stream functions such as stopping a stream,
recording a stream, and more, see the [Stream
API](/api-reference/stream/overview).
### Play a Stream
To learn how to play a stream, see the
[Play a Livestream](/developers/guides/playback-a-livestream) guide.
# Upload encrypted assets
Source: https://docs.livepeer.org/v1/developers/guides/encrypted-asset
Learn how to upload and play back an encrypted video asset
Livepeer enables you to upload encrypted video content or import it from
decentralized storages. It creates a playback URL that can have independent
access control through Livepeer's
[access control](/developers/guides/overview#access-control) feature.
This guide is written for developers using JavaScript, but the concepts can be
applied to any language.
### Generate an encryption key
First, we generate a 256-bit encryption key to encrypt the file.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// Generate a random 256-bit key
const key = await window.crypto.subtle.generateKey(
{
name: "AES-CBC",
length: 256,
},
true,
["encrypt", "decrypt"]
);
// Export the key as raw data
const keyData = await window.crypto.subtle.exportKey("raw", key);
// Encode the key in Base64
const keyBase64 = btoa(String.fromCharCode(...new Uint8Array(keyData)));
```
### Encrypt your video
To encrypt a video file with the key we just generated, we follow these steps:
1. Generate a random 128-bit initialization vector (IV).
2. Pad the data using PKCS#7 padding.
3. Encrypt the data using AES-CBC.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const iv = window.crypto.getRandomValues(new Uint8Array(16));
const encrypted = await window.crypto.subtle.encrypt(
{
name: "AES-CBC",
iv: iv,
},
key, // from generateKey or importKey above
arrayBuffer // ArrayBuffer of data you want to encrypt
);
// Concatenate IV and encrypted file into a new ArrayBuffer
const resultBuffer = new ArrayBuffer(iv.length + encrypted.byteLength);
new Uint8Array(resultBuffer).set(new Uint8Array(iv), 0);
new Uint8Array(resultBuffer).set(new Uint8Array(encrypted), iv.length);
const blob = new Blob([resultBuffer], { type: "application/octet-stream" });
```
Currently Livepeer supports only video content encrypted using
[SubtleCrypto.encrypt](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/encrypt)
with `AES-CBC` algorithm, which is also the encryption used by other web3
protocols like
[Lit](https://developer.litprotocol.com/sdk/explanation/encryption/). It can
implemented in other environments with regular AES-CBC encryption using PKCS#7
padding.
### Retrieve the Livepeer Public Key
After obtaining an encryption key and encrypting a video file with it, the next
step is to retrieve the Livepeer Public Key. This key will be used to encrypt
our encryption key, which can then be shared with Livepeer when creating a video
asset.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// Fetch the public key from Livepeer
const publicKeyResponse = await fetch(
"https://livepeer.studio/api/access-control/public-key",
{
headers: {
Authorization: "Bearer XXXX-XXXXXX-XXXXXXX-XXXX",
},
}
);
const publicKeyData = await publicKeyResponse.json();
const publicKey = publicKeyData.spki_public_key;
```
### Encrypt the encryption key
Now, we can use asymmetric encryption with the Livepeer Public Key to encrypt
our Encryption Key. The resulting data is then encoded in base64 before being
sent to Livepeer along with the video file.
The Web Cryptography API built into modern browsers does not directly support
PEM or PKCS#1 formatted keys. It only supports the SPKI format for public keys
and the PKCS8 format for private keys. In Javascript, you need to use the
`spki_public_key`.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// Decode the SPKI public key from base64 and convert it to a buffer
const spkiPublicKey = atob(publicKeyData.spki_public_key);
const publicKeyBuffer = Uint8Array.from(atob(spkiPublicKey), (c) =>
c.charCodeAt(0)
).buffer;
// Import the public key
const publicKey = await window.crypto.subtle.importKey(
"spki",
publicKeyBuffer,
{
name: "RSA-OAEP",
hash: { name: "SHA-256" },
},
false,
["encrypt"]
);
// Encrypt the key data with the public key
const encryptedKeyData = await window.crypto.subtle.encrypt(
{
name: "RSA-OAEP",
},
publicKey,
keyData
);
// Base64 encode the encrypted key data
const encryptedKeyBase64 = btoa(
String.fromCharCode(...new Uint8Array(encryptedKeyData))
);
```
### Upload/import the video file
When requesting an upload to the Livepeer API, you can simply
[add an `encryption` field](/api-reference/asset/upload-via-url) with your
encrypted key.
When uploading an encrypted video, specifying a `playbackPolicy` is required.
You can still specify the type of the playback policy as `public`, but be
aware that anyone with the `playbackId` or `playbackUrl` would be able to
watch it.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// Request the upload URL
const response = await fetch(
"https://livepeer.studio/api/asset/request-upload",
{
method: "POST",
headers: {
Authorization: "Bearer XXXX-XXXXXX-XXXXXX-XXXX",
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "File name",
encryption: {
encryptedKey: encryptedKeyBase64,
},
playbackPolicy: {
// Your playback policy
},
}),
}
);
if (!response.ok) {
alert("Error requesting upload URL");
return;
}
const data = await response.json();
// Upload the encrypted file to the returned URL
const uploadResponse = await fetch(data.url, {
method: "PUT",
body: encryptedFile,
});
```
# Engagement via API
Source: https://docs.livepeer.org/v1/developers/guides/get-engagement-analytics-via-api
Learn how to check out viewer engagement on Livepeer
Livepeer offers detailed information on viewer behavior and playback quality on
your platform. The API includes engagement metrics such as view counts and watch
time, as well as performance metrics such as error rate, time to first frame,
rebuffer ratio, and exit-before-starts across a variety of dimensions.
### Realtime Viewership
Please note that in order to use Realtime Viewership metrics, you need to use
Player SDK `@livepeer/react` version 4.2.0 or higher.
This API includes real-time metrics about the ongoing livestream or VOD
engagement:
* Viewer Count: The number of viewers currently watching the stream (or VOD).
* Error Rate: This metric helps to understand the number of errors that viewers
are experiencing while watching the stream (or VOD).
### Usage Metrics
This API includes usage metrics to help you understand how viewers are engaging
with your platform:
* Number of Views: This metric gives you a comprehensive view of the total
number of views across your platform. We colloquially define a view as “play
intent”, which means the video either played, stalled, or encountered an
error.
* Minutes of Watch Time: Measure the total amount of time viewers spend on your
platform, so you can track engagement and identify areas for improvement.
Please note that data is refreshed every 5 minutes and newly uploaded videos
may take up to an hour before viewership data is available
### Performance Metrics
This API offers several key performance metrics to help you understand your
platforms performance:
* Error Rate: Percentage of views that encountered an error.
* Time to First Frame (TTFF): Measures the time in milliseconds it takes between
the player requesting video and the first frame being ready to play.
* Rebuffer Ratio: Percentage of time a viewer spends experiencing rebuffering
during playback.
* Exit Before Starts: Percentage of views that are abandoned before the video
begins to play, potentially indicating issues with playback.
Please note that data is refreshed every 5 minutes and newly uploaded videos
may take up to an hour before viewership data is available
### Dimensions
To provide a comprehensive view of viewer behavior, our data product includes
several dimensions to help you segment your data and identify patterns:
* Video: View metrics for individual videos, queryable by playback ID or by
dStorage ID’s, such as CID.
* Browser: Understand how different browsers impact viewer behavior and
performance, so you can optimize your platform for each browser type.
* Device: Understand how different devices impact viewer behavior, so you can
optimize your platform for each device type.
* OS: Understand how different operating systems impact viewer behavior, so you
can optimize your platform for each OS.
* Continent, Country, and Subdivisions: Segment your data by location to
identify regional trends and tailor your platform to local preferences.
* Time Zone: Measure viewer behavior across different time zones, so you can
optimize your platform for peak usage times.
* Time: Analyze viewer behavior across different time periods (hour, day, week,
month, year, all-time) to identify trends.
## Registering views
To collect and register viewership metrics, you first need to configure your
player. We recommend that you use the [Livepeer player](/sdks/react/player/Root)
to get viewership metrics, as it comes fully configured. You can follow the
Player guide to get started.
We also support viewership metrics for applications using custom players. In
order for metrics to be tracked by Livepeer, you will need to configure your
player using `addMediaMetrics`.
Here's how to configure your player:
Make sure you have initialized your player before calling `addMediaMetrics`.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { addMediaMetrics } from "@livepeer/core-web/browser";
const video = document.getElementById("my-video");
const { destroy } = addMediaMetrics(ref.current);
// or, you can *optionally* pass options to the addMediaMetrics function
const { destroy } = addMediaMetrics(ref.current, {
// specify the source URL of the video, which should include a playbackId.
// this should only be used when using a custom video player that sets a `blob:...` URL or no `src` on the video element.
src: "https://livepeercdn.studio/hls/{playbackId}/index.m3u8",
// specify a unique viewer ID for tracking purposes
viewerId: "user123",
// monitor when the metrics fails to report
onError: (error) => {
console.error("Metrics collection error:", error);
},
});
```
Make sure you have initialized your player before calling `addMediaMetrics`.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { addMediaMetrics } from "@livepeer/core-web/media/browser";
import React, { useEffect, useRef, useState } from "react";
const source = "https://livepeercdn.studio/hls/{playbackId}/index.m3u8";
export default function VideoPlayer() {
const ref = useRef(null);
useEffect(() => {
const { destroy } = addMediaMetrics(ref.current, {
// specify the source URL of the video, which should include a playbackId.
// this should only be used when using a custom video player that sets a `blob:...` URL or no `src` on the video element.
src: source,
// specify a unique viewer ID for tracking purposes
viewerId: "user123",
// monitor when the metrics fails to report
onError: (error) => {
console.error("Metrics collection error:", error);
},
});
return () => destroy();
}, []);
return (
);
}
```
## Retrieving views from the Dashboard
The Livepeer Studio Dashboard is a frontend interface for publishing live or
on-demand video streams with no code. In this guide, we'll show you how to use
the dashboard to retrieve viewership metrics.
### Navigate to the assets page
### Click on an existing asset
Click on an existing asset and you'll be brought to that asset's specific
details page. If you haven't created an asset yet, you can follow the
[upload a video asset guide](/developers/guides/upload-video-asset).
### View your asset's viewership metrics
In the asset's specific detail page you can view its total number of views.
## Retrieving views from the API
### Get the `playbackId` of an existing stream/asset
Get the `playbackId` of an existing asset. A `playbackId` can be found in the
stream/asset page on the dashboard or from any Asset API call. If you haven't
created a stream/asset yet, you can follow the
[upload a video asset guide](/developers/guides/upload-video-asset).
The `playbackId` can be a canonical playback ID from a specific Livepeer asset
or stream objects, or dStorage identifiers for assets. Queries by dStorage ID
are universal/cross-account, as explained below, so check what makes the most
sense for your app.
When querying by dStorage ID (e.g. `ipfs://` or `ar://` URLs, or CID/txID), you
will get views for all assets with that dStorage ID across any Livepeer account.
This is useful to display global metrics from a video. To display the viewership
metrics only from the videos in your account, use the API objects `playbackId`.
### Retrieve viewership data
Once you have the `playbackId`, you can make a request to get the viewership
data.
```sh theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl --request GET \
--url https://livepeer.studio/api/data/views/query/total/{playbackId} \
--header 'Authorization: Bearer '
```
For more information on the API and SDK methods, refer to the [API
reference](/api-reference/viewership/get-public-total-views).
### Diving deeper
If you're happy with the above metrics you can stop here. If you want to build
more advanced analytics, you can use the following API endpoints to get more
detailed data.
#### [Realtime Viewership API](/api-reference/viewership/get-realtime-viewership)
This API can be called from the frontend to retrieve realtime engagement metrics
(current view count and error rate). You can break down the results by playback
id, browser, device, and country.
```sh theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl --request GET \
--url 'https://livepeer.studio/api/data/views/now?playbackId=playback_id&breakdownBy%5B%5D=browser' \
--header 'Authorization Bearer '
```
For more information on the API and SDK methods, refer to the [API
reference](/api-reference/viewership/get-realtime-viewership).
#### [Creator metrics API](/api-reference/viewership/get-creators-metrics)
This API can be called from the frontend to retrieve detailed engagement metrics
for a specific resource. The only restriction it has is that it has to be called
with an `assetId` or `streamId` values, which are private values today that only
the asset creator should have access. Soon this creator ownership will be
validated using wallet signatures instead.
The idea for this API is to build creator analytics dashboards. It can be called
from the frontend and can provide detailed insights to creators about their
assets and streams.
```sh theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl --request GET \
--url 'https://livepeer.studio/api/data/views/query/creator?from=from&to=to&timeStep=day&assetId=asset_id_here&breakdownBy%5B%5D=browser' \
--header 'Authorization: Bearer '
```
For more information on the API and SDK methods, refer to the [API
reference](/api-reference/viewership/get-creators-metrics).
#### [All metrics API](/api-reference/viewership/get-usage-metrics)
This API can be called from the backend to retrieve detailed engagement metrics
for a specific resource. It requires a non-CORS API key to be used, meaning that
it cannot be called from the frontend. This is for security reasons since this
API provides full access to all metrics in the account, meaning it provides the
most flexibility in queries.
The idea is that developers should build their own abstraction and access
control logics on top of this API and abstract it as higher level API in their
apps.
```sh theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl --request GET \
--url 'https://livepeer.studio/api/data/usage/query?timeStep=hour&breakdownBy%5B%5D=creatorId&from=from&to=to' \
--header 'Authorization: Bearer '
```
For more information on the API and SDK methods, refer to the [API
reference](/api-reference/viewership/get-usage-metrics).
### Visualizing Your Data
If you are ready to take a deep dive into your data, then visualizations are the
next step. We have put together a tutorial complete with templates to get you
started.
#### Visualize Engagement Metrics with Grafana
If you are interested in visualizing your engagement metrics with Grafana, feel
free to check out our tutorial,
[Visualize Engagement Metrics with Grafana](/developers/guides/get-engagement-analytics-via-grafana),
to learn more.
# Engagement via Grafana
Source: https://docs.livepeer.org/v1/developers/guides/get-engagement-analytics-via-grafana
Learn how to visualize your engagement metrics with Grafana
In May 2023, we released powerful engagement metrics offering detailed
information on viewer behavior and playback quality on your platform. The API
includes engagement metrics such as view counts and watch time, as well as
performance metrics such as error rate, time to first frame, rebuffer ratio, and
exit-before-starts across a variety of dimensions. For more details, check out
[the docs here][1].
In this tutorial we will introduce a simple, free, and customizable method to
quickly visualize the core metrics and dimensions of the API.
## Prerequisites
Before you begin this tutorial, make sure you have:
1. Integrated the necessary components to capture viewership data. Details
[here][2].
2. Viewed videos via (1) to collect data.
3. Created an [CORS-enabled API Key][3]. The key must allow CORS access from
your Grafana origin, or from all (`*`)
4. Set up a Grafana account and workspace with permissions to add new dashboard
(and datasource/connection, if necessary). A free account is sufficient and
available at [grafana.com][4]
5. Install the [`JSON API`][marcusolsson-json-datasource] plugin for grafana.
With that we are ready to set up our dashboard!
## Setting up the Engagement Dashboard
* Login to Grafana
* Click "Connections" > "Connect Data"
* Set up your JSON API:
1. Name: e.g. "Livepeer Engagement Data"
2. URL: [`https://livepeer.studio/api/data/views/query`][5]
3. Authentication methods: Forward OAuth Identity
4. TLS Settings: Skip TLS certificate validation
5. Custom HTTP Headers
1. Header: "Authorization"
2. Value: Full Access `Bearer `
* Save and Test
* ["Import" the dashboard][6] from the official [Livepeer Studio Viewership
Engagement dashboard][dashboard] and using the JSON API datasource created
above.
* Rename the dashboard if you'd prefer
[1]: /developers/guides/get-engagement-analytics-via-api
[2]: /developers/guides/get-engagement-analytics-via-api#registering-views
[3]: /api-reference/overview/authentication
[4]: https://grafana.com/ "Grafana"
[5]: /api-reference/viewership/get-viewership-metrics
[6]: https://grafana.com/docs/grafana/latest/dashboards/build-dashboards/import-dashboards/#import-a-dashboard
[dashboard]: https://grafana.com/grafana/dashboards/20511-livepeer-studio-user-engagement/
[marcusolsson-json-datasource]: https://grafana.com/grafana/plugins/marcusolsson-json-datasource/ "JSON API Grafana Plugin"
# Engagement via Timeplus
Source: https://docs.livepeer.org/v1/developers/guides/get-engagement-analytics-via-timeplus
Learn how to analyze Livepeer video engagement metrics with Timeplus
Video engagement metrics are important to video creators, serving as valuable
indicators of content quality, helping users manage their time effectively,
facilitating interaction with content creators and other viewers, and
contributing to the overall user experience on video-sharing platforms.
In May 2023, Livepeer released their version of these
[engagement metrics](/developers/guides/get-engagement-analytics-via-api)
offering detailed information on viewer behavior and playback quality on your
platform. The API includes engagement metrics such as view counts and watch
time, as well as performance metrics such as error rate, time to first frame,
rebuffer ratio, and exit-before-starts across a variety of dimensions.
There are many different data analysis tools available today which can be used
to help analyze these engagement metrics. Typically, users need to import the
data into a data platform, and then build queries (SQL or non-SQL based) and
dashboards on that platform to support interactive data exploration or
monitoring what’s happening with those metrics data using visualizations.
# What is Timeplus?
Timeplus is a real-time streaming data analytics platform, it provides analytics
functionality combined with both real-time streaming data and historical
batching data. You can take it as a combination of streaming processing (such as
Apache Flink) + real-time OLAP (such as Apache Druid).
Timeplus is a great tool that can be used for engagement metrics analysis due
to:
* Timeplus offers query analytics capabilities based on SQL, making it
user-friendly for those already proficient in SQL.
* Timeplus delivers ultra-low latency real-time queries, instantly delivering
analytical results to users as events occur.
* Timeplus facilitates the extraction of query time information, eliminating the
need for traditional ETL processes. Users can swiftly create analytics by
combining diverse data sources.
# How to get started using Timeplus with Livepeer's Engagement Data
Analyzing Livepeer engagement metrics on Timeplus is incredibly easy. Based on
the
[Timeplus terraform provider](https://www.timeplus.com/post/timeplus-terraform-provider),
users can create the whole analytic solution with a few simple commands.
Here is the process, assuming you have both a Livepeer studio account and a
Timeplus workspace created.
1. Create a [Livepeer API Key](/api-reference/overview/authentication)
2. Create your [Timeplus API Key](https://docs.timeplus.com/apikey)
3. Install terraform
[https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli](https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli)
4. Download the Livepeer terraform resource definition from
[https://github.com/timeplus-io/livepeer-source/blob/main/stacks/main.tf](https://github.com/timeplus-io/livepeer-source/blob/main/stacks/main.tf)
to your local directory
5. Open a terminal from the directory and add following environments
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
export TF_VAR_timeplus_apikey=your_timeplus_api_key
export TF_VAR_timeplus_workspace=your_timeplus_workspace_id
export TF_VAR_timeplus_endpoint=timeplus_cloud_endpoint
export TF_VAR_livepeer_apikey=your_livepeer_apikey
```
6. Deploy the resources to Timeplus Cloud by run the following commands
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
terraform init
terraform apply
```
This resource template will help users to create the following resources in
Timeplus:
* A [stream](https://docs.timeplus.com/working-with-streams) of engagement
metrics with name `livepeer_viewership_metrics_kv`
* A Livepeer [source](https://docs.timeplus.com/source) which will periodically
pull data from Livepeer API and store the metrics data into the defined stream
* A [user defined function](https://docs.timeplus.com/udf) (UDF) that turns the
geohash into geo locations with longitude and latitude.
* A [dashboard](https://docs.timeplus.com/viz#dashboard) that contains the
following:
* Hourly Views and Watch Time
* Engagement by OS
* View count by Video (Top 5)
* View count by Device Type (Top 5)
* Rebuffering Percentage
* Time to First Frame
* View By Geo Locations
Here is the dashboard that you will instantly get after the resources being
deployed to Timeplus:
# Listen to asset events
Source: https://docs.livepeer.org/v1/developers/guides/listen-to-asset-events
Learn how to listen to asset events using Studio webhooks.
Livepeer Studio uses webhooks to communicate with your application
asynchronously when events for your asset occur. For example, you may want to
know when an asset has been `uploaded` or is `ready`, so that you can surface
this information to viewers.
When these events happen, you can configure Studio to make a `POST` request to a
webhook URL that you specify.
### Type of asset events
| | |
| --------------- | ------------------------------------------------------------------------------------------------------------------------ |
| `asset.created` | This fires when an On Demand asset is created. |
| `asset.updated` | This fires when an On Demand asset is updated. The asset payload will contain a playback URL when playback is available. |
| `asset.ready` | This fires when an On Demand asset is ready. Playback will be available with all transcoded renditions. |
| `asset.failed` | This fires when an On Demand asset fails during the upload or during processing. |
| `asset.deleted` | This fires when an On Demand asset is deleted. |
### Set up a webhook endpoint
The first step is to set up a webhook endpoint in your application. This is the
URL that Livepeer Studio will send the event to - learn more about
[setting up a webhook endpoint](/developers/guides/setup-and-listen-to-webhooks).
### Add a webhook URL to Livepeer Studio
Log in to the [Livepeer Studio](https://livepeer.studio/) and navigate to the
[Developers/Webhooks](https://livepeer.studio/dashboard/developers/webhooks)
page.
Click the "Create Webhook" button and enter the URL of the webhook endpoint.
Select any asset event (with an `asset` prefix) and click "Create Webhook".
# Listen to stream events
Source: https://docs.livepeer.org/v1/developers/guides/listen-to-stream-events
Learn how to listen to stream events using Studio webhooks
Livepeer Studio uses webhooks to communicate with your application
asynchronously when events for your stream occur. For example, you may want to
know when a stream is `active` or `idle`, so that you can surface this
information to viewers.
When these events happen, you can configure Studio to make a `POST` request to a
webhook URL that you specify.
### Type of stream events
| | |
| -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `stream.started` | The parent stream object's isActive value is marked as true and the .m3u8 HLS URL works |
| `stream.idle` | The parent stream object's isActive value should be marked as false and the .m3u8 HLS URL no longer works |
| `recording.ready` | This fires when a recording is ready to be downloaded |
| `recording.started` | This fires when recording has started on an active stream |
| `recording.waiting` | This fires after a stream with recording on has concluded and is not yet ready to be downloaded. Typically it takes 5 minutes for recordings to be ready for download. |
| `multistream.connected` | This fires when we've successfully connected to the multistream target |
| `multistream.error` | This fires when we've encountered an error either while attempting to connect to the third party streaming service or while broadcasting. |
| `multistream.disconnected` | This fires when we are no longer sending video to the multistream target. |
### Set up a webhook endpoint
The first step is to set up a webhook endpoint in your application. This is the
URL that Livepeer Studio will send the event to. Learn more about
[setting up a webhook endpoint](/developers/guides/setup-and-listen-to-webhooks).
### Add a webhook URL to Livepeer Studio
Log in to the [Livepeer Studio](https://livepeer.studio/) and navigate to the
[Developers/Webhooks](https://livepeer.studio/dashboard/developers/webhooks)
page.
Click the "Create Webhook" button and enter URL of webhook endpoint. Select any
stream event (with stream/multistream prefix) to receive notifications for and
click "Create Webhook".
# In-browser broadcasting
Source: https://docs.livepeer.org/v1/developers/guides/livestream-from-browser
Learn how to broadcast using WebRTC
We demonstrate below how to
[broadcast from the web](/developers/core-concepts/studio/in-browser-broadcast)
using Livepeer's low latency WebRTC broadcast. Developers can either use the
Livepeer Broadcast React component, or build their own WebRTC solution.
## Using UI Kit Broadcast
The example below shows how to use the Livepeer UI Kit
[`Broadcast`](/sdks/react/broadcast/Root) component to broadcast from the web.
### Broadcast
This guide assumes you have configured a Livepeer JS SDK client with an API key.
We can use the [`Broadcast`](/sdks/react/broadcast/Root) primitives with a
stream key, from a stream we created.
We show some simple styling below with Tailwind CSS, but this can use any
styling library, since the primitives ship as unstyled, composable components.
```tsx Broadcast.tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { EnableVideoIcon, StopIcon } from "@livepeer/react/assets";
import * as Broadcast from "@livepeer/react/broadcast";
import { getIngest } from "@livepeer/react/external";
const streamKey = "your-stream-key";
export const DemoBroadcast = () => {
return (
LIVELOADINGIDLE
);
};
```
## Embeddable broadcast
This is one of the easiest ways to broadcast video from your
website/applications. You can embed the iframe on your website/applications by
using the below code snippet.
You can replace the `STREAM_KEY` with your stream key for the stream.
```html theme={"theme":{"light":"github-light","dark":"dark-plus"}}
```
This will automatically stream from the browser with a fully composed UI, using
STUN/TURN servers to avoid network firewall issues.
## Adding custom broadcasting
If you want to add custom broadcasting to your app and handle the WebRTC SDP
negotiation without using the Livepeer React primitives, you can follow the
steps below.
### Get the SDP Host
First, you will need to make a request to get the proper ingest URL for the
region which your end user is in. We have a global presence, and we handle
redirects based on GeoDNS to allow users to get the lowest latency server.
To do this make a `HEAD` request to the WebRTC redirect endpoint:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -I 'https://livepeer.studio/webrtc/{STREAM_KEY}'
...
> Location: https://lax-prod-catalyst-2.lp-playback.studio/webrtc/{STREAM_KEY}
```
We are only interested in getting the redirect URL from the response, so that
we can set up the correct ICE servers.
From the above response headers, the best WebRTC ingest URL for the user is
`https://lax-prod-catalyst-2.lp-playback.studio/webrtc/{STREAM_KEY}`. We will
use this in the next step.
The process will change in the future to remove the need for this extraneous
`HEAD` request - please check back later.
### Broadcast
Now that we have the endpoint for the ICE servers, we can start SDP negotiation
following the
[WHIP spec](https://www.ietf.org/archive/id/draft-ietf-wish-whip-01.html) and
kick off a livestream.
The outline of the steps are:
1. Create a new `RTCPeerConnection` with the ICE servers from the redirect URL.
2. Construct an SDP offer using the library of your choice.
3. Wait for ICE gathering.
4. Send the SDP offer to the server and get the response.
5. Use the response to set the remote description on the `RTCPeerConnection`.
6. Get a local media stream and add the track to the peer connection, and set
the video element `src` to the `srcObject`.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// the redirect URL from the above GET request
const redirectUrl = `https://lax-prod-catalyst-2.lp-playback.studio/webrtc/{STREAM_KEY}`;
// we use the host from the redirect URL in the ICE server configuration
const host = new URL(redirectUrl).host;
const iceServers = [
{
urls: `stun:${host}`,
},
{
urls: `turn:${host}`,
username: "livepeer",
credential: "livepeer",
},
];
// get user media from the browser (which are camera/audio sources)
const mediaStream = await navigator.mediaDevices.getUserMedia({
video: true,
audio: true,
});
const peerConnection = new RTCPeerConnection({ iceServers });
// set the media stream on the video element
element.srcObject = mediaStream;
const newVideoTrack = mediaStream?.getVideoTracks?.()?.[0] ?? null;
const newAudioTrack = mediaStream?.getAudioTracks?.()?.[0] ?? null;
if (newVideoTrack) {
videoTransceiver =
peerConnection?.addTransceiver(newVideoTrack, {
direction: "sendonly",
}) ?? null;
}
if (newAudioTrack) {
audioTransceiver =
peerConnection?.addTransceiver(newAudioTrack, {
direction: "sendonly",
}) ?? null;
}
/**
* https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/createOffer
* We create an SDP offer here which will be shared with the server
*/
const offer = await peerConnection.createOffer();
/** https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/setLocalDescription */
await peerConnection.setLocalDescription(offer);
/** Wait for ICE gathering to complete */
const ofr = await new Promise((resolve) => {
/** Wait at most five seconds for ICE gathering. */
setTimeout(() => {
resolve(peerConnection.localDescription);
}, 5000);
peerConnection.onicegatheringstatechange = (_ev) => {
if (peerConnection.iceGatheringState === "complete") {
resolve(peerConnection.localDescription);
}
};
});
if (!ofr) {
throw Error("failed to gather ICE candidates for offer");
}
/**
* This response contains the server's SDP offer.
* This specifies how the client should communicate,
* and what kind of media client and server have negotiated to exchange.
*/
const sdpResponse = await fetch(redirectUrl, {
method: "POST",
mode: "cors",
headers: {
"content-type": "application/sdp",
},
body: ofr.sdp,
});
if (sdpResponse.ok) {
const answerSDP = await sdpResponse.text();
await peerConnection.setRemoteDescription(
new RTCSessionDescription({ type: "answer", sdp: answerSDP })
);
}
```
We just negotiated following the WHIP spec (which outlines the structure for the
POST requests seen above) and we did SDP negotiation to create a new livestream.
We then retrieved a local camera source and started a broadcast!
To make the above process clearer, here is the flow (credit to the authors of
the WHIP spec):
The final HTTP DELETE is not needed for our media server, since we detect the
end of broadcast by the lack of incoming packets from the gateway.
```txt WHIP Outline theme={"theme":{"light":"github-light","dark":"dark-plus"}}
+-----------------+ +---------------+ +--------------+ +----------------+
| WebRTC Producer | | WHIP endpoint | | Media Server | | WHIP Resource |
+---------+-------+ +-------+- -----+ +------+-------+ +--------|-------+
| | | |
| | | |
|HTTP POST (SDP Offer) | | |
+------------------------>+ | |
|201 Created (SDP answer) | | |
+<------------------------+ | |
| ICE REQUEST | |
+----------------------------------------->+ |
| ICE RESPONSE | |
<------------------------------------------+ |
| DTLS SETUP | |
<==========================================> |
| RTP/RTCP FLOW | |
+------------------------------------------> |
| HTTP DELETE |
+------------------------------------------------------------>+
| 200 OK |
<-------------------------------------------------------------x
```
# Managing Projects
Source: https://docs.livepeer.org/v1/developers/guides/managing-projects
Explore best practices for managing multiple environments in Livepeer Studio
## Overview
Projects in Livepeer Studio allow for the organization of streams, assets, API
keys, and usage within dedicated environments. This feature is helpful for
separating staging and production environments, managing multiple applications,
and ensuring efficient workflow within a single account.
## Why Use Projects?
* **Separation of Environments**: Keep your staging and production environments
separate to avoid conflicts and ensure reliable testing.
* **Centralized Management for Multiple Applications**: Instead of juggling
multiple accounts, you can build and manage separate applications from within
the same account. This is ideal for developers and companies that operate
multiple apps or brands and wish to streamline their management in one place.
## Getting Started with Projects
### Creating a New Project
To start building with separate environments or applications, you'll need to
create a new project. Here's how:
1. In the sidebar, click on the project dropdown at the top of the menu.
2. Choose **+ New project** from the dropdown list.
3. Enter a name for your new project when prompted.
4. Confirm the creation to set up your new environment.
### Renaming a Project
1. Within a project, navigate to the **Settings** section in the sidebar.
2. Find the project name field, make your changes, and save.
### Deleting a Project
In the current version of Livepeer Studio, you **cannot** delete a project. But
we are working on adding this feature soon.
## Conclusion
With the introduction of Projects, Livepeer Studio provides you with a powerful
way to manage your application's live and on-demand streams. By leveraging the
ability to create separate projects for staging and production, you can
streamline your workflows and ensure a clean separation of your streaming
environments.
# Monitor stream health
Source: https://docs.livepeer.org/v1/developers/guides/monitor-stream-health
Learn how to monitor stream metrics on Livepeer
This guide provides instructions and information about using stream metrics to:
* Monitor any active stream for issues that may impact the quality of your
stream
* Understand the metrics for operating a livestreaming or user generated content
platform
* View health status of your livestream (API and Dashboard No-Code Option)
## Metrics with Source Segments Duration
The value of `sourceSegmentsDuration` returned is the duration in seconds of the
asset source processed by Livepeer Studio. On the parent stream object, this
value equates to the total amount of source video ingested by Livepeer Studio
all time. On the session object, this value is the length of the livestream
session (or the session recording).
### Request
Use the [get stream](/api-reference/stream/get) endpoint to retrieve a stream,
or
```javascript theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Livepeer } from "livepeer";
const apiKey = 'YOUR_API_KEY';
const streamId = 'STREAM_ID';
const livepeer = new Livepeer({apiKey});
livepeer.stream.get(streamId)
.then((response) => {
console.log("Stream details:", response);
})
.catch((error) => {
console.error("Error fetching stream details:", error);
});
```
```python theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import livepeer
// Initialize the Livepeer client with your API key
client = livepeer.Livepeer(
api_key="",
)
// Replan with the stream ID you want to retrieve
res = client.stream.get(id='')
if res.stream is not None:
# handle response
pass
```
```go theme={"theme":{"light":"github-light","dark":"dark-plus"}}
package main
import(
livepeergo "github.com/livepeer/livepeer-go"
"context"
"log"
)
func main() {
// Initialize the Livepeer client with your API key
client := livepeergo.New(
livepeergo.WithSecurity(""),
)
// Define the stream ID you want to retrieve
var id string = ""
ctx := context.Background()
res, err := client.Stream.Get(ctx, id)
if err != nil {
log.Fatal(err)
}
if res.Stream != nil {
// handle response
}
}
```
**`GET /session/{id}` to retrieve a session object**
```javascript theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Livepeer } from "livepeer";
const apiKey = 'YOUR_API_KEY';
const sessionId = 'SESSION_ID';
const livepeer = new Livepeer({apiKey});
livepeer
.session.get(sessionId)
.then((response) => {
console.log("Session details:", response);
})
.catch((error) => {
console.error("Error fetching session details:", error);
});
```
```python theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import livepeer
client = livepeer.Livepeer(
api_key="",
)
res = client.session.get(id='')
if res.session is not None:
# handle response
pass
```
```go theme={"theme":{"light":"github-light","dark":"dark-plus"}}
package main
import(
livepeergo "github.com/livepeer/livepeer-go"
"context"
"log"
)
func main() {
client := livepeergo.New(
livepeergo.WithSecurity(""),
)
var id string = ""
ctx := context.Background()
res, err := client.Session.Get(ctx, id)
if err != nil {
log.Fatal(err)
}
if res.Session != nil {
// handle response
}
}
```
### Response
* Returns a `200` response with the following object:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"name": "test_stream",
"id": "ijkl61f3-95bd-4971-a7b1-4dcb5d39e78a",
"createdAt": 1596081229373,
"streamKey": "abcd-uimq-jtgy-x98v",
"playbackId": "efghb2mxupongp5k",
"isActive": "true",
"lastSeen": 1596119750455,
"sourceSegments": 1360,
"transcodedSegments": 5480,
"sourceSegmentsDuration": 2630.53200000000004,
"transcodedSegmentsDuration": 10620.1280000000004
// other asset object keys, like profiles and parentId
}
```
### Global Health Status
* `Healthy` indicates that all the Health Checks are in a `Healthy` state.
* `Unhealthy` indicates that one or more of the Health Checks are in an
`Unhealthy` state
* `Idle` indicates that the stream is not currently active
### Health Checks
* ***Transcoding*** — A `Healthy` status indicates that video transcoding is
occurring, and the multiple profiles of your stream are available for
playback. An `Unhealthy` status indicates that we have failed to generate the
profiles, so only the original video will be available. Check the event log
below for any actionable errors, or check the
[Status page](https://livepeer.statuspage.io/) for platform-wide issues.
* ***Real-time —*** This indicates whether our system transcoded the stream
faster than in real-time. In other words, if the video transcodes, latency is
lower than the video duration. Unconventional configurations may cause an
`Unhealthy` status.
* ***Multistreaming —*** This health check indicates whether all configured
`multistream targets` are connected. If no targets exist, this will appear
blank and not be considered for the global health state. If this shows up as
`Unhealthy`, you can also check the status of the individual
`multistream targets` in the `Overview` tab, where the targets can be either
`Idle`, `Pending`, `Online'or' Offline`:
* An `Idle` status indicates that the stream is not currently active, so
neither is multistreaming.
* A `Pending` status indicates that our system tries connecting to the
respective `multistream target`.
* An `Online` status indicates that the `multistream target` is successfully
connected.
* An `Offline` status means that we've received an error when trying to
connect to the target. To try again, check the ingest URL and stream key of
your destination service, re-configure your `multistream target` and restart
your stream.
### Logs
Logs will surface informational alerts (ex., stream has started/stopped,
multistream destinations have connected/disconnected) or any fatal errors from
the transcoding process. Here is an example of a fatal error:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
Transcode error from ewr-prod-livepeer-orchestrator-0 for segment 0:
**Unsupported input pixel format**
```
If you run into this or any similar errors, check the configuration in your
streaming software (e.g., OBS) and restart the stream.
### Session Ingest Rate
Session ingest rate tells you the bitrate of the video received by Livepeer
ingest servers, updated every 10 seconds. A high bitrate is suggestive that
streams into the Livepeer system are high quality, your encoder is working
correctly, and your internet connection is good. A fluctuating or low bitrate
may suggest that your encoder is misconfigured or that the streamer internet
connection isn't as strong as it should be to deliver high-quality streams to
your viewers.
### Monitoring in the Dashboard
In the dashboard, there will be a `health` tab on the right side:

During any Active stream, components on this page will display a variety of health
indicators.


At the bottom of the page, a chart will show the ingest rate of a livestream:

### Monitor with the API
We are working on building a first-class solution to monitor stream health
using the API. Please reach out to us on Discord if you have any input.
# Set up a multistream
Source: https://docs.livepeer.org/v1/developers/guides/multistream
Learn how to add multistreaming
[Multistreaming](/developers/core-concepts/core-api/multistream) allows a source
stream and transcoded renditions to be pushed to multiple RTMP(S) targets, such
as Twitch, Facebook Live, and YouTube Live.
## Multistream targets with the API
You can manage multistream target objects from the API - see the
[API reference](/api-reference/multistream/create). Each target represents a
specific endpoint where a stream could be multistreamed to.
Note that the creation of a multistream target itself is not enough - you also
need to reference the target from the stream object that should be
multistreamed. To avoid managing the separate multistream target objects, you
can also create the targets inlined in the stream
[creation](/api-reference/stream/create) and
[update](/api-reference/stream/update) APIs.
You can also create and remove multistream targets individually from a given
stream using the
[Create Multistream Target](/api-reference/stream/add-multistream-target) and
[Delete Multistream Target](/api-reference/stream/delete-multistream-target)
APIs.
Any changes to multistream targets, including creating new targets, will apply
only to the next active session. If you make changes while a stream is active,
those changes will not apply until the current session has ended and a new
session begins.
## Multistream targets in the Studio dashboard
To add, manage, and delete multistream targets, navigate to the
[Streams page](https://livepeer.studio/dashboard/streams) and click on a stream
name. On the stream detail page, on the Overview tab, you can view all
configured targets. You must configure new multistream targets for each stream.
This will apply the multistream configuration to that stream. Multistream
targets **do not carry over when you create new streams.**
To add a new target, click `Create` on the right side of the multistream targets
section. You'll be asked to name your target, provide the Ingest URL and a
stream key, Ingest URL being the only required value. The Ingest URL and stream
key should be provided by the platform that you're streaming into and can one
of: RTMP, RTMPS, or SRT protocols. Select the rendition profile that you'd like
to send to that target and click `Create Target`. Once created, you can toggle
the targets on and off.
To edit a multistream target, click on the three dots to the right of the target
name and then on `Edit` to open up the target settings. Select `Update Target`
when you've completed your changes.
To delete a multistream target, click on the three dots to the right of the
target name and then on `Delete`.
Any changes to multistream targets, including creating new targets, will apply
only to the next active session. If you make changes while a stream is active,
those changes will not apply until the current session has ended and a new
session begins.
## Understanding Multistream Performance
### Dashboard
While a session is active that has multistream targets configured, you'll be
able to see if a destination is `Active` or `Offline`.
There may be a slight delay between starting the stream and the push
destinations connecting. When starting to stream to multistream targets, use
these indicators to understand whether it has connected to its target(s).
On the stream page where you've configured your multistream targets, select the
Health tab at the top. While a session is active, you'll see the ingest rate of
the source stream.
### Webhooks
There are three webhooks to help you monitor the state of your multistream
targets:
* `multistream.connected`: When Studio has successfully connected to the
multistream target and you're also online in the other service you are
multistreaming to.
* `multistream.error`: In case any error has occurred during connection to the
multistream target. This means some kind of problem with the configuration or
the other service you are multistreaming to.
* `multistream.disconnected`: Sent after a stream is ended to indicate that
Multistream has also ended for the respective target.
# Optimize latency
Source: https://docs.livepeer.org/v1/developers/guides/optimize-latency-of-a-livestream
Learn how to optimize latency for your Livepeer Studio workflow.
One of the first questions that many developers ask during Livepeer Studio
onboarding is: "How do we optimize for low latency?" Many live streaming apps
and sites rely on low latency to promote engagement and interaction between
viewers and streamers.
Latency refers to the lapse in time between a camera capturing an action in
real life and viewers of a livestream seeing it happen on their screen.
Ultra-low latency is when that time is short enough, typically 0.5 - 3
seconds, so viewers of a live-streaming application can interact with what's
happening in the stream in a way that feels natural.
There’s a range of latencies to support a variety of use cases; low or ultra-low
latency is a common goal, but it is one of many viable latency choices. The
right latency depends on what you’re trying to achieve.
In this primer, we provide an overview of Livepeer Studio’s approach to latency.
By the end of the primer, you should have an understanding of how to achieve the
right latency / quality balance for your workflow.
## Understanding Protocols
Livepeer Studio delivers video using several protocols. The most common (though
not the only) delivery protocols supported by Livepeer Studio are **HLS** and
**WebRTC**.
### Delivering video with HLS
HLS (HTTP Live Streaming), initially developed by Apple for iOS devices, serves
video with a series of segmented `.ts` files. It is broadly supported across
many device types and is extremely well-optimized for serving multiple
renditions; these characteristics position HLS as the default choice for many
gateways.
However, HLS has very high overhead and latency. Specifically, its chunked
segment delivery means that viewers must wait for the current segment to finish
downloading before they can start viewing it. Similarly, HLS players often
buffer a few segments in advance to ensure smooth playback and to handle network
fluctuations. This buffer introduces additional latency, as the player waits to
accumulate enough data before starting playback. Buffer behavior is heavily
dependent on client implementation.
**HLS delivers video with standard latency of 10-20 seconds. Streaming HLS
with Livepeer Studio’s recommended low-latency settings lead to \~10s
latency.**
### Delivering video with WebRTC
WebRTC (Web Real-Time Communication) is a streaming protocol known for its
low-latency capabilities, making it suitable for real-time communication
applications like video conferencing, online gaming, and live streaming. Unlike
HLS, which is designed for adaptive streaming and on-demand content, WebRTC
focuses on minimizing latency.
WebRTC offers low latency by prioritizing real-time communication, direct
peer-to-peer connections, UDP transport, and adaptive streaming while minimizing
intermediaries. It is a preferred choice for applications where minimizing delay
is critical, such as video conferencing and live interactive streaming.
**WebRTC delivers video with ultra-low latency of 0.5 - 3 seconds.**
# Optimizing Playback for Low Latency
## Lowest possible latency (WebRTC playback)
WebRTC is available as a delivery protocol for all streams regardless of input
protocol; to achieve the lowest possible latency of 0.5 - 3 seconds, use of
WebRTC delivery is required. We implement the WHIP/WHEP spec with
[a few minor nuances around SDP negotiation](/v1/developers/guides/livestream-from-browser#adding-custom-broadcasting).
To play back a WebRTC rendition, you will need to use a WebRTC-compatible
player, such as the Livepeer Player.
* [Playing WebRTC livestreams with the Livepeer Player](/v1/developers/guides/playback-a-livestream)
* [Playing WebRTC livestreams with other players](/v1/developers/guides/playback-a-livestream#using-your-own-player)
Please note that **if b-frames are present in a livestream, WebRTC renditions
will not be available**. This is because in WebRTC video playback, b-frames
will appear out-of-order on most systems.
## Optimizing for Lower Latency (HLS and WebRTC ingest and playback)
Depending on your goals, you may or may not want to optimize for the lowest
latency; for example, if your user base has a high percentage of low-bandwidth
mobile users, it may be preferable to optimize for bandwidth efficiency over
latency.
### Streaming with OBS
Achieving the right balance between low latency and stream quality is essential
for providing the best possible user experience. Two settings that significantly
impact your stream quality, latency, and user experience are:
* **Rate Control:** This setting dictates the bitrate or "quality" of the
stream. A high amount of bandwidth usually means better quality, but keep in
mind that your output can never improve the quality of your stream beyond your
input.
* **Keyframe Interval:** Video streams consist of full frames and data relative
to the full frames. This setting determines how often a full frame appears,
which heavily influences latency.
To allow streamers to easily configure OBS for best performance with Livepeer
Studio, we’ve created an OBS preset that can be selected in the OBS Settings
panel.
You can read more about configuring OBS here
* [Selecting the Livepeer Studio preset](/v1/developers/guides/stream-via-obs#update-stream-settings)
* [Optimizing OBS for low latency](/v1/developers/guides/stream-via-obs#optimizing-for-low-latency)
* [Optimizing for Stream Quality](/v1/developers/guides/stream-via-obs#optimizing-for-stream-quality-and-user-experience)
Finally, we’ve compiled a set of recommended settings to achieve specific
experience goals (e.g., highest quality but high latency, average quality but
lower latency, or a balanced approach):
* [Sample settings](/v1/developers/guides/stream-via-obs#recommended-obs-settings)
## In-browser broadcasting
Livepeer Studio allows users to broadcast from within their browser using WebRTC
broadcast. **These broadcasts are optimized for low latency by default** and can
play back in HLS (8-10s latency) or WebRTC (0.5 - 3s latency).
You can leverage this capability in three ways:
* [Implement the customizable React component](/v1/developers/guides/livestream-from-browser)
* [Embed a hosted version](/v1/developers/guides/livestream-from-browser#embeddable-broadcast)
* [Roll your own broadcasting experience with plain WebRTC](/v1/developers/guides/livestream-from-browser#adding-custom-broadcasting)
# Smoke testing your workflow
When you first implement your livestreaming workflow, you may see
higher-than-expected latency. This is common and likely means that a few
settings need to be tweaked.
### Check latency using the Livepeer Player
Go to `https://lvpr.tv/?v=` and observe the latency. This will help
isolate the cause of the latency.
If you are seeing higher-than-expected latency on the Livepeer Player (>15s for
HLS or >4s for WebRTC), it suggests something about the incoming stream is
causing high latency. Check your keyframe interval, bitrate, and b-frame
settings.
Viewers changing the resolution will also impact the latency for WebRTC, since
this will necessarily incur transcode latency.
### If you’re using another HLS player, compare your HLS config to the Livepeer Player
Our defaults can be found
[here](https://github.com/livepeer/react/blob/47e572880224739f538e75ef192bb290b85a852f/packages/core-web/src/media/browser/hls/index.ts#L55-L61).
Please note that this config is a starting point that we feel is a good balance
for latency, quality, rebuffering, etc.
### Reach out to the Livepeer Studio team
We will be happy to help troubleshoot so that you are able to achieve 0.5-3s
latency with WebRTC or \~10s latency with HLS for the bulk of your users. Often,
we achieve improvements by helping you tweak broadcasting settings or optimizing
HLS configs.
# Overview
Source: https://docs.livepeer.org/v1/developers/guides/overview
Practical step-by-step guides to help you achieve a specific goal. These guides are designed to help you get started with a specific task or feature.
### Video On Demand
Upload a video asset to Livepeer
Play a video asset with Player
Upload and store encrypted videos.
Set up webhook to receive notifications.
Transcode videos programmatically
Retrieve analytics via Livepeer API.
Visualize analytics using Grafana.
Visualize analytics using Timeplus.
### Livestream
Start a live video broadcast.
Watch live broadcasts in real-time.
Broadcast using OBS
Go live directly from your web browser.
Keep track of the livestream's health
Set up webhook to receive notifications.
Livestream to multiple platforms at once.
Clip a livestream
### Access control
Control access using webhooks
Control access using JWTs
### Webhooks
Set up webhook to receive notifications.
# Play a livestream
Source: https://docs.livepeer.org/v1/developers/guides/playback-a-livestream
Learn how to use a media player with Livepeer
In this guide, we demonstrate how to play livestreams in your application.
We do not recommend using ["CORS-enabled" API
keys](/api-reference/overview/authentication) - they will be deprecated in an
upcoming release. We recommend making requests from your backend to the
Livepeer Studio API.
## Using the UI Kit Player
The example below show to use the UI Kit [`Player`](/sdks/react/player/Root) to
play a livestream.
### Play Video
This guide assumes you have configured a Livepeer JS SDK client with an API key.
We use the [`Player`](/sdks/react/player/Root) with a `playbackId`, which we
created previously when creating a livestream.
```tsx DemoPlayer.tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
import { getSrc } from "@livepeer/react/external";
const playbackId = "f5eese9wwl88k4g8";
// fetch the playback info on the server, using React Server Components
// or regular API routes
export const getPlaybackSource = () => {
const playbackInfo = await livepeer.playback.get(playbackId);
const src = getSrc(playbackInfo.playbackInfo);
return src;
};
export const DemoPlayer = ({ src }: { src: Src[] | null }) => {
return (
);
};
```
Check out the [Player docs](/sdks/react/player/Root) for more details on the
video primitives you can use to build custom viewing experiences.
## Using your own player
Using Livepeer React is the recommended way to play back a livestream - it
handles WebRTC WHEP playback, fallback to HLS on errors (which may occur with
WebRTC due to network firewalls, etc), errors from the API, and is composable
to allow advanced video apps without writing a custom integration. However, if
you want to use an alternative, you can do so by following the instructions
below.
### Fetch the playback URL
To play back a livestream in other players, you'll need to fetch the playback
URL(s). By default, all content has an HLS endpoint. HLS is a protocol that
allows you to stream video and audio content over HTTP. Much of the video you
watch on the web is delivered using HLS. Livepeer uses HLS to deliver video and
audio content.
We also support WebRTC WHEP low latency playback - however, ecosystem player
support is limited, as it is a new spec that is rapidly gaining traction.
Below, we show how to fetch playback info in Typescript using the
[playback info API endpoint](/api-reference/playback/get), but we have a similar
interface across all SDKs.
```tsx DemoPlayer.tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Player } from "@livepeer/react";
import Livepeer from "livepeer";
const livepeer = new Livepeer({
apiKey: process.env.YOUR_PRIVATE_API_KEY,
});
const playbackId = "f5eese9wwl88k4g8";
// fetch the playback info on the server
const playbackInfo = await livepeer.playback.get(playbackId);
// use the playbackInfo with your player
```
Please note that to play back livestreams inside your application you'll need
to use a video player component that supports HLS or WebRTC WHEP.
### Handling various playback sources
The playback info endpoint can return multiple sources in the response, as
outlined above.
WebRTC URLs for low latency livestream playback *must* be played back with our
ICE servers, which are used to route traffic in restricted networking
environments. The WebRTC WHEP negotiation will send back these STUN/TURN servers
in the SDP response headers, which can be used in a player.
If there is WebRTC playback available, the API will return a JSON payload
similar to:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"type": "live",
"meta": {
"live": 0,
"source": [
{
"hrn": "HLS (TS)",
"type": "html5/application/vnd.apple.mpegurl",
"url": "https://livepeercdn.studio/hls/{PLAYBACK_ID}/index.m3u8"
},
{
"hrn": "WebRTC (H264)",
"type": "html5/video/h264",
"url": "https://livepeercdn.studio/webrtc/{PLAYBACK_ID}"
},
{
"hrn": "Thumbnail (PNG)",
"type": "image/png",
"url": "https://storage.lp-playback.studio/{ID}/catalyst-recordings-com/hls/{PLAYBACK_ID}/{ID}/source/latest.png"
}
]
}
}
```
There are multiple sources you can choose from, and it is up to you to decide
how you want to prioritize each source for your custom player. See the
[Player docs](/sdks/react/player/Root) for more information on how Livepeer UI
Kit Player handles this.
### Use the playback URL in a player
You can use the playback URL with any video player that supports HLS. Here is a
list of popular players that support HLS:
* [Video.js](https://videojs.com/)
* [Plyr.io](https://plyr.io/)
* [JW Player](https://www.jwplayer.com/html5-video-player/)
* [Bitmovin Player](https://bitmovin.com/video-player/)
* [HLS.js](https://github.com/video-dev/hls.js) (requires custom logic to wire
to a video element)
Here is an example of how to use the playback URL in video.js player.
```html theme={"theme":{"light":"github-light","dark":"dark-plus"}}
```
## Embeddable Player
Livepeer Studio maintains an embeddable version of the Livepeer Player that is
suitable for iframing.
If you are using React, consider using Livepeer UI Kit instead.
This is one of the easiest ways to play back a livestream on your website. You
can embed the player by using the below code snippet.
You can replace the `PLAYBACK_ID` with your video's playback id.
```html theme={"theme":{"light":"github-light","dark":"dark-plus"}}
```
### Low Latency
In the embeddable player, livestreams will, by default, play back with
low-latency WebRTC. If this does not succeed in playing back (rarely, usually
due to a slow network or connectivity issues), the embeddable player will
automatically fall back to HLS playback. Also, if the stream contains B-frames
(or bidirectional frames, which are common for users streaming with OBS or other
streaming apps), the Player will automatically fall back to HLS, so that
out-of-order frames are not displayed. *This only applies to users who are
playing livestreams.*
If you do not want to use WebRTC, you can pass `&lowLatency=false` in the query
string, or if you want *only* low latency, you can pass `&lowLatency=force`.
OBS users should be instructed to use the Livepeer Studio stream profile, or
to manually turn off B-frames in their stream. See our [Stream from
OBS](/developers/guides/stream-via-obs) docs for more information.
### Clipping
To enable clipping, `&clipLength={seconds}` can be passed, which will allow
viewers to clip livestreams. The length in seconds **must be less than 120
seconds**.
### Constant Playback
The embed supports "constant" playback with `constant=true`, which means that
audio will not be distorted if the playhead falls behind the livestream. This is
usually used for music applications, where audio quality/consistency is more
important than latency.
### Other Configs
You can also override the default `muted` and `autoplay` behavior with
`&muted=false` and/or `&autoplay=false`. These are set to true by default.
Looping can also be set with `&loop=true`.
# Play an asset
Source: https://docs.livepeer.org/v1/developers/guides/playback-an-asset
Learn how to play assets with Livepeer
In this guide, we demonstrate how to play back assets in your application.
We do not recommend using ["CORS-enabled" API
keys](/api-reference/overview/authentication) - they will be deprecated in an
upcoming release. We recommend making requests from your backend to the
Livepeer Studio API.
## Using the Livepeer React Player
The example below shows how to use the Livepeer React
[`Player`](/sdks/react/player/Root) to view a video asset, with some custom
styles to demonstrate what's possible.
### Play Video
This guide assumes you have configured a Livepeer JS SDK client with an API key.
We can use the [`Player`](/sdks/react/player/Root) with a `playbackId`, which we
created previously when uploading a video asset.
```tsx DemoPlayer.tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
import { getSrc } from "@livepeer/react/external";
import Image from "next/image";
const playbackId = "f5eese9wwl88k4g8";
// fetch the playback info on the server, using React Server Components
// or regular API routes
export const getPlaybackSource = () => {
const playbackInfo = await livepeer.playback.get(playbackId);
const src = getSrc(playbackInfo.playbackInfo);
return src;
};
// pass the parsed playback info Src[] into the player
export const DemoPlayer = ({ src }: { src: Src[] | null }) => {
return (
);
};
```
Check out the [Player docs](/sdks/react/player/Root) for more details on the
video primitives you can use to build custom viewing experiences.
## Using your own player
Using Livepeer UI Kit is the recommended way to play back an asset - it
handles prioritizing HLS & MP4 renditions, errors from the API, and is
composable to allow advanced video apps without writing a custom integration.
However, if you want to use an alternative, you can do so by following the
instructions below.
### Fetch the playback URL
To play back a livestream in other players, you'll need to fetch the playback
URL(s). By default, all content has an HLS endpoint. HLS is a protocol that
allows you to stream video and audio content over HTTP.
Short-form assets will also have one or more MP4 source URLs.
Below, we show how to do this in Typescript using the
[playback info API endpoint](/api-reference/playback/get), but we have a similar
interface across all SDKs.
```tsx DemoPlayer.tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Player } from "@livepeer/react";
import Livepeer from "livepeer";
const livepeer = new Livepeer({
apiKey: process.env.YOUR_PRIVATE_API_KEY,
});
const playbackId = "f5eese9wwl88k4g8";
// fetch the playback info on the server
const playbackInfo = await livepeer.playback.get(playbackId);
// use the playbackInfo with your player
```
#### Source playback
When an asset is initially created, we will provide a "source playback" URL in
the list returned from the
[playback info endpoint](/api-reference/playback/get). This is a non-transcoded
version of the asset that can be played immediately, while processing happens in
the background. The playback info endpoint will then automatically update with
the transcoded renditions when processing is completed.
### Handling various playback sources
The playback info endpoint can return multiple sources in the response. These
may include short form MP4 playback URLs, which allow you to obtain alternative
URLs for your video asset to enable applications (and CDNs) to cache short
videos for instant playback of subsequent videos. This means that viewers can
experience instant time-to-first-frame (TTFF) when watching short videos.
It is important to note that short form playback URLs are only available for
video assets that are less than 2 minutes in duration.
If there are MP4 renditions or HLS playback available, the
[playback info endpoint](/api-reference/playback/get) will return:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"type": "vod",
"meta": {
"source": [
{
"hrn": "MP4",
"type": "html5/video/mp4",
"url": "https://asset-cdn.lp-playback.com/hls/{PLAYBACK_ID}/static360p0.mp4",
"size": 494778,
"width": 204,
"height": 360,
"bitrate": 449890
},
{
"hrn": "MP4",
"type": "html5/video/mp4",
"url": "https://asset-cdn.lp-playback.com/hls/{PLAYBACK_ID}/static720p0.mp4",
"size": 1869154,
"width": 406,
"height": 720,
"bitrate": 1996936
},
{
"hrn": "HLS (TS)",
"type": "html5/application/vnd.apple.mpegurl",
"url": "https://livepeercdn.studio/recordings/{RECORDING_ID}/index.m3u8"
}
]
}
}
```
There are multiple renditions you can choose from, and it is up to you to decide
how you want to prioritize each source for your custom player.
When you make a request for playback URLs, in the response MP4 URLs are always
listed before HLS URLs. Additionally, each MP4 URL includes additional
metadata about the video, such as its width, height, bitrate, and size. This
metadata can be useful for mobile applications that want to optimize playback
quality and size based on the viewer's device and network conditions.
### Use the playback URL in a player
You can use the playback URL with any video player that supports HLS. Here is a
list of popular players that support HLS:
* [Video.js](https://videojs.com/)
* [Plyr.io](https://plyr.io/)
* [JW Player](https://www.jwplayer.com/html5-video-player/)
* [Bitmovin Player](https://bitmovin.com/video-player/)
* [HLS.js](https://github.com/video-dev/hls.js) (requires custom logic to wire
to a video element)
Here is an example of how to use the playback URL in video.js player.
```html theme={"theme":{"light":"github-light","dark":"dark-plus"}}
```
## Embeddable Player
Livepeer Studio maintains an embeddable version of the Livepeer Player that is
suitable for iframing.
If you are using React, consider using Livepeer UI Kit instead.
This is one of the easiest ways to play back a video on your website. You can
embed the player by using the below code snippet.
You can replace the `PLAYBACK_ID` with your video's playback id.
```html theme={"theme":{"light":"github-light","dark":"dark-plus"}}
```
### Configuration
If you are using the iframe for livestreams as well as assets, see the
livestream embed docs for how to set up low latency, clipping, and other
configs for streams.
You can override the default `muted` and `autoplay` behavior with `&muted=false`
and/or `&autoplay=false`. These are set to true by default. Looping can also be
set with `&loop=true`.
# Set up and listen for webhooks
Source: https://docs.livepeer.org/v1/developers/guides/setup-and-listen-to-webhooks
Learn how to set up a webhook using Node.js and Ngrok to receive notifications from Livepeer.
A webhook trigger event refers to a specific occurrence or action in Livepeer
that prompts the webhook to send data to another system. You can learn more
about the different webhook events in the Studio
[Webhook Core Concept](/developers/core-concepts/studio/webhooks) section.
Setting up a webhook using Node.js and Ngrok allows you to receive real-time
data from Livepeer. In this guide, we'll walk you through the steps to set up a
webhook using Node.js and Ngrok to receive notifications from Livepeer.
### Create a New Node.js Project
Open your terminal and create a new directory for your project:
```sh theme={"theme":{"light":"github-light","dark":"dark-plus"}}
mkdir webhook-project
cd webhook-project
```
Next, initialize a new Node.js project:
```sh theme={"theme":{"light":"github-light","dark":"dark-plus"}}
npm init -y
```
### Install Dependencies
You'll need the Express.js framework to create a web server and the body-parser
middleware to parse incoming JSON data.
```sh theme={"theme":{"light":"github-light","dark":"dark-plus"}}
npm install express body-parser --save
```
### Create an Express.js Server
Create an `app.js` file in your project directory and set up an Express.js
server:
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const express = require("express");
const bodyParser = require("body-parser");
const app = express();
const port = 3000;
// Parse JSON requests
app.use(bodyParser.json());
// Define a route to handle incoming webhook data
app.post("/webhook", (req, res) => {
const payload = req.body;
console.log("Received webhook data:", payload);
// Handle the webhook data here
res.sendStatus(200);
});
// Start the server
app.listen(port, () => {
console.log(`Server is running on http://localhost:${port}`);
});
```
next, run your Express server using the following command:
```
node app.js
```
Your Express server is now running locally on [http://localhost:3000](http://localhost:3000).
In this case, we're using Ngrok to expose our local server to the internet. If
you're running your server on a remote server, you can skip the next step. And
for production applications, you'll want to deploy your server to a cloud
provider like Vercel or Fly.io.
### Set Up Ngrok
Ngrok will create a secure tunnel to expose your local server to the internet.
In a new terminal window, run the following command:
```sh theme={"theme":{"light":"github-light","dark":"dark-plus"}}
ngrok http 3000
```
If you don't have Ngrok installed, you can download it
[here](https://ngrok.com/download).
Ngrok will provide a public URL (e.g., [https://abc123.ngrok.io](https://abc123.ngrok.io)). You'll use this
URL as your webhook endpoint.
### Set Up a Webhook in Livepeer Studio
Log in to [Livepeer Studio](https://livepeer.studio/) and navigate to the
[Developers/Webhooks](https://livepeer.studio/dashboard/developers/webhooks)
page.
Click the Create Webhook button and enter your Ngrok URL as the webhook
endpoint. Select the an event to receive notifications for and click Create
Webhook.
You should now receive webhook requests for the event you selected.
## Webhook Payload
Webhook payloads contain information about the event that triggered the webhook.
The payload is a JSON object that contains different properties depending on the
event type.
The fields are defined as:
The id of webhook
The time when the webhook was created
The time when the webhook was triggered
The event type that triggered the webhook
The object payload. This will be a stream/asset/task. The definitions can be
found in the [API reference](/api-reference/overview/introduction) for the
specific object type.
## Webhook Signatures
It is highly recommended that you verify signatures of incoming webhooks. If
anyone has access to your webhook URL, they can fake events from Studio. See
[Webhooks.fyi](https://webhooks.fyi/) for examples on best practices for
webhooks.
You should verify the webhook requests that Livepeer Studio sends to your
endpoints, using the request header signature. This signature will help you
verify the incoming request.
* Livepeer Studio will include a signature in each event’s `Livepeer-Signature`
header.
* The timestamp is prefixed by `t=` and the signature is prefixed by a scheme.
* Schemes start with `v`, followed by an integer. Currently, the only valid
signature scheme is v1. Livepeer Studio generates signatures using HMAC with
SHA2-256.
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
Livepeer-Signature: t=36285904404,v1=88f3ff0fds9sf8a98vb0b096e81507cfd5c932fc17cf63a4a55566fd38da3a2d3d2
```
### Extract from the header
1. Split the header, using the `,` character as the separator, to get a list of
elements.
2. Split each element, using the `=` character as the separator, to get a prefix
and value pair.
The value for the prefix `t` corresponds to the timestamp, and `v1` corresponds
to the signature (or signatures). You can discard all other elements.
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
t=36285904404
v1=88f3ff0fds9sf8a98vb0b096e81507cfd5c932fc17cf63a4a55566fd38da3a2d3d2
```
### Prepare the signed payload
The `signed_payload` is the raw request payload.
It is important to note that the `JSON` in the request payload includes the same
`timestamp` from the signature header to protect against replay attacks.
Compare the signature (or signatures) in the header to the expected signature.
* **For an equality match** compute the difference between the current timestamp
and the received timestamp, then decide if the difference is within your
tolerance.
* **To protect against timing attacks:** use a constant-time string comparison
to compare the expected signature to each of the received signatures.
## Troubleshooting Common Issues
During the setup and operation of your webhook in conjunction with Livepeer
Studio, you may encounter issues that prevent your application from receiving or
processing webhook events as expected. Here, we'll outline some common issues,
their solutions, and how to debug them.
### Local Endpoint Configuration
1. **Not Receiving Webhook Calls:**
* Make sure that your local server is running and accessible. If using Ngrok,
ensure it's properly forwarding requests to your local server.
* Check the Ngrok's web interface (usually accessible at
[http://localhost:4040](http://localhost:4040)) to see the list of HTTP requests being forwarded to
your local server.
* Ensure that the URL you set in Livepeer Studio for your webhook endpoint is
correct and is the public URL provided by Ngrok.
2. **Error Messages in Your Server Logs:**
* Look at the console logs in your terminal where your Node.js server is
running to see if there are any error messages.
* Common errors might include problems parsing the request body, or errors in
your route handling logic.
3. **Verifying Webhook Signatures:**
* If you are having trouble verifying the webhook signatures, double-check
the logic in your verification code against the steps outlined in the guide
above.
* Ensure you are correctly extracting the timestamp and signatures from the
header and preparing the `signed_payload` string as described.
### Debugging Tips
1. **Logging:**
* Add `console.log` statements in your Express.js route handler to output the
request headers, body, and any other relevant information to the console.
* This can help you understand the data you're receiving and identify any
discrepancies between what you expect and what you're actually getting.
2. **Error Handling:**
* Add error handling logic to your route handler to catch and log errors.
This can help you identify issues in your code or configuration.
* Return meaningful error responses from your server to assist in debugging.
For example, return a 400 Bad Request status code with a message indicating
what was wrong with the request.
3. **Tools:**
* Use tools like [Postman](https://www.postman.com/) to send test requests to
your server to ensure it's responding as expected.
* Utilize Ngrok's web interface to inspect the HTTP requests and responses
being sent between Livepeer Studio and your server.
4. **Livepeer Studio Dashboard:**
* Check the Livepeer Studio dashboard for any error messages or logs related
to your webhook configuration or the events you are subscribed to.
# Livestream via OBS
Source: https://docs.livepeer.org/v1/developers/guides/stream-via-obs
Learn how to stream into Livepeer Studio with OBS
The purpose of this guide is to allow you to get a more in-depth look at setting
up a livestream using Livepeer Studio with OBS.
## Introduction
[OBS](https://obsproject.com/) is an application that many creators use to
stream into Livepeer because it is easy to use, open source, and offers a high
degree of customization.
## Get a unique stream key
Follow our previous guide on
[creating a stream](/developers/guides/create-livestream) to get a stream key to
provide to the creator on your platform. They will need to use this for their
OBS configuration.
## Open OBS and create source
The creator will then need to:
1. Click the **+ icon** under sources and select **Video Capture Device** if
you’d like to stream using a camera or webcam. If you’d like to stream a
browser window, select **Window Capture**.
2. Give the device a name:
## Update stream settings
1. Select **Stream** settings.
2. Select **Show All...** and then **Livepeer Studio** for the service.
3. Keep the **Default** Server and paste the **Stream Key** provided by Livepeer
Studio into the OBS **“Stream Key”** fields. It is highly recommended to not
ignore the streaming service recommendations. If you choose to do this,
please see the [low latency](#configuring-obs-for-low-latency) section below.
## Stream and play back
After they save their settings, OBS will return to the stream console.
Press start streaming (from the output they selected when inputting your stream
settings above). Any player will now be able to
[play back the livestream](/developers/guides/playback-a-livestream) with the
playback ID.
## Configuring OBS for Low Latency
### Balancing Low Latency with User Experience
Achieving the right balance between low latency and stream quality is essential
for providing the best possible user experience. Two settings that significantly
impact your stream quality, latency, and user experience are:
* **Rate Control:** This setting dictates the bitrate or "quality" of the
stream. A high amount of bandwidth usually means better quality, but keep in
mind that your output can never improve the quality of your stream beyond your
input.
* **Keyframe Interval:** Video streams consist of full frames and data relative
to the full frames. This setting determines how often a full frame appears,
which heavily influences latency.
#### Optimizing for Low Latency
Low latency is primarily determined by the *keyframe interval*. Having keyframes
appear more frequently allows viewers to "hook onto" a point closer to the
actual live point. However, full frames can't (re)use references to other
frames, so more bandwidth is needed to generate a stream of the same quality
compared to one with a lower number of keyframes.
We also require that the user turns off B-frames for lowest latency. B-frames,
or bidirectional frames, are a type of video frame that makes use of
references from the past as well as the future. They improve video compression
by having more context, but also increase latency because they require a
bigger encode buffer. Furthermore, in WebRTC video playback, B-frames will
appear out-of-order on most systems.
#### Optimizing for Stream Quality and User Experience
Stream quality and user experience are mainly decided by the rate control of the
stream. When optimizing for user experience, consider the stability of the video
playback and the smoothness of the video. This is mostly decided by the peak
bitrate of the video. A high peak bitrate can cause playback problems like
buffering or skips in video playback for some viewers.
#### Livepeer-specific considerations
Since Livepeer is mostly HLS-based, a 2-second keyframe interval is generally
encouraged, as HLS has a minimum latency of around 3-5 keyframe intervals. This
choice would prioritize low latency.
However, if the connection is fairly poor, a 5-second keyframe interval will
allow for higher quality per bit at the expense of more latency. If quality is
valued over latency, this is a better choice, and you could even consider going
for longer intervals. It is essential to understand the impact of each setting
and adapt them to your specific requirements and priorities. The optimal stream
settings may vary depending on your specific requirements.
### Recommended OBS Settings
The following profiles provide a good starting point for balancing low latency
with stream quality and user experience. You may need to adjust the settings to
suit your specific situation.
#### Low latency, high quality
This profile prioritizes low latency, but still maintains a good quality at the
cost of more (and more unpredictably spiking) bandwidth.
```txt theme={"theme":{"light":"github-light","dark":"dark-plus"}}
Rate Control: CRF
CRF: 25
Keyframe Interval: 1
CPU Usage Preset: Very fast
Profile: High
Tune: None
x264 options: bframes=0
Resolution: 1080p
```
#### Low latency for bad connections
This profile prioritizes low latency, sacrificing quality to maintain a low bit
rate so that even those with bad connections can watch reliably.
```txt theme={"theme":{"light":"github-light","dark":"dark-plus"}}
Rate Control: CBR
Bit Rate: 1200
Keyframe Interval: 1
CPU Usage Preset: Very fast
Profile: High
Tune: None
x264 options: bframes=0
Resolution: 720p
```
#### Balanced high quality
A good balance between reasonable latency and reasonable bit rate, but with
consistently high quality.
```txt theme={"theme":{"light":"github-light","dark":"dark-plus"}}
Rate Control: CRF
CRF: 25
Keyframe Interval: 2
CPU Usage Preset: Very fast
Profile: High
Tune: None
No additional x264 options
Resolution: Any
```
#### Balanced for bad connections
A good balance between reasonable latency and reasonable quality, but with a
consistent bit rate that should be comfortably viewable for most modern internet
connections.
```txt theme={"theme":{"light":"github-light","dark":"dark-plus"}}
Rate Control: CBR
Bit Rate: 2000
Keyframe Interval: 2
CPU Usage Preset: Very fast
Profile: High
Tune: None
No additional x264 options
Resolution: Up to 1080p
```
#### High quality, high latency
This profile prioritizes quality over everything else, sacrificing latency to
keep the bit rate within reasonable bounds.
```txt theme={"theme":{"light":"github-light","dark":"dark-plus"}}
Rate Control: CRF
CRF: 27
Keyframe Interval: 10
CPU Usage Preset: Very fast
Profile: High
Tune: None
x264 options: bframes=3
Resolution: 1080p
```
#### Low bandwidth, high latency
This profile prioritizes watchability, even for really bad connections,
sacrificing both quality and latency to do so.
```txt theme={"theme":{"light":"github-light","dark":"dark-plus"}}
Rate Control: CBR
Bit Rate: 700
Keyframe Interval: 10
CPU Usage Preset: Very fast
Profile: High
Tune: None
x264 options: bframes=3
Resolution: 720p or lower
```
# Get a livestream thumbnail
Source: https://docs.livepeer.org/v1/developers/guides/thumbnails-live
Learn how to retrieve thumbnails for a live stream
For live streams, we provide a single updating thumbnail URL - it will return
the **first frame of the most recent segment of video**.
## Create a stream
Follow our previous guide on
[creating a stream](/developers/guides/create-livestream) to get a stream key. A
creator can then start a stream.
## Fetch playback info
After \<1 minute of the stream ingest starting, a thumbnail URL should be
returned from the [playback info API endpoint](/api-reference/playback/get).
Example response:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"type": "live",
"meta": {
"live": 0,
"source": [
{
"hrn": "HLS (TS)",
"type": "html5/application/vnd.apple.mpegurl",
"url": "https://livepeercdn.studio/hls/{playbackId}/index.m3u8"
},
{
"hrn": "WebRTC (H264)",
"type": "html5/video/h264",
"url": "https://livepeercdn.studio/webrtc/{playbackId}"
},
{
"hrn": "Thumbnail (PNG)",
"type": "image/png",
"url": "https://recordings-cdn-s.lp-playback.studio/hls/{playbackId}/{ID}/source/latest.png"
}
]
}
}
```
You should see an entry in the `source` array with the type `image/png`. This
URL will always return the **latest thumbnail of your stream**.
The thumbnail will always have a `hrn` of `Thumbnail (PNG)` and `type` of
`image/png`.
This thumbnail is also used in the Player - it is automatically parsed in
[`getSrc`](/sdks/react/player/get-src) and passed as the video `poster`
attribute, and updated every few seconds.
## Examples
A common use for this feature is to show a live preview URL which constantly
updates with the latest frame from the stream.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PreviewComponent() {
// Update to your thumbnail URL
const thumbnailUrl =
"https://recordings-cdn-s.lp-playback.studio/hls/61482gtjzi49cyvb/6cf39a0f-8b68-4ff8-8c7b-b105d6a6a9ed/source/latest.png";
const [randomValue, setRandomValue] = useState(Date.now());
// We will append a random value to the URL to force the browser to fetch the latest image (at least every 5 seconds)
useEffect(() => {
const interval = setInterval(() => {
setRandomValue(Date.now()); // Update the randomValue every 5 seconds
}, 5000);
return () => clearInterval(interval); // Clean up the interval on unmount
}, []);
return ;
}
```
# Get an asset thumbnail
Source: https://docs.livepeer.org/v1/developers/guides/thumbnails-vod
Learn how to retrieve thumbnails for a video asset
For video assets we provide a way to retrieve a list of thumbnails for your
video assets. Thumbnails will be generated as part of the asset processing, with
each "segment" (which is roughly every 3 seconds) of video resulting in one
image.
Follow the steps below to find out how to use this.
## Upload an asset
Follow our previous guide on
[uploading an asset](/developers/guides/upload-video-asset) and get the
`playbackId`.
Any assets uploaded after November 21st, 2023 will have thumbnails generated
for them. If the asset was uploaded before then, it will need to be
re-imported to create thumbnails.
## Fetch playback info
Once the processing has completed for your asset, fetch the playback info using
the [playback info API endpoint](/api-reference/playback/get).
Example response:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"type": "vod",
"meta": {
"playbackPolicy": null,
"source": [
{
"hrn": "HLS (TS)",
"type": "html5/application/vnd.apple.mpegurl",
"url": "https://vod-cdn.lp-playback.studio/raw/jxf4iblf6wlsyor6526t4tcmtmqa/catalyst-vod-com/hls/95c9ih1y6tl97xbx/index.m3u8"
},
{
"hrn": "Thumbnails",
"type": "text/vtt",
"url": "https://vod-cdn.lp-playback.studio/raw/jxf4iblf6wlsyor6526t4tcmtmqa/catalyst-vod-com/hls/95c9ih1y6tl97xbx/thumbnails/thumbnails.vtt"
}
]
}
}
```
You should see an entry in the `source` array with the type `text/vtt`. This
file uses the [WebVTT format](https://w3c.github.io/webvtt/) to represent the
thumbnails associated with each time point in the video.
This format was chosen with the use case of thumbnail scrubbing in mind, to
allow a player to overlay thumbnail images as the user is seeking through a
video, but it allows more general usage of selecting a desired time in your
video and fetching a thumbnail for it.
This will always have a `hrn` of `Thumbnails` and `type` of `text/vtt`.
## Download the VTT file
Fetch the VTT file from the URL above.
```vtt theme={"theme":{"light":"github-light","dark":"dark-plus"}}
WEBVTT
00:00:00.000 --> 00:00:10.000
keyframes_0.jpg
00:00:10.000 --> 00:00:20.000
keyframes_1.jpg
00:00:20.000 --> 00:00:29.000
keyframes_2.jpg
```
## Show a thumbnail
Use one of the JPG paths to download a thumbnail. As an example if your VTT URL
is:
```
https://vod-cdn.lp-playback.studio/catalyst-vod-com/hls/ac906f1cs0oe9rb1/thumbnails/thumbnails.vtt
```
You can get the first frame of the video from:
```
https://vod-cdn.lp-playback.studio/catalyst-vod-com/hls/ac906f1cs0oe9rb1/thumbnails/keyframes_0.jpg
```
This is a pattern that can be used for any asset to get a preview thumbnail.
Since these coincide with a "segment" (roughly every 3 seconds), the index (in
the example above, `keyframes_0.jpg`) can be varied depending on your apps
use-case. These can be used to form reliable preview images for an asset.
# Transcode with Storj
Source: https://docs.livepeer.org/v1/developers/guides/transcode-video-storj
This guide will describe how to use the Livepeer
[transcode API](/api-reference/transcode/create) to transcode and store video
files in Storj using Storj’s S3 API.
There are [code examples](#code-examples) provided for reference.
The Transcode API can be used with any S3-compatible storage provider.
### Storj S3 Credentials
This step assumes that you have already created an account with
[Storj](https://www.storj.io/).
Follow the
[Storj guide for generating S3 credentials](https://docs.storj.io/dcs/api-reference/s3-compatible-gateway#I7p7Q)
using either the web interface or `uplink`. Make sure that the credentials have
the proper read/write permissions for the bucket that your video files will be
read from and that transcoded videos will be written to. The access key and
secret key of the credentials will be used in the next step.
### Upload Video to Storj
Make sure you have a video file uploaded to your Storj bucket. You must upload
the video file using one of the following methods:
* Via the Storj web interface
* Via the [Storj uplink CLI](https://www.storj.io/integrations/uplink-cli)
* Via a S3 API client
* [AWS has S3 API client implementations](https://aws.amazon.com/developer/tools/)
in different programming languages
* The [code examples](#code-examples) illustrate how to upload a video file to
Storj using a S3 API client
### Transcode with Livepeer
This step assumes that you have already created a
[Livepeer Studio account](https://livepeer.studio/) and an
[API key](/api-reference/overview/authentication).
```javascript theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Livepeer } from "livepeer";
const apiKey = "YOUR_API_KEY";
const livepeer = new Livepeer({ apiKey });
livepeer.transcode.create({
input: {
type: "s3",
endpoint: "https://gateway.storjshare.io",
credentials: {
accessKeyId: "$ACCESS_KEY_ID",
secretAccessKey: "$SECRET_ACCESS_KEY"
},
bucket: "mybucket",
path: "/video/source.mp4"
},
storage: {
type: "s3",
endpoint: "https://gateway.storjshare.io",
credentials: {
accessKeyId: "$ACCESS_KEY_ID",
secretAccessKey: "$SECRET_ACCESS_KEY"
},
bucket: "mybucket"
},
outputs: {
hls: {
path: "/samplevideo/hls"
},
mp4: {
path: "/samplevideo/mp4"
}
},
profiles: [
{
name: "480p",
bitrate: 1000000,
fps: 30,
width: 854,
height: 480
},
{
name: "360p",
bitrate: 500000,
fps: 30,
width: 640,
height: 360
}
]
}).then((video) => {
console.log(video);
}).catch((error) => {
console.error(error);
});
```
```python theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import livepeer
from livepeer.models import components
client = livepeer.Livepeer(
api_key="",
)
params = {
"input": {
"type": "s3",
"endpoint": "https://gateway.storjshare.io",
"credentials": {
"accessKeyId": "$ACCESS_KEY_ID",
"secretAccessKey": "$SECRET_ACCESS_KEY"
},
"bucket": "mybucket",
"path": "/video/source.mp4"
},
"storage": {
"type": "s3",
"endpoint": "https://gateway.storjshare.io",
"credentials": {
"accessKeyId": "$ACCESS_KEY_ID",
"secretAccessKey": "$SECRET_ACCESS_KEY"
},
"bucket": "mybucket"
},
"outputs": {
"hls": {
"path": "/samplevideo/hls"
},
"mp4": {
"path": "/samplevideo/mp4"
}
},
"profiles": [
{
"name": "480p",
"bitrate": 1000000,
"fps": 30,
"width": 854,
"height": 480
},
{
"name": "360p",
"bitrate": 500000,
"fps": 30,
"width": 640,
"height": 360
}
]
}
res = client.transcode.create(request=components.TranscodeRequest(**params))
if res.task is not None:
# handle response
pass
```
```go theme={"theme":{"light":"github-light","dark":"dark-plus"}}
package main
import(
livepeergo "github.com/livepeer/livepeer-go"
"github.com/livepeer/livepeer-go/models/components"
"context"
"log"
)
func main() {
client := livepeergo.New(
livepeergo.WithSecurity(""),
)
params := map[string]interface{}{
"input": map[string]interface{}{
"type": "s3",
"endpoint": "https://gateway.storjshare.io",
"credentials": map[string]string{
"accessKeyId": "$ACCESS_KEY_ID",
"secretAccessKey": "$SECRET_ACCESS_KEY",
},
"bucket": "mybucket",
"path": "/video/source.mp4",
},
"storage": map[string]interface{}{
"type": "s3",
"endpoint": "https://gateway.storjshare.io",
"credentials": map[string]string{
"accessKeyId": "$ACCESS_KEY_ID",
"secretAccessKey": "$SECRET_ACCESS_KEY",
},
"bucket": "mybucket",
},
"outputs": map[string]interface{}{
"hls": map[string]string{
"path": "/samplevideo/hls",
},
"mp4": map[string]string{
"path": "/samplevideo/mp4",
},
},
"profiles": []map[string]interface{}{
{
"name": "480p",
"bitrate": 1000000,
"fps": 30,
"width": 854,
"height": 480,
},
{
"name": "360p",
"bitrate": 500000,
"fps": 30,
"width": 640,
"height": 360,
},
},
}
ctx := context.Background()
res, err := client.Transcode.Create(ctx, request)
if err != nil {
log.Fatal(err)
}
if res.Task != nil {
// handle response
}
}
```
The parameters are defined as:
* `$API_KEY` is your Livepeer Studio API key
* `$ACCESS_KEY_ID` is the access key and `$SECRET_ACCESS_KEY` is the secret key
of the S3 credentials you generated in the previous step
* `input.bucket` is the name of your Storj bucket
* `input.path` is the path that your video file can be found in the Storj bucket
* `outputs.hls.path` is the path that the HLS playlist and mpegts segments is
found in when transcoding is complete
* `outputs.mp4.path` is the path that the MP4 video files is found in when
transcoding is complete
* `profiles` is an optional parameter to specify the desired properties of
transcoded video
Use the task ID in the response to query for the transcoding task status. Once
the task is complete, the HLS playlist and mpegts segments will be available at
`outputs.hls.path`, and MP4 output videos will be available at
`outputs.mp4.path`.
For more information about the transcode API refer to the
[API reference docs](/api-reference/transcode/create).
### Playback From Storj
You can create a public playback URL for the transcoded video by first creating
a shared Storj URL:
* If you are using `uplink`, follow the
[Storj Link Sharing guide](https://docs.storj.io/dcs/api-reference/uplink-cli/share-command/#f-jKX)
to create a URL for your bucket
* Ex.
`uplink share sj://demo-bucket/ --url --not-after=none --base-url=https://link.storjshare.io`
* If you are using the web interface, navigate to your bucket under “Buckets”
and click the “Share Bucket” button to create a URL for your bucket
The URL should look like this:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
https://link.storjshare.io/jwjfgdxkvmfgngsgitii6pny62za/demo-bucket
```
For example, if the `outputs.hls.path` for the request in the previous step was
`/samplevideo/hls`, then the master HLS playlist used for playback will be
available at:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
https://link.storjshare.io/jwjfgdxkvmfgngsgitii6pny62za/demo-bucket
```
You can play back the transcoded video from Storj using this URL with any HLS
player. For example,
`https://lvpr.tv/?url=https://storage.lp-playback.studio/raw/jwjfgdx…/demo-bucket/samplevideo/hls/index.m3u8`
will play back the video using the embeddable Livepeer player.
### Code Examples
* [Nodejs](https://github.com/livepeer/storj-livepeer-nodejs-example)
# Transcode with W3S
Source: https://docs.livepeer.org/v1/developers/guides/transcode-video-w3s
This guide will describe how to use the Livepeer
[transcode API](/api-reference/transcode/create) to transcode and store video
files in [web3.storage](http://web3.storage).
The playback of long videos (longer than 1h) stored in Web3 Storage can be
slow due to the W3 Link issue tracked
[here](https://github.com/web3-storage/w3link/issues/46).
Also, there are [code examples](#code-examples) provided for reference.
### UCAN Proof
This step assumes that you have [w3 CLI](https://github.com/web3-storage/w3cli)
installed. Follow the
[Getting Started](https://github.com/web3-storage/w3cli#getting-started)
instructions to create new space for storing data and register the space.
Get Livepeer Studio DID.
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl https://livepeer.studio/api/did
```
The response should contain the Livepeer Studio DID.
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"did": "did:key:z6Mkn1f6JUmxJi8Ht53SzeK3LSWNn9DRPsSfFLoPJWHVTCaX"
}
```
Create a UCAN delegation.
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
w3 delegation create | base64
```
This returns the base64-encoded delegation proof which authorizes the Livepeer
Studio DID to store data to your space. Note that the proof should not contain
any whitespaces.
### Upload Video to web3.storage
Make sure you have a video file uploaded to web3.storage. You can do upload a
file using the `w3 up` command by following
[these instructions](https://github.com/web3-storage/w3cli#w3-up-path-path).
### Transcode with Livepeer
This step assumes that you have already created a
[Livepeer Studio account](https://livepeer.studio/) and an
[API key](/api-reference/overview/authentication).
Submit the following request:
```javascript theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Livepeer } from "livepeer";
const apiKey = "YOUR_API_KEY"
const livepeer = new Livepeer({apiKey});
livepeer.transcode({
input: {
url: "$INPUT_VIDEO_URL",
},
storage: {
type: "web3.storage",
credentials: {
proof: "$DELEGATION_PROOF",
},
},
outputs: {
hls: {
path: "/",
},
mp4: {
path: "/",
},
},
profiles: [
{
name: "480p",
bitrate: 1000000,
fps: 30,
width: 854,
height: 480,
},
{
name: "360p",
bitrate: 500000,
fps: 30,
width: 640,
height: 360,
},
],
}).then((video) => {
console.log(video);
}).catch((error) => {
console.error(error);
});
```
```python theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import livepeer
from livepeer.models import components
client = livepeer.Livepeer(
api_key="",
)
params = {
"input": {
"url": "$INPUT_VIDEO_URL"
},
"storage": {
"type": "web3.storage",
"credentials": {
"proof": "$DELEGATION_PROOF"
}
},
"outputs": {
"hls": {
"path": "/"
},
"mp4": {
"path": "/"
}
},
"profiles": [
{
"name": "480p",
"bitrate": 1000000,
"fps": 30,
"width": 854,
"height": 480
},
{
"name": "360p",
"bitrate": 500000,
"fps": 30,
"width": 640,
"height": 360
}
]
}
res = s.transcode.create(request=components.TranscodeRequest(**params))
if res.task is not None:
# handle response
pass
```
```go theme={"theme":{"light":"github-light","dark":"dark-plus"}}
package main
import(
livepeergo "github.com/livepeer/livepeer-go"
"github.com/livepeer/livepeer-go/models/components"
"context"
"log"
)
func main() {
client := livepeergo.New(
livepeergo.WithSecurity(""),
)
params := map[string]interface{}{
"input": map[string]string{
"url": "$INPUT_VIDEO_URL",
},
"storage": map[string]interface{}{
"type": "web3.storage",
"credentials": map[string]string{
"proof": "$DELEGATION_PROOF",
},
},
"outputs": map[string]map[string]string{
"hls": {
"path": "/",
},
"mp4": {
"path": "/",
},
},
"profiles": []map[string]interface{}{
{
"name": "480p",
"bitrate": 1000000,
"fps": 30,
"width": 854,
"height": 480,
},
{
"name": "360p",
"bitrate": 500000,
"fps": 30,
"width": 640,
"height": 360,
},
},
}
ctx := context.Background()
res, err := client.Transcode.Create(ctx, params)
if err != nil {
log.Fatal(err)
}
if res.Task != nil {
// handle response
}
}
```
The parameters are defined as:
* `$API_KEY` is your Livepeer Studio API key
* `$DELEGATION_PROOF` is the delegation proof you created using `w3`
* `input.url` is the URL of the video you would like to transcode
* `outputs.hls.path` is the relative path that the HLS playlist and mpegts
segments is found in when transcoding is complete
* `outputs.mp4.path` is the path that the MP4 video files is found in when
transcoding is complete
* `profiles` is an optional parameter to specify the desired properties of
transcoded video
Use the task ID in the response to query for the transcoding task status. Once
the task is complete, you’ll see the output directory IPFS URL in the
`/api/task` response in the `output.transcodeFile.baseUrl` field.
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"id": "...",
"type": "transcode-file",
"output": {
"transcodeFile": {
"baseUrl": "ipfs://bafybeiakkypfc7uzk6jnk6pg3f2fwumkahrmgbii7cigyyc7oejjo3ff4e",
"hls": {
"path": "/index.m3u8"
},
"mp4": [
{ "path": "/static360p0.mp4" },
{ "path": "/static720p0.mp4" },
{ "path": "/static1080p0.mp4" }
]
}
},
...
}
```
For more information about transcode API usage refer to the
[API reference docs](/api-reference/transcode/create).
### Code Examples
* [Nodejs](https://github.com/livepeer/web3storage-livepeer-nodejs-example)
# Upload an asset
Source: https://docs.livepeer.org/v1/developers/guides/upload-video-asset
Learn how to upload and play back an asset
Uploading and watching an asset is easy! The example below uses the
[Create Asset API](/api-reference/asset/upload) to create an upload URL to
upload a video.
Livepeer supports resumable uploads through the TUS protocol, which helps with
reliability and efficiency when transferring large assets. **This is the
recommended approach for uploading media files.**
Livepeer provides two options for uploading assets:
* **TUS Resumable Upload (recommended for all use-cases)**: TUS uploads ensure
reliability and efficiency when transferring media files. It is recommended
for all use-cases, as it is compatible with all modern browsers and supports
resuming uploads.
* **`PUT` Upload**: Upload assets via simple HTTP verbs for processing and play
back.
## Using Livepeer's SDKs
We can use one of the Livepeer SDKs to create a
[TUS-compatible](https://github.com/TUS/TUS-js-client) upload endpoint.
We can then use TUS on the frontend to directly upload the asset to Livepeer.
```javascript theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Livepeer } from "livepeer";
const apiKey = 'YOUR_API_KEY';
const fileName = 'filename.mp4';
const livepeer = new Livepeer({apiKey});
const assetData = {
name: fileName
};
livepeer
.asset.create(assetData)
.then((response) => {
console.log("Asset upload request:", response);
})
.catch((error) => {
console.error("Error requesting asset upload:", error);
});
// pass the TUS endpoint to the frontend and use TUS to upload
// https://github.com/TUS/TUS-js-client
```
```python theme={"theme":{"light":"github-light","dark":"dark-plus"}}
from livepeer import Livepeer
# Initialize the Livepeer client with your API key
api_key = "YOUR_API_KEY"
livepeer = Livepeer(api_key)
file_name = "filename.mp4" # Replace with the desired file name
asset_data = {
"name": file_name
}
try:
# Request asset upload
response = livepeer.asset.create(asset_data)
print("Asset upload request:", response)
except Exception as e:
print("Error requesting asset upload:", e)
# pass the TUS endpoint to the frontend and use TUS to upload
# https://github.com/TUS/TUS-js-client
```
```go theme={"theme":{"light":"github-light","dark":"dark-plus"}}
package main
import(
livepeergo "github.com/livepeer/livepeer-go"
"github.com/livepeer/livepeer-go/models/components"
"context"
"log"
)
func main() {
// Initialize the Livepeer client with your API key
client := livepeergo.New(
livepeergo.WithSecurity(""),
)
request := components.NewAssetPayload{
Name: "filename.mp4", // Replace with the desired file name
}
ctx := context.Background()
res, err := client.Asset.Create(ctx, request)
if err != nil {
log.Fatal(err)
}
if res.Data != nil {
// handle response
}
// pass the TUS endpoint to the frontend and use TUS to upload
// https://github.com/TUS/TUS-js-client
```
Once an upload endpoint is created, you can use it to upload your video file to
Livepeer. The upload endpoint is TUS compatible, so you can use any
TUS-compatible client (like
[TUS-js-client](https://github.com/TUS/TUS-js-client)) to upload your video file
from the frontend.
**For rapid processing of assets that will also be archived on IPFS or
Arweave, we strongly encourage either (1) uploading to Livepeer with the [IPFS
storage option
enabled](/developers/tutorials/upload-playback-videos-on-ipfs#uploading-videos-to-ipfs),
or (2) uploading the raw file to the API prior to archiving on dStorage,
rather than passing the IPFS / Arweave gateway URL. The gateway URL will work,
but may incur longer-than-usual processing time.**
### IPFS and Arweave sources
IPFS is a network of nodes that allow you to read content from the network
using a content identifier unique to the data you’re requesting, ensuring you
are able to verifiably get exactly what you are asking for, regardless of
where the data is physically stored. Arweave is a set of nodes that are
incentivized to store data permanently; content stored on the network is
pulled through an Arweave gateway.
### Play an asset
To learn how to play an asset, see the
[Play an Asset](/developers/guides/playback-an-asset) guide.
# Introduction
Source: https://docs.livepeer.org/v1/developers/introduction
Explore APIs, guides, and examples
If you're looking for documentation on Livepeer's hosted realtime
StreamDiffusion AI platform "Daydream", please navigate
[here](https://pipelines.livepeer.org/docs)
Learn how to add live and on-demand video experience to your app using Livepeer
Studio. Effortlessly manage livestreams, video uploads, API keys, network usage,
billing, and more.
Get started with Livepeer Studio in less than 5 minutes.
Learn how to add live or on-demand video experiences to your app.
Explore the Livepeer Studio API
Get up and running with SDKs and pre-built UI components
## Explore the Livepeer Studio SDKs
Explore developer SDKs, pre-built UI components, and tools for interacting with
the Livepeer Studio API.
### Server-side SDKs
### React Components
Fully customizable video player component for seamless playback
Full-featured broadcast component with controls, settings, and device
selection
[View all developer tools](/sdks/introduction)
# CLI
Source: https://docs.livepeer.org/v1/developers/livepeer-studio-cli
Generate a new Livepeer app.
The Livepeer Studio CLI is a command line tool that helps you generate a new
Livepeer app in just a few seconds.
## Getting Started
First, create a Livepeer API key
[here](https://livepeer.studio/dashboard/developers/api-keys). Next, use the CLI
to generate a new project.
```sh theme={"theme":{"light":"github-light","dark":"dark-plus"}}
npx @livepeer/create
```
When prompted, enter your Livepeer **API key** and **Stream ID**.
Once the app has been created, `cd` into the new directory and run the start
command:
```sh theme={"theme":{"light":"github-light","dark":"dark-plus"}}
npm run dev
```
# Quickstart
Source: https://docs.livepeer.org/v1/developers/quick-start
Learn how to create an API key and start adding live and on-demand video to your app or website!
First, go to [Livepeer Studio](https://livepeer.studio), if you haven't already,
and create an account. Once you've created an account, you'll be able to create
an API key by clicking on the "Create API Key" button on Developers page.
We do not recommend using ["CORS-enabled" API
keys](/api-reference/overview/authentication) - they will be deprecated in an
upcoming release. We recommend making requests from your backend to the
Livepeer Studio API.
You can now use this API key in Livepeer SDKs and APIs in order to authenticate
your requests and start building.
We recommend creating separate accounts for your development and production
environments. This will allow you to easily isolate your environments. We will
be shipping a solution for multi-environment management soon.
In this exampe, we will use Javascript anld React to upload a video. Make sure
to set up a React app first.
## Install the JS SDK and Livepeer React
We install both the NodeJS SDK (which works in all JS environments with `fetch`)
and the Livepeer React library, which provides composable React primitives for
building video apps.
```
npm install livepeer @livepeer/react
```
## Set up the SDK
Add an API key to the environment variables, and construct a new Livepeer SDK
client.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import Livepeer from "livepeer";
const livepeer = new Livepeer({
apiKey: process.env.YOUR_PRIVATE_API_KEY,
});
```
## Retrieve playback info
We can now use the SDK on the backend to fetch the playback info for our asset.
This asset was uploaded using the dashboard, but this can also be an asset
created from an application.
```ts theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { getSrc } from "@livepeer/react/external";
const playbackId = "f5eese9wwl88k4g8";
export const getPlaybackSource = () => {
const playbackInfo = await livepeer.playback.get(playbackId);
const src = getSrc(playbackInfo.playbackInfo);
return src;
};
```
## Play the asset
We can now use Player component from the SDK to play a video. In the below
example, we style the elements with Tailwind, but you can use any styling
solution:
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { PauseIcon, PlayIcon } from "@livepeer/react/assets";
import { getSrc } from "@livepeer/react/external";
import * as Player from "@livepeer/react/player";
import { vodSource } from "./source";
export const DemoPlayer = ({ src }: { src: Src[] | null }) => {
return (
);
};
```
## Start building
Check out the [SDKs](/sdks/introduction) and
[API Reference](/api-reference/overview/introduction) pages to learn more about
how to use the SDKs and API to build your application.
You can also refer to the [Guides](/developers/guides/overview) section for more
in-depth tutorials on how to use the SDKs and API to build specific
applications.
Don't know where to start? Check out these four tutorials:
* [Learn how to create a livestream](/developers/guides/create-livestream)
* [Learn how to listen to asset events](/developers/guides/listen-to-asset-events)
# Youtube clone with FVM
Source: https://docs.livepeer.org/v1/developers/tutorials/decentralized-app-with-fvm
Learn how to Build a decentralized video application with FVM and Livepeer
This tutorial is based on Livepeer React version 3.9 or earlier, which is now
deprecated. Please ensure that you use Livepeer React version 4 or later, with
the new Livepeer JavaScript SDK. The integration process may appear different,
but the underlying concepts remain same.
The Filecoin Virtual Machine (FVM) is a runtime environment designed for
executing smart contracts on the Filecoin network. It enables developers to
write and deploy custom code on Filecoin blockchain unleashing the ability to
write software that automates the storage, retrieval, and ultimately the
transformation of data in a Web3-native way. This allows for decentralized
applications to provide permanent storage guarantees for user content through
smart contracts that store video data securely on Filecoin. FVM allows
developers to write smart contracts on the Filecoin blockchain to automate
storage, retrieval, and transformation of data.
For end-users, Web3 apps provide greater security, privacy, and control over
their data. By leveraging the power of blockchain technology, users can be sure
that their data is stored in a tamper-proof and decentralized manner, which
means that no single entity has complete control over their data. This provides
greater protection against data breaches, hacks, and other security threats.
When combined with Livepeer, developers can build decentralized video
applications, archive videos, create video NFTs, and more. In this tutorial, you
will learn how to build a decentralized video application with FVM and Livepeer.
## Prerequisites
Before you start with this tutorial, make sure you have the following tool
installed on your machine:
* [Node.js](https://nodejs.org/en/) v16 or later
* [Metamask](https://metamask.io/download/) extension
In addition to the above tools, this tutorial assumes that you have a basic
understanding of Solidity and Next.js
## Setting up Next.js App
First, create a directory for the project and then initialize a Next.js app
using the following command in your terminal:
```
npx create-next-app .
```
This will create a new Next.js app in the current directory and install all the
necessary dependencies. Once the project is created successfully, run the
following command to install a few other dependencies.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
npm install @livepeer/react lighthouse-web3/sdk react-icons ethers moment
```
### Adding TailwindCSS
Tailwind CSS is a utility-first CSS framework that enables you to rapidly build
user interfaces. We will use it to style our app. First, we need to install the
`tailwindcss`, `postcss`, and `autoprefixer`dependencies. These dependencies are
necessary for TailwindCSS to work properly in a Next.js app.
Run the following command to install them:
```
npm install --dev tailwindcss postcss autoprefixer
```
Once the dependencies are installed, we need to initiate the Tailwind CSS. This
will create the necessary configuration files and allow you to customize the
default Tailwind CSS styles. To do that, run the below code in your terminal.
```
npx tailwind init -p
```
The above command will generate two files named `tailwind.config.js` and
`postcss.config.js`. These files contain the configuration for Tailwind CSS and
PostCSS, respectively. Next, open the `tailwind.config.js` file in code editor
of your choice and replace its contents with the following code:
```
module.exports = {
content: [
"./pages//*.{js,ts,jsx,tsx}",
"./components//*.{js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}
```
The above code tells Tailwind CSS which files to process. At last, add the
tailwind directives for each of Tailwind’s layers to the `./styles/globals.css`
file.
```
@tailwind base;
@tailwind components;
@tailwind utilities;
```
## The smart contract
Now that the project setup is completed, we can start writing smart contracts
for our application. In this article, I will be using Solidity.
> A smart contract is a decentralized program that responds to events by
> executing business logic.
To quickly create and deploy a contract, you can use Remix - a browser-based IDE
developed by the Ethereum Foundation. Here's how you can get started:
* Open your web browser and go to
[remix.ethereum.org](https://remix.ethereum.org/).
* Create a new workspace by selecting Blank.
* Copy and paste the below contract code into the editor.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;
contract YouTube {
// Declaring the videoCount 0 by default
uint256 public videoCount = 0;
// Name of your contract
string public name = "YouTube";
// Creating a mapping of videoCount to Video
mapping(uint256 => Video) public videos;
// Create a struct called 'Video' with the following properties:
struct Video {
uint256 id;
string hash;
string title;
string description;
string location;
string category;
string thumbnailHash;
string date;
address author;
}
// Create a 'VideoUploaded' event that emits the properties of the video
event VideoUploaded(
uint256 id,
string hash,
string title,
string description,
string location,
string category,
string thumbnailHash,
string date,
address author
);
constructor() {}
// Function to upload a video
function uploadVideo(
string memory _videoHash,
string memory _title,
string memory _description,
string memory _location,
string memory _category,
string memory _thumbnailHash,
string memory _date
) public {
// Validating the video hash, title and author's address
require(bytes(_videoHash).length > 0);
require(bytes(_title).length > 0);
require(msg.sender != address(0));
// Incrementing the video count
videoCount++;
// Adding the video to the contract
videos[videoCount] = Video(
videoCount,
_videoHash,
_title,
_description,
_location,
_category,
_thumbnailHash,
_date,
msg.sender
);
// Triggering the event
emit VideoUploaded(
videoCount,
_videoHash,
_title,
_description,
_location,
_category,
_thumbnailHash,
_date,
msg.sender
);
}
}
```
* Switch to the Deploy tab.
* [Add Hyperspace testnet](https://docs.filecoin.io/developers/smart-contracts/how-tos/add-to-metamask/)
to your Metamask account and choose your network from the Environment tab.
* If everything goes well, you should see a success message at the bottom of the
IDE window along with your contract address.
* To download the artifacts folder from Remix, click on the backup folder and
look for the folder inside the `.workspace` directory.
## The Frontend
Now that we have completed smart contracts, it is time to work on the front end
of the application. Let’s start with the Authentication of the app.
### Authentication
The first step is to set up authentication in our app that allows users to
connect their wallets. Create a new folder named `landing` inside of the pages
folder and create a new file inside of it named index.js. This file will have
the code for the landing page in our application, which will also allow users to
connect their wallets.
Erase everything inside of `index.js` in the page directory and inside import
the `Landing` file to the file. Here is what your index.js file should look
like.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import React from "react";
import Landing from "./landing";
export default function index() {
return ;
}
```
Now, on the landing page, we will create a simple hero component with connect
wallet button that will allow users to connect their wallets and access our
application.
Add the below code to the landing page. I have already added comments so you can
understand them properly.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import React, { useState } from "react";
function Landing() {
// Creating a function to connect user's wallet
const connectWallet = async () => {
try {
const { ethereum } = window;
// Checking if user have Metamask installed
if (!ethereum) {
// If user doesn't have Metamask installed, throw an error
alert("Please install MetaMask");
return;
}
// If user has Metamask installed, connect to the user's wallet
const accounts = await ethereum.request({
method: "eth_requestAccounts",
});
// At last save the user's wallet address in browser's local storage
localStorage.setItem("walletAddress", accounts[0]);
} catch (error) {
console.log(error);
}
};
return (
<>
{/* Creating a hero component with black background and centering everything in the screen */}
It is YouTube, but{" "}
Decentralized
A YouTube Clone built on top of FVM, allow users to create,
share and watch videos, without worrying about their privacy.
>
);
}
export default Landing;
```
If everything goes fine you should see a similar screen. You should also be able
to connect your MetaMask wallet.

### Uploading videos
Now that users are able to connect their wallets, it is time to add upload video
functionality to our app.
Create a new folder in the pages directory named `upload` and add a file named
`index.js`. Inside the file add the below code.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import React, { useState, useRef } from "react";
import { BiCloud, BiMusic, BiPlus } from "react-icons/bi";
export default function Upload() {
// Creating state for the input field
const [title, setTitle] = useState("");
const [description, setDescription] = useState("");
const [category, setCategory] = useState("");
const [location, setLocation] = useState("");
const [thumbnail, setThumbnail] = useState("");
const [video, setVideo] = useState("");
// Creating a ref for thumbnail and video
const thumbnailRef = useRef();
const videoRef = useRef();
return (
setTitle(e.target.value)}
placeholder="Rick Astley - Never Gonna Give You Up (Official Music Video)"
className="w-[90%] text-white placeholder:text-gray-600 rounded-md mt-2 h-12 p-2 border bg-[#1a1c1f] border-[#444752] focus:outline-none"
/>
);
}
```
And you should see a similar screen if you navigate to
[http://localhost:3000/upload](http://localhost:3000/upload).

This is a basic upload page, for now, we just have the inputs and save their value
of them in the state.
Before working on the handle submit function, create a new folder named `utils`,
and inside of it create a file named `getContract`. This file will be used to
interact with your contract on the upload page. Add the below code to it and
make sure to replace the contract address and artifacts.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import ContractAbi from "../artifacts/contracts/YouTube.sol/YouTube.json";
import { ethers } from "ethers";
export default function getContract() {
// Creating a new provider
const provider = new ethers.providers.Web3Provider(window.ethereum);
// Getting the signer
const signer = provider.getSigner();
// Creating a new contract factory with the signer, address and ABI
let contract = new ethers.Contract(
"YOUR_CONTRACT_ADDRESS",
ContractAbi.abi,
signer
);
// Returning the contract
return contract;
}
```
### Integrating IPFS (Web3 Storage)
Now we need an IPFS client to upload thumbnails. There are many services that
offer IPFS service, but for this tutorial, we will use
[lighthouse.storage](https://www.lighthouse.storage/).
Create a new account in lighthouse.storage and then navigate to the API Key
page. Create a new token and copy the generated token as we will need it later.
Next, we need to integrate Livepeer in order to upload the videos and serve them
through Livepeer CDN.
### Integrating Livepeer
Livepeer is a decentralized video processing network and developer platform
which you can use to build video applications. It is very fast, easy to
integrate, and cheap. In this tutorial, we will be using Livepeer to upload
videos and serve it.
Navigate to [https://livepeer.studio/register](https://livepeer.studio/register)
and create a new account on Livepeer Studio.
Once you have created an account, in the dashboard, click on the Developers on
the sidebar.
Then, click on Create API Key, give a name to your key and then copy it as we
will need it later.
Now back to the code, create a new file inside of the root directory named
`livepeer.js` and add the below code to initialize a React client.
```
import { createReactClient, studioProvider } from "@livepeer/react";
const LivepeerClient = createReactClient({
provider: studioProvider({ apiKey: "YOUR_API_KEY" }),
});
export default LivepeerClient;
```
Make sure to replace the `YOUR_API_KEY` with the key which you just copied from
the Livepeer dashboard. And also replace the code inside of `_app.js` in the
page directory with the below code.
```
import "../styles/globals.css";
import { LivepeerConfig } from "@livepeer/react";
import LivepeerClient from "../livepeer";
function MyApp({ Component, pageProps }) {
return (
);
}
export default MyApp;
```
And that is it, you can now use Livepeer to upload assets/videos.
Back to the upload page, add the following functions to the `upload.js`.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const goBack = () => {
window.history.back();
};
const uploadToLighthouse = async (e, type) => {
setIsUploading(true);
const output = await lighthouse.upload(
e,
process.env.NEXT_PUBLIC_LIGHTHOUSE_KEY
);
let cid = output.data.Hash;
if (type == "thumbnail") {
setThumbnail(cid);
} else {
setVideo(cid);
}
setIsUploading(false);
};
const handleSubmit = async () => {
let data = {
video,
title,
description,
location,
category,
thumbnail,
UploadedDate: Date.now(),
};
await saveVideo(data);
};
const saveVideo = async (data) => {
let contract = await getContract();
await contract.uploadVideo(
data.video,
data.title,
data.description,
data.location,
data.category,
data.thumbnail,
false,
data.UploadedDate
);
};
```
Finally, this is how your code should look like:
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import React, { useState, useEffect, useRef } from "react";
import { Sidebar, Header } from "../../layout";
import { BiCloud, BiPlus } from "react-icons/bi";
import { getContract } from "../../utils";
import lighthouse from "@lighthouse-web3/sdk";
export default function Upload() {
const [title, setTitle] = useState("");
const [description, setDescription] = useState("");
const [category, setCategory] = useState("");
const [location, setLocation] = useState("");
const [thumbnail, setThumbnail] = useState();
const [video, setVideo] = useState("");
const [isUploading, setIsUploading] = useState();
const thumbnailRef = useRef(null);
const goBack = () => {
window.history.back();
};
const uploadToLighthouse = async (e, type) => {
setIsUploading(true);
const output = await lighthouse.upload(
e,
process.env.NEXT_PUBLIC_LIGHTHOUSE_KEY
);
let cid = output.data.Hash;
if (type == "thumbnail") {
setThumbnail(cid);
} else {
setVideo(cid);
}
setIsUploading(false);
};
const handleSubmit = async () => {
let data = {
video,
title,
description,
location,
category,
thumbnail,
UploadedDate: Date.now(),
};
await saveVideo(data);
};
const saveVideo = async (data) => {
let contract = await getContract();
await contract.uploadVideo(
data.video,
data.title,
data.description,
data.location,
data.category,
data.thumbnail,
false,
data.UploadedDate
);
};
return (
setTitle(e.target.value)}
placeholder="Rick Astley - Never Gonna Give You Up (Official Music Video)"
className="w-[90%] text-white placeholder:text-gray-600 rounded-md mt-2 h-12 p-2 border bg-[#1a1c1f] border-[#444752] focus:outline-none"
/>
);
}
```
Save the file and we are done with the upload functionality. You should now be
able to upload videos to the contract.

### Fetching videos from Blockchain
Create a new file named `index.js` inside of a new folder named `home`. And for
now you can add the below code to the file.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import React, { useEffect, useState } from "react";
import { useApolloClient, gql } from "@apollo/client";
export default function Main() {
// Creating a state to store the uploaded video
const [videos, setVideos] = useState([]);
// Function to get the videos from contract
const getVideos = async () => {
// Get the videos from the contract
let contract = await getContract();
let videosCount = await contract.videoCount();
console.log(String(videosCount));
let videos = [];
for (var i = videosCount; i >= 1; i--) {
let video = await contract.videos(i);
videos.push(video);
}
setVideos(videos);
};
useEffect(() => {
// Runs the function getVideos when the component is mounted
getVideos();
}, []);
return (
{videos.map((video) => (
{video.title}
))}
);
}
```
Save the file and you should see a similar output.

As you can see for now we are just fetching the video title. So let's create a
reusable component to display the videos nicely.
> Make sure to upload a few videos so you can see the above output
Create a folder named `components`, and then create a new file named `Video.js`
inside of it. Add the below code to the file. It is a very basic video
component.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import React from "react";
import { BiCheck } from "react-icons/bi";
import moment from "moment";
export default function Video({ horizontal, video }) {
return (
);
}
```
Import the Video component to the home file and replace the map function with
the below code.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
videos.map((video) => (
{
// Navigation to the video screen (which we will create later)
window.location.href = `/video?id=${video.id}`;
}}
>
));
}
```
Save the file and now you should see a nice-looking homepage, similar to below
image.

### Video page
Now that we are able to fetch the videos on the home screen. Let's work on the
video page where the user will be redirected if they click on any video
component.
Create a new file in the components folder named `Player` and add the below code
to it. We are using Livepeer player to create a video player component.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import React from "react";
import { useAsset, Player } from "@livepeer/react";
interface PlayerProps {
id: any;
}
const VideoPlayer: React.FC = ({ id }) => {
return (
);
};
export default VideoPlayer;
```
Create another file in the same directory named `VideoContainer`. Imagine this
component as the left side of the youtube video page, which contains a player,
video title, upload date, and description. Add the below code to the file.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import React from "react";
import Player from "./Player";
export default function VideoComponent({ video }) {
return (
);
}
```
At last, create a new folder named video inside of the `pages` directory and
create a new file `index.js` of it. For now, you can add the following code to
the file.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useRouter } from "next/router";
import { Header, Sidebar } from "../../layout";
import React, { useEffect, useState } from "react";
import { Background, Player, Video as RelatedVideos } from "../../components";
import lighthouse from "@lighthouse-web3/sdk";
import Link from "next/link";
import moment from "moment";
import { BiCheck } from "react-icons/bi";
import Avvvatars from "avvvatars-react";
import { IVideo } from "../../types";
import { getContract } from "../../utils";
export default function Video() {
const router = useRouter();
const { id } = router.query;
const [video, setVideo] = useState(null);
const [relatedVideos, setRelatedVideos] = useState([]);
const fetchVideos = async () => {
if (id) {
let contract = await getContract();
let video = await contract.videos(id);
let videosCount = await contract.videoCount();
let videos = [];
for (var i = videosCount; i >= 1; i--) {
let video = await contract.videos(i);
videos.push(video);
}
setRelatedVideos(videos);
setVideo(video);
}
};
useEffect(() => {
fetchVideos();
}, [id]);
return (
{video && (
{video.title}
{video.category}
{video.author.slice(0, 13)}...{" "}
Video by {video.author}
{video.description}
Related Videos
{relatedVideos.map((video) => (
))}
)}
);
}
```
Save the file and click on any videos on the home screen. You should be
redirected to the video screen similar to the below page.

That is it for this tutorial, visit
[FVM](https://docs.filecoin.io/developers/smart-contracts/filecoin-virtual-machine/)
docs to learn more about its capabilities
# Token gate videos with Lit
Source: https://docs.livepeer.org/v1/developers/tutorials/token-gate-videos-with-lit
Learn how to token gate videos using Livepeer and Lit: A step-by-step tutorial
This tutorial is based on Livepeer React version 3.9 or earlier, which is now
deprecated. Please ensure that you use Livepeer React version 4 or later, with
the new Livepeer JavaScript SDK. The integration process may appear different,
but the underlying concepts remain same.
Token gating is a method of restricting access to videos based on ownership of a
specific type of token or cryptocurrency. It can be used to restrict access to
certain videos to those who hold a specific type of token, such as an NFT
(non-fungible token). One of the primary benefits of token gating is that it
allows creators to monetise their content more effectively. It can also provide
creators with more control over their content and its distribution. By
restricting access to certain videos to those who hold a specific token,
creators can ensure that their content is only being viewed by those who have a
genuine interest in it.
Lit Protocol is a decentralised key management network powered by threshold
cryptography. A blockchain-agnostic middleware layer, Lit can be used to read
and write data between blockchains and off-chain platforms, powering conditional
decryption and programmatic signing.
When combined with Livepeer, developers can build token-gated video applications
and allow creators to token-gate their video with specific tokens, NFTs,
addresses, etc. In this tutorial, you will learn how to build a token-gated
video application with Lit and Livepeer.
Here is a high-level workflow diagram of how Livepeer’s access control feature
works and how we will use it in our app:
## Prerequisites
Before you start with this tutorial, make sure you have the following tool
installed on your machine:
* Latest [Node.js](https://nodejs.org/en/) version
* An Ethereum wallet such as Metamask or Rainbow
In addition to the above tools, this tutorial assumes that you have a basic
understanding of Next.js
## Setting up Next.js App
First, create a directory for the project and then initialize a Next.js app
using the following command in your terminal:
```
npx create-next-app .
```
This will create a new Next.js app in the current directory and install all the
necessary dependencies.
> While creating a Next.js application, you will be prompted if you would want
> to use Tailwind. In this tutorial, we will be using Tailwind, so make sure to
> set up a Next.js app with Tailwind.
Once the project is created successfully, run the following command to install a
few other dependencies.
```
npm install @livepeer/react @lit-protocol/sdk-nodejs @rainbow-me/rainbowkit ethers lit-js-sdklit-share-modal-v3 nanoid wagmi next-transpile-modules
```
## Setting up Clients
In this tutorial, we will be using different packages and SDKs which means we
have to set up the context and clients for each of them. Let’s start with
RainbowKit and WAGMI
### RainbowKit and WAGMI
For this tutorial, we will be using Rainbow Kit and WAGMI to handle
authentication such as connecting the wallet and signing message.
First, inside of `_app.js` import the following from Rainbow and WAGMI.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import "@rainbow-me/rainbowkit/styles.css";
import { getDefaultWallets, RainbowKitProvider } from "@rainbow-me/rainbowkit";
import { configureChains, createClient, WagmiConfig } from "wagmi";
import { mainnet } from "wagmi/chains";
import { publicProvider } from "wagmi/providers/public";
```
Then, configure your desired chains (in this tutorial, we will be using Ethereum
mainnet) and generate the required connectors. You will also need to set up a
WAGMI client.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// ... import { alchemyProvider } from 'wagmi/providers/alchemy';
// ... import { publicProvider } from 'wagmi/providers/public';
const { chains, provider } = configureChains([mainnet], [publicProvider()]);
const { connectors } = getDefaultWallets({
appName: "My Awesome App",
chains,
});
const wagmiClient = createClient({
autoConnect: true,
connectors,
provider,
});
```
Finally, wrap your application with `RainbowKitProvider` and `WagmiConfig`
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const App = () => {
return (
);
};
```
### Livepeer
Livepeer is a decentralized video infrastructure protocol that allows users to
upload, transcode, and serve video content. The Livepeer React SDK provides a
set of ready-to-use hooks that make it easy to integrate Livepeer into a
project.
To get started, navigate to
[](https://livepeer.studio/register)[https://livepeer.studio/register](https://livepeer.studio/register)
and create a new account on Livepeer Studio. This will give you access to your
Livepeer dashboard, where you can manage your account and access your API keys.
Once you have created an account, in the dashboard, click on the Developers on
the sidebar.
Then, click on Create API Key, give a name to your key, and then copy it as we
will need it later.
To use Livepeer React in your project, create a new directory named `client` in
the root directory, and add the following code to `index.js`
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { createReactClient, studioProvider } from "@livepeer/react";
const LivepeerClient = createReactClient({
provider: studioProvider({ apiKey: "YOUR_API_KEY" }),
});
export default LivepeerClient;
```
Make sure to replace the `YOUR_API_KEY` with the key which you just copied from
the Livepeer dashboard. And also replace the code inside of `_app.js` in the
page directory with the below code.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
//... import { publicProvider } from 'wagmi/providers/public';
import { LivepeerConfig } from "@livepeer/react";
import LivepeerClient from "../client";
//... const wagmiClient = createClient({
function MyApp({ Component, pageProps }) {
return (
);
}
export default MyApp;
```
And that is it, you can now use Livepeer to upload and transcode assets.
### Lit Protocol
As mentioned above, we will be using Lit Protocol for token gating/access
control in our application. First, create a new directory named `hooks` and
inside of it, create a new file named `useLit`. This would be the file to handle
the connection with Lit’s node. Add the following code to it:
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import {
createContext,
FunctionComponent,
useContext,
useEffect,
useMemo,
useState,
} from "react";
import LitJsSdk from "lit-js-sdk";
const LitClientContext = createContext({
litNodeClient: null,
litConnected: false,
});
export const LitProvider = ({ children }) => {
const client = useMemo(
() => new LitJsSdk.LitNodeClient({ debug: false }),
[]
);
const [connected, setConnected] = useState(false);
useEffect(() => {
client
.connect()
.then(() => {
{
setConnected(true);
}
})
.catch(() =>
alert(
"Failed connecting to Lit network! Refresh the page to try again."
)
);
}, [client]);
return (
{children}
);
};
export default function useLit() {
return useContext(LitClientContext);
}
```
Here, we have created a provider and a custom hook to manage the connection to a
Lit node client throughout the application. This is useful if you want to share
the same instance of the Lit node client across multiple components in the app.
Next, add the following lit imports to `_app.js` and also wrap the application
with `LitProvider`
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// import LivepeerClient from '../client';
import "lit-share-modal-v3/dist/ShareModal.css";
import { LitProvider } from "../hooks/useLit";
//... const wagmiClient = createClient({
function MyApp({ Component, pageProps }) {
return (
);
}
export default MyApp;
```
## Backend
The first step is to set up a background route that will handle the webhook and
verify the token. Since we are using Next.js, we can simply use the `api`
routes.
### Create a Webhook Handler
The first step is to create an access control webhook handler. We need to set up
an endpoint (e.g.,
[](https://yourdomain.com/api/check-access)[https://yourdomain.com/api/check-access](https://yourdomain.com/api/check-access))
to handle the logic for granting or denying access to your assets. This endpoint
should accept a POST request with a JSON payload containing the access key and
webhook context.
This is an example of a payload this endpoint would receive:
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"accessKey": "your-access-key",
"context": {
"assetId": "abcd1234",
"userId": "user5678"
},
"timestamp": 1680530722502
}
```
In the Next.js `api` directory, create a new file named `verify-lit-jwt.js` and
add the following code to it
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import type { NextApiRequest, NextApiResponse } from "next";
import * as LitJsSdk from "@lit-protocol/lit-node-client-nodejs";
interface Payload {
baseUrl: string;
path: string;
orgId: string;
iat: number;
exp: number;
}
const handler = async (req, res) => {
const { accessKey, webhookContext } = req.body;
const { verified, header, payload } = LitJsSdk.verifyJwt({
jwt,
});
if (!verified) {
res.status(403).json({ message: "Access token is not correct" });
} else if (
webhookContext?.resourceId &&
(webhookContext.resourceId.baseUrl !== payload.baseUrl ||
webhookContext.resourceId.path !== payload.path ||
webhookContext.resourceId.orgId !== payload.orgId)
) {
res.status(403).json({ message: "ResourceId does not match" });
} else {
res.status(200).json({ message: "Success" });
}
};
export default handler;
```
The above code verifies a JWT access token and checks if its payload matches the
webhook context's resource ID. The Lit SDK is used to verify the JWT access
token, which must contain a payload object with `baseUrl`, `path`, `orgId`,
`iat`, and `exp` fields.
If the access token is not verified or if the resource ID does not match, an
HTTP response with a status code of 403 is returned. If everything is fine, the
handler returns an HTTP response with a status code of 200.
Next, deploy your Next.js app to Vercel or any other hosting provider as we will
need a link to the verify JWT API.
### Register an Access Control Webhook
Once you deployed, you can use the Livepeer Studio dashboard to create a new
webhook with the type `playback.accessControl` and specify the URL of your
access control endpoint.
Once created, copy the id of Webhook as we will need it later in the next step.
## Frontend
Now that we have set up the clients and backend, we can move to the front end
and add the upload and access control features to our app.
### Wallet Connection
First, we need to allow users to connect their wallets. Create a new directory
named `components` and inside of it, create a new file named `Connect` and add
the following code to it.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import React from "react";
import { ConnectButton } from "@rainbow-me/rainbowkit";
export default function Navbar() {
return (
);
}
```
It is a simple component that imports ConnectButton from Rainbow which would
handle the authentication.
### Upload page
In the pages directory, we can use `index.jsx` as the upload page, or you can
also create a new file named `upload.jsx` for the upload page. In this tutorial,
we will be using `index.jsx` as the upload page and it will be the index page of
our app.
First import the following in the `index.jsx` file.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import React, { useEffect, useMemo, useRef, useState } from "react";
import useLit from "../../hooks/useLit";
import { nanoid } from "nanoid";
import { useAsset, useCreateAsset } from "@livepeer/react";
import Link from "next/link";
import { useAccount } from "wagmi";
import LitJsSdk from "lit-js-sdk";
import LitShareModal from "lit-share-modal-v3";
```
After that, we have to create a `resourceId` that will be used by Lit for
checking the access control.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
//... import LitShareModal from "lit-share-modal-v3";
const resourceId = {
baseUrl: "my-awesome-app.vercel.app",
path: `/asset/${nanoid()}`,
orgId: "some-app",
role: "",
extraData: `createdAt=${Date.now()}`,
};
```
Next, add the following hooks inside the component. The code contains a few
useStates for managing the state, the lit hook which we created earlier, and
finally the `useAccount` hook that is imported from WAGMI.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// Inputs
const [file, setFile] = useState(undefined);
const fileInputRef = useRef(null);
// Lit
const [showShareModal, setShowShareModal] = useState(false);
const [savedSigningConditionsId, setSavedSigningConditionsId] = useState();
const [authSig, setAuthSig] = useState({});
const { litNodeClient, litConnected } = useLit();
const [litGateParams, setLitGateParams] = useState({
unifiedAccessControlConditions: null,
permanent: false,
chains: [],
authSigTypes: [],
});
// Misc
const { address: publicKey } = useAccount();
```
Next, we need to pre-sign the user’s wallet after it is connected using Lit. To
do that, you can add the following code after the useAccount hook.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
//...const { address: publicKey } = useAccount();
// Step 1: pre-sign the auth message
useEffect(() => {
if (publicKey) {
Promise.resolve().then(async () => {
try {
setAuthSig({
ethereum: await LitJsSdk.checkAndSignAuthMessage({
chain: "ethereum",
switchChain: false,
}),
});
} catch (err: any) {
alert(`Error signing auth message: ${err?.message || err}`);
}
});
}
}, [publicKey]);
```
In the above code, we are checking if the user is connected, if they are, the
app asks to sign the message and then save it to `AuthSign` state.
Next, after signing the message, we can use `useCreateAsset` to upload the video
to Livepeer. In the below code, we also specify the webhook id, which we created
earlier. And `useAsset` hook to check if the asset upload/processing is
completed
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// Step 2: Creating an asset
const {
mutate: createAsset,
data: createdAsset,
status: createStatus,
progress,
} = useCreateAsset(
file
? {
sources: [
{
file: file,
name: file.name,
playbackPolicy: {
type: "webhook",
webhookId: "WEBHOOK_ID",
webhookContext: {
accessControl: litGateParams.unifiedAccessControlConditions,
resourceId: resourceId,
},
},
},
] as const,
}
: null
);
// Step 3: Getting asset and refreshing for the status
const {
data: asset,
error,
status: assetStatus,
} = useAsset({
assetId: createdAsset?.[0].id,
refetchInterval: (asset) =>
asset?.storage?.status?.phase !== "ready" ? 5000 : false,
});
```
You can also add the below code to check the status of the upload.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const progressFormatted = useMemo(
() =>
progress?.[0].phase === "failed" || createStatus === "error"
? "Failed to upload video."
: progress?.[0].phase === "waiting"
? "Waiting"
: progress?.[0].phase === "uploading"
? `Uploading: ${Math.round(progress?.[0]?.progress * 100)}%`
: progress?.[0].phase === "processing"
? `Processing: ${Math.round(progress?.[0].progress * 100)}%`
: null,
[progress, createStatus]
);
const isLoading = useMemo(
() =>
createStatus === "loading" ||
assetStatus === "loading" ||
(asset && asset?.status?.phase !== "ready") ||
(asset?.storage && asset?.storage?.status?.phase !== "ready"),
[asset, assetStatus, createStatus]
);
```
Add the following code that would get called once everything is complete to save
the signing conditions on Lit.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// Step 4: After an asset is created, save the signing condition
useEffect(() => {
if (
createStatus === "success" &&
asset?.id &&
asset?.id !== savedSigningConditionsId
) {
setSavedSigningConditionsId(asset?.id);
// @ts-ignore
const ACConditions = asset?.playbackPolicy.webhookContext.accessControl;
console.log(ACConditions, resourceId);
Promise.resolve().then(async () => {
try {
await litNodeClient.saveSigningCondition({
unifiedAccessControlConditions: ACConditions,
authSig,
resourceId: resourceId,
});
} catch (err: any) {
alert(`Error saving signing condition: ${err?.message || err}`);
}
});
}
}, [litNodeClient, createStatus, savedSigningConditionsId, authSig, asset]);
```
Finally, we can write a function that would call the createAsset to upload the
video.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const handleClick = async () => {
if (!publicKey) {
console.log("Please connect your wallet to continue");
return;
}
if (!file) {
console.log("Please choose a file");
return;
}
if (!litGateParams.unifiedAccessControlConditions) {
console.log("Please choose the access control conditions");
return;
}
createAsset?.();
};
```
Next, in the return function add the following JSX code. It is pretty long, but
I am going to explain it.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
return (
Livepeer x Ethereum x Lit
Token gate your videos on Ethereum with Livepeer.
Token gating is a powerful tool for content creators who want to
monetize their video content. With Livepeer, you can easily create a
gated video that requires users to hold a certain amount of tokens/NFT
in order to access the content.
Livepeer's token
gating feature is easy to use and highly customizable
);
```
The first section contains a banner image and some text that describes the
purpose of token gating on the Livepeer platform. Then we have two input fields.
The first input field allows the user to select a video file to upload. The
second input field allows the user to set access control conditions. Once a user
clicks on the second input, it displays a modal window that allows the user to
customize the access control conditions using the LitShareModal component.
And that is it for the upload page. Save the file and you should see a similar
page:
### Watch Page
For this watch page, you can create a new directory named `watch` inside the
page and then create a new file named `[playbackId].tsx`. This will tell Next.js
to match any link of `/watch/anything` to this page. Next, import the following
into the page.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import React, { useEffect, useState } from "react";
import { useRouter } from "next/router";
import { useAccount } from "wagmi";
import { Player, usePlaybackInfo } from "@livepeer/react";
import useLit from "../../hooks/useLit";
import LitJsSdk from "lit-js-sdk";
```
Then, add the following hooks inside of the page:
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// ... import LitJsSdk from "lit-js-sdk";
export default function Watch() {
const router = useRouter();
const playbackId = router.query.playbackId?.toString();
const { address } = useAccount();
const { litNodeClient, litConnected } = useLit();
const [gatingError, setGatingError] = useState();
const [gateState, setGateState] = useState();
const [jwt, setJwt] = useState("");
```
Next, we would need to fetch the playback info using the playback id. We can do
this very easily using the `usePlaybackInfo` hook from `@livepeer/react`
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// Step 1: Fetch playback URL
const { data: playbackInfo, status: playbackInfoStatus } = usePlaybackInfo({
playbackId,
});
```
Next, we need a function to check whether the users have access. This function
can easily be handled with Lit SDK
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
async function checkLitGate(litNodeClient, playbackPolicy) {
const ethSign = await LitJsSdk.checkAndSignAuthMessage({
chain: "ethereum",
switchChain: false,
});
const jwt = await litNodeClient.getSignedToken({
unifiedAccessControlConditions: playbackPolicy.webhookContext.accessControl,
authSig: { ethereum: ethSign },
resourceId: playbackPolicy.webhookContext.resourceId,
});
console.log(jwt);
setGateState("open");
setJwt(jwt);
return jwt;
}
```
And finally, we can add a `useEffect` function to get playback info and check
Lit access control when the component mounts.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// Step 2: Check Lit signing condition and obtain playback cookie
useEffect(() => {
if (playbackInfoStatus !== "success" || !playbackId) return;
const { playbackPolicy } = playbackInfo?.meta ?? {};
setGateState("checking");
setTimeout(() => {
checkLitGate(litNodeClient, playbackPolicy)
.then(() => {
console.log("open");
})
.catch((err: any) => {
setGateState("closed");
});
}, 1000);
}, [address, playbackInfoStatus, playbackInfo, playbackId, litNodeClient]);
```
And that is it. We can add the following code to the return function to render
the player if the JWT is valid, otherwise show a message that the user doesn’t
have access.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
return (
<>
Asset Token Gating with Lit Signing Conditions
Prove your identity to access the gated content.
{jwt && (
)}
{gateState == "checking" && (
Checking, please wait...
)}
{gateState == "closed" && (
Sorry, you do not have access to this content
)}
>
);
```
And that is it. Save the file. Now try uploading a video and then once it is
uploading come to the watch screen and check if you have access to it. Here is a
short video of the whole flow:
## Token gate multiple assets with the same ACL condition
If you want to token gate multiple assets with the same access control
conditions, then you can simply get unified access control conditions from the
Lit SDK and the same resources Id and then send the same info to as many assets
as would like to token gate.
The access controls conditions and resource id should be inside of the Webhook
Context.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const {
mutate: createAsset,
data: createdAsset,
status: createStatus,
progress,
} = useCreateAsset(
file
? {
sources: [
{
file: file,
name: file.name,
playbackPolicy: {
type: "webhook",
webhookId: "WEBHOOK_ID",
webhookContext: {
accessControl: litGateParams.unifiedAccessControlConditions,
resourceId: resourceId,
},
},
},
] as const,
}
: null
);
```
## Remove the ACL conditions
If you want to remove the access control conditions from an asset. You need to
update both the Livepeer Studio API as well as the Lit state. However, this is
only possible, if the access control condition is not chosen permanently.
# Play from 4everland
Source: https://docs.livepeer.org/v1/developers/tutorials/upload-playback-videos-4everland
Learn how to play videos 4everland's IPFS gateway using Livepeer
This tutorial is based on Livepeer React version 3.9 or earlier, which is now
deprecated. Please ensure that you use Livepeer React version 4 or later, with
the new Livepeer JavaScript SDK. The integration process may appear different,
but the underlying concepts remain same.
IPFS is a decentralized peer-to-peer network that allows anyone to store and
share files. Unlike traditional centralized storage systems, IPFS stores data
across a network of distributed nodes, making it impossible to tamper with or
lose data.
4everland makes it very easy to upload, store, pin and fetch files from IPFS.
When combined with Livepeer, users can build decentralized video applications,
archive videos, create video NFTs, and more.
In this tutorial, you will learn how to use Livepeer to upload, transcode, and
playback videos on IPFS using 4Everland and Livepeer.
## Prerequisites
Before you start with this tutorial, make sure you have the following tools
installed on your machine:
* [Node.js](https://nodejs.org/en/) v16 or later
## Setting up Next.js App
First, let's create a directory for your project and initialize a Next.js app
using the following command in your terminal:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
npx create-next-app .
```
This will create a new Next.js app in the current directory and install all the
necessary dependencies.
Next, let"s install the `@livepeer/react`, library which we will use to
integrate Livepeer:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
npm install @livepeer/react dotenv
```
### Adding TailwindCSS
Tailwind CSS is a utility-first CSS framework that enables you to rapidly build
user interfaces. We will use it to style our app. First, we need to install the
`tailwindcss`, `postcss`, and `autoprefixer`dependencies. These dependencies are
necessary for TailwindCSS to work properly in a Next.js app.
Run the following command to install them:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
npm install --dev tailwindcss postcss autoprefixer
```
Once the dependencies are installed, we need to initiate the Tailwind CSS. This
will create the necessary configuration files and allow you to customize the
default Tailwind CSS styles. To do that, run the below code in your terminal.
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
npx tailwind init -p
```
The above command will generate two files named `tailwind.config.js` and
`postcss.config.js`. These files contain the configuration for Tailwind CSS and
PostCSS, respectively. Next, open the `tailwind.config.js` file in code editor
of your choice and replace its contents with the following code:
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
module.exports = {
content: ["./pages//.{js,ts,jsx,tsx}", "./components//.{js,ts,jsx,tsx}"],
theme: {
extend: {},
},
plugins: [],
};
```
The above code tells Tailwind CSS which files to process. At last, add the
tailwind directives for each of Tailwind’s layers to the `./styles/globals.css`
file.
```css theme={"theme":{"light":"github-light","dark":"dark-plus"}}
@tailwind base;
@tailwind components;
@tailwind utilities;
```
You can also check if Tailwind CSS is integrated successfully by updating the
code inside of the `pages/index.js` file, with below code.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
Livepeer x IPFS
Upload, stream, and transcode video on the decentralized web with Livepeer
and IPFS.
```
Save the file and run `npm run dev` to start the next.js app.
## Integrating Livepeer
Livepeer is a decentralized video platform that allows users to upload,
transcode, and serve video content. The Livepeer React SDK provides a set of
ready-to-use hooks that make it easy to integrate Livepeer into a project.
To get started, navigate to
[https://livepeer.studio/register](https://livepeer.studio/register) and create
a new account on Livepeer Studio. This will give you access to your Livepeer
dashboard, where you can manage your account and access your API keys.
Once you have created an account, in the dashboard, click on the Developers on
the sidebar.
Then, click on Create API Key, give a name to your key and then copy it as we
will need it later.
To use Livepeer React in your project, create a new directory named `client`in
the root directory, and add the following code to `index.js`
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { createReactClient, studioProvider } from "@livepeer/react";
const LivepeerClient = createReactClient({
provider: studioProvider({ apiKey: "YOUR_API_KEY" }),
});
export default LivepeerClient;
```
Make sure to replace the `YOUR_API_KEY` with the key which you just copied from
the Livepeer dashboard. And also replace the code inside of `_app.js` in the
page directory with the below code.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { LivepeerConfig } from "@livepeer/react";
import LivepeerClient from "../client";
import "../styles/globals.css";
function MyApp({ Component, pageProps }) {
return (
);
}
export default MyApp;
```
And that is it, you can now use Livepeer to upload and transcode assets.
## Create IPFS Bucket
We will be first using 4everland to upload videos to Arweave and then playback
the transcoded version using Livepeer’s Player.
The Livepeer player automatically triggers video transcoding to ensure smooth
playback.
This can be useful for ensuring that your videos are of high quality and that
they are accessible to a wide range of viewers, regardless of their device or
connection speed.
Head to the 4everland website and sign up for an account. Once you've created
your account, navigate to the "buckets" section in the sidebar and click on
"create bucket". Give your bucket a name and select IPFS as the storage option.
You can then use the 4everland dashboard or the API to upload your videos to
IPFS.
Then you can either use the 4everland dashboard to upload your videos to IPFS or
the API.
## Playback Videos from IPFS
Once you have uploaded the video, you can add Livepeer Player to playback the
video from the IPFS.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
arweaveId && (
);
}
```
And that is it. The player automatically transcodes your videos to ensure that
they playback smoothly and without any issues.
This can be useful for ensuring that your videos are of high quality and that
they are accessible to a wide range of viewers, regardless of their device or
connection speed.
Visit [4everland](https://4everland.org) to learn more about its capabilities
and the service on IPFS.
# Play from Arweave
Source: https://docs.livepeer.org/v1/developers/tutorials/upload-playback-videos-on-arweave
Learn how to upload and stream videos from Arweave using Bundlr and Livepeer
This tutorial is based on Livepeer React version 3.9 or earlier, which is now
deprecated. Please ensure that you use Livepeer React version 4 or later, with
the new Livepeer JavaScript SDK. The integration process may appear different,
but the underlying concepts remain same.
Arweave is a decentralized storage network that allows anyone to upload and
access data in a permanent and tamper-proof manner. Bundlr Network makes
uploading files and interacting with Arweave very easy. It provides fast and
multichain support for Arweave. When combined with Livepeer, users can build
decentralized video applications, archive videos, create video NFTs, and more.
In this tutorial, you will learn how to upload videos to Arweave using Bundlr
Network and playback the transcoded version of it using Livepeer React.
## Prerequisites
Before you start with this tutorial, make sure you have the following tool
installed on your machine:
* [Node.js](https://nodejs.org/en/) v16 or later
## Setting up Next.js App
First, create a directory for the project and then initialize a Next.js app
using the following command in your terminal:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
npx create-next-app .
```
This will create a new Next.js app in the current directory and install all the
necessary dependencies.
Next, let's install the `@livepeer/react` , `@bundlr-network/client` ,
`filereader-stream` libraries which we will use to integrate Livepeer, Bundlr
Network and stream the file respectively:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
npm install @livepeer/react @bundlr-network/client filereader-stream
```
### Adding TailwindCSS
Tailwind CSS is a utility-first CSS framework that enables you to rapidly build
user interfaces. We will use it to style our app. First, we need to install the
`tailwindcss`, `postcss`, and `autoprefixer`dependencies. These dependencies are
necessary for TailwindCSS to work properly in a Next.js app.
Run the following command to install them:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
npm install --dev tailwindcss postcss autoprefixer
```
Once the dependencies are installed, we need to initiate the Tailwind CSS. This
will create the necessary configuration files and allow you to customize the
default Tailwind CSS styles. To do that, run the below code in your terminal.
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
npx tailwind init -p
```
The above command will generate two files named `tailwind.config.js` and
`postcss.config.js`. These files contain the configuration for Tailwind CSS and
PostCSS, respectively. Next, open the `tailwind.config.js` file in code editor
of your choice and replace its contents with the following code:
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
module.exports = {
content: ["./pages//*.{js,ts,jsx,tsx}", "./components//*.{js,ts,jsx,tsx}"],
theme: {
extend: {},
},
plugins: [],
};
```
The above code tells Tailwind CSS which files to process. At last, add the
tailwind directives for each of Tailwind’s layers to the `./styles/globals.css`
file.
```css theme={"theme":{"light":"github-light","dark":"dark-plus"}}
@tailwind base;
@tailwind components;
@tailwind utilities;
```
You can also check if Tailwind CSS is integrated successfully by updating the
code inside of the `pages/index.js` file, with below code.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
Livepeer x Arweave x Bundlr
Playback transcode video from Arweave using Livepeer
```
Save the file and run `npm run dev` to start the next.js app and you should see
a similar page.
## Integrating Livepeer
Livepeer is a decentralized video platform that allows users to upload,
transcode, and serve video content. The Livepeer React SDK provides a set of
ready-to-use hooks that make it easy to integrate Livepeer into a project.
To get started, navigate to
[https://livepeer.studio/register](https://livepeer.studio/register) and create
a new account on Livepeer Studio. This will give you access to your Livepeer
dashboard, where you can manage your account and access your API keys.
Once you have created an account, in the dashboard, click on the Developers on
the sidebar.
Then, click on Create API Key, give a name to your key and then copy it as we
will need it later.
To use Livepeer React in your project, create a new directory named `client`in
the root directory, and add the following code to `livepeer.js`
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { createReactClient, studioProvider } from "@livepeer/react";
const LivepeerClient = createReactClient({
provider: studioProvider({ apiKey: "YOUR_API_KEY" }),
});
export default LivepeerClient;
```
Make sure to replace the `YOUR_API_KEY` with the key which you just copied from
the Livepeer dashboard. And also replace the code inside of `_app.js` in the
page directory with the below code.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { LivepeerConfig } from "@livepeer/react";
import LivepeerClient from "../client/livepeer";
import "../styles/globals.css";
function MyApp({ Component, pageProps }) {
return (
);
}
export default MyApp;
```
And that is it, you can now use Livepeer to upload and transcode assets.
## Uploading Videos To Arweave
We will be first using Bundlr Network to upload videos to Arweave and then
playback the transcoded version using Livepeer’s Player.
The Livepeer player automatically triggers video transcoding to ensure smooth
playback.
This can be useful for ensuring that your videos are of high quality and that
they are accessible to a wide range of viewers, regardless of their device or
connection speed.
Inside `client` directory, create a new file named `bundlr.js` and add the below
code inside of it.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { providers } from "ethers";
import { WebBundlr } from "@bundlr-network/client";
const Bundlr = async () => {
// Request permission from the user to access their Ethereum account
await window.ethereum.enable();
// Create a new Web3 provider using the user's Ethereum account
const provider = new providers.Web3Provider(window.ethereum);
// Wait for the provider to be ready to use
await provider._ready();
// Create a new instance of the Bundlr and, passing in the provider and the URL of the Bundlr node
const bundlr = new WebBundlr(
"https://node1.bundlr.network",
"matic", // You can use any of the currencies supported by Bundlr
provider
);
// Wait for the Bundlr instance to be ready to use
await bundlr.ready();
// Return the Bundlr instance
return bundlr;
};
export default Bundlr;
```
This file creates a new instance of the Bundlr's Web API, which can be used to
interact with the Bundlr network, such as uploading files, checking the balance,
and funding the account.
Next, inside the `index.js` file in the `pages` directory, create two states,
one for the video file and the other for the Arweave ID:
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const [video, setVideo] = useState(null);
const [arweaveId, setArweaveId] = useState(null);
```
Then, below the paragraph tag, add the following input and button:
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
setVideo(e.target.files[0])}
/>
```
This code adds an input field where the user can select a video file, and a
button that will call the `uploadVideo` function when clicked.
Add the following function to handle the uploading of the video:
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const uploadVideo = async () => {
const bundlr = await Bundlr();
// Uses the fileReaderStream function to create a stream from the video
const stream = fileReaderStream(video);
// Passing the stream to Bundlr to upload the video
const { data } = await bundlr.uploader.chunkedUploader.uploadData(stream, {
tags: [{ name: "Content-Type", value: "video/mp4" }],
});
// Save the ID to state we declared earlier
setArweaveId(data.id);
};
```
Finally, add Livepeer Player to playback the video from the Arweave network.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
arweaveId && (
);
}
```
Here is what your final code should look like:
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useState } from "react";
import Bundlr from "../client/bundlr";
import fileReaderStream from "filereader-stream";
import { Player } from "@livepeer/react";
export default function Home() {
const [video, setVideo] = useState(null);
const [arweaveId, setArweaveId] = useState(null);
const uploadVideo = async () => {
const bundlr = await Bundlr();
const stream = fileReaderStream(video);
const { data } = await bundlr.uploader.chunkedUploader.uploadData(stream, {
tags: [{ name: "Content-Type", value: "video/mp4" }],
});
setArweaveId(`ar://${data.id}`);
};
return (
Livepeer x Arweave x Bundlr
Playback transcode video from Arweave using Livepeer
setVideo(e.target.files[0])}
/>
{arweaveId && (
)}
);
}
```
Visit [Bundlr](https://bundlr.network/) to learn more about its capabilities and
the service on [Arweave](https://www.arweave.org/).
# Play from IPFS
Source: https://docs.livepeer.org/v1/developers/tutorials/upload-playback-videos-on-ipfs
Learn how to upload and play back videos on IPFS using Livepeer
This tutorial is based on Livepeer React version 3.9 or earlier, which is now
deprecated. Please ensure that you use Livepeer React version 4 or later, with
the new Livepeer JavaScript SDK. The integration process may appear different,
but the underlying concepts remain same.
IPFS is a decentralized peer-to-peer network that allows anyone to store and
share files. Unlike traditional centralized storage systems, IPFS stores data
across a network of distributed nodes, making it impossible to tamper with or
lose data.
In this tutorial, you will learn how to use Livepeer to upload, transcode, and
playback videos on IPFS using Livepeer.
## Prerequisites
Before you start with this tutorial, make sure you have the following tools
installed on your machine:
* [Node.js](https://nodejs.org/en/) v16 or later
## Setting up Next.js App
First, let's create a directory for your project and initialize a Next.js app
using the following command in your terminal:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
npx create-next-app .
```
This will create a new Next.js app in the current directory and install all the
necessary dependencies.
Next, let's install the `@livepeer/react`, library which we will use to
integrate Livepeer:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
npm install @livepeer/react dotenv
```
### Adding TailwindCSS
Tailwind CSS is a utility-first CSS framework that enables you to rapidly build
user interfaces. We will use it to style our app. First, we need to install the
`tailwindcss`, `postcss`, and `autoprefixer`dependencies. These dependencies are
necessary for TailwindCSS to work properly in a Next.js app.
Run the following command to install them:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
npm install --dev tailwindcss postcss autoprefixer
```
Once the dependencies are installed, we need to initiate the Tailwind CSS. This
will create the necessary configuration files and allow you to customize the
default Tailwind CSS styles. To do that, run the below code in your terminal.
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
npx tailwind init -p
```
The above command will generate two files named `tailwind.config.js`
and `postcss.config.js`. These files contain the configuration for Tailwind CSS
and PostCSS, respectively. Next, open the `tailwind.config.js` file in code
editor of your choice and replace its contents with the following code:
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
module.exports = {
content: ["./pages//*.{js,ts,jsx,tsx}", "./components//*.{js,ts,jsx,tsx}"],
theme: {
extend: {},
},
plugins: [],
};
```
The above code tells Tailwind CSS which files to process. At last, add the
tailwind directives for each of Tailwind’s layers to the `./styles/globals.css`
file.
```css theme={"theme":{"light":"github-light","dark":"dark-plus"}}
@tailwind base;
@tailwind components;
@tailwind utilities;
```
You can also check if Tailwind CSS is integrated successfully by updating the
code inside of the `pages/index.js` file, with below code.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
Livepeer x IPFS
Upload, stream, and transcode video on the decentralized web with Livepeer
and IPFS.
```
Save the file and run `npm run dev` to start the next.js app and you should see
a similar page.
## Integrating Livepeer
Livepeer is a decentralized video platform that allows users to upload,
transcode, and serve video content. The Livepeer React SDK provides a set of
ready-to-use hooks that make it easy to integrate Livepeer into a project.
To get started, navigate
to [https://livepeer.studio/register](https://livepeer.studio/register) and
create a new account on Livepeer Studio. This will give you access to your
Livepeer dashboard, where you can manage your account and access your API keys.
Once you have created an account, in the dashboard, click on the Developers on
the sidebar.
Then, click on Create API Key, give a name to your key and then copy it as we
will need it later.
To use Livepeer React in your project, create a new directory named `client`in
the root directory, and add the following code to `index.js`
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { createReactClient, studioProvider } from "@livepeer/react";
const LivepeerClient = createReactClient({
provider: studioProvider({ apiKey: "YOUR_API_KEY" }),
});
export default LivepeerClient;
```
Make sure to replace the `YOUR_API_KEY` with the key which you just copied from
the Livepeer dashboard. And also replace the code inside of `_app.js` in the
page directory with the below code.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { LivepeerConfig } from "@livepeer/react";
import LivepeerClient from "../client";
import "../styles/globals.css";
function MyApp({ Component, pageProps }) {
return (
);
}
export default MyApp;
```
And that is it, you can now use Livepeer to upload and transcode assets.
Create a components folder named and inside of it create a new file named
`Button.js`. Add the below code to it.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import React from "react";
export default function Button({ children, onClick }) {
return (
);
}
```
Next, in the `pages/index.js` file, import the Button component and add it below
the `p` tag. This is how your file should look like
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import Button from "../components/Button";
export default function Home() {
return (
Livepeer x IPFS
Upload, stream, and transcode video on the decentralized web with
Livepeer and IPFS.
);
}
```
Add the file input with class name hidden below the Button component.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
```
Next, create a useState named asset and also a reference for the file input.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// State for the asset
const [asset, setAsset] = useState(null);
// Ref for the file input
const fileInput = useRef(null);
```
I have already commented on each line of the code so you can understand what is
going on.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const ChooseAsset = async () => {
// When user clicks the button, open the file input dialog
ref.current?.click();
};
const onChange = async (e) => {
// Get the file
const file = e.target.files?.[0];
// If no file, return
if (!file) return;
// If there is a file, set the asset state to the file
setAsset(file);
};
const uploadAsset = async () => {};
```
Save the file and now you should be able to select a file from your computer.
Next, import the `useCreateAsset` from the `@livepeer/react` and add the hook to
the index.js file.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const {
mutate: createAsset,
data: assets,
progress,
error,
} = useCreateAsset(
asset
? {
sources: [{ name: asset.name, file: asset }] as const,
}
: null
);
```
Update the `uploadAsset` function and save the files. You can now choose and
upload videos to Livepeer.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const uploadAsset = async () => {
await createAsset?.();
};
```
You can also add the below code to check the progress of the asset
upload/transcode.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const progressFormatted = useMemo(
() =>
progress?.[0].phase === "failed"
? "Failed to process video."
: progress?.[0].phase === "waiting"
? "Waiting"
: progress?.[0].phase === "uploading"
? `Uploading: ${Math.round(progress?.[0]?.progress * 100)}%`
: progress?.[0].phase === "processing"
? `Processing: ${Math.round(progress?.[0].progress * 100)}%`
: null,
[progress]
);
```
Now, let’s also print the asset information once it is uploaded successfully. To
do that simply add the below code below the input tag.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
assets?.map((asset) => (
Asset Name: {asset?.name}
Playback URL: {asset?.playbackUrl}
IPFS CID: {asset?.storage?.ipfs?.cid ?? "None"}
));
}
```
Finally this is how your code should look like:
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useCreateAsset } from "@livepeer/react";
import { useMemo, useRef, useState } from "react";
import Button from "../components/Button";
export default function Home() {
// State for the asset
const [asset, setAsset] = useState(null);
// Ref for the file input
const fileInput = useRef(null);
const {
mutate: createAsset,
data: assets,
progress,
error,
} = useCreateAsset(
asset
? {
sources: [{ name: asset.name, file: asset }],
}
: null
);
const ChooseAsset = async () => {
// When user clicks the button, open the file input dialog
fileInput.current?.click();
};
const onChange = async (e) => {
// Get the file
const file = e.target.files?.[0];
// If no file, return
if (!file) return;
// If there is a file, set the asset state to the file
setAsset(file);
};
const uploadAsset = async () => {
await createAsset?.();
};
const progressFormatted = useMemo(
() =>
progress?.[0].phase === "failed"
? "Failed to process video."
: progress?.[0].phase === "waiting"
? "Waiting"
: progress?.[0].phase === "uploading"
? `Uploading: ${Math.round(progress?.[0]?.progress * 100)}%`
: progress?.[0].phase === "processing"
? `Processing: ${Math.round(progress?.[0].progress * 100)}%`
: null,
[progress]
);
return (
Livepeer x IPFS
Upload, stream, and transcode video on the decentralized web with
Livepeer and IPFS.
{progressFormatted}
{assets?.map((asset) => (
Asset Name: {asset?.name}
Playback URL: {asset?.playbackUrl}
IPFS CID: {asset?.storage?.ipfs?.cid ?? "None"}
))}
);
}
```
Go ahead choose and upload a video and then navigate to
[https://livepeer.studio/dashboard/assets](https://livepeer.studio/dashboard/assets)
you should be able to see the video which you just uploaded.
## Uploading Videos To IPFS
By default, the assets which you upload would be saved on Livepeer’ storage. If
you want to upload the videos to IPFS, you can use `useUpdateAsset` hook from
Livepeer React or Livepeer Studio’s REST API. In this tutorial we will be using
the Livepeer React hooks.
Import the `useUpdateAsset` hook from the livepeer.js and add it after the
useCreateAsset
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const { mutate: updateAsset, status } = useUpdateAsset({
// Here we are providing the assetId of the video
assetId: assets?.[0].id,
// And choose IPFS : true to make sure the video is uploaded to IPFS
storage: { ipfs: true },
});
```
And also include a Button to call the updateAsset hook in the map function:
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
```
If you have saved your videos on other IPFS services like web3.storage, you can
easily playback them using Livepeer's decentralized storage player. This player
transcodes your videos to ensure that they playback smoothly and without any
issues.
This can be useful for ensuring that your videos are of high quality and that
they are accessible to a wide range of viewers, regardless of their device or
connection speed.
# API Support Matrix
Source: https://docs.livepeer.org/v1/references/api-support-matrix
## On Demand
### Inputs
Currently, only file sizes up to 30GB are supported.
#### Video
| Container | Video codecs supported with container |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| MPEG-4 (.mp4) | Uncompressed, AVC Intra 50/100, DivX/Xvid, H.261, H.262, H.263, AVC (H.264), HEVC (H.265), JPEG 2000, MPEG-2, MPEG-4 part 2, VC-1 |
| QuickTime (.mov). | Uncompressed, AVC Intra 50/100, DivX/Xvid, DV/DVCPRO, H.261, H.262, H.263, AVC (H.264), HEVC (H.265), JPEG 2000 (J2K), MJPEG, MPEG-2, MPEG-4 part 2, QuickTime Animation (RLE) |
| Audio Video Interleave (.avi) | Uncompressed, Canopus HQ, DivX/Xvid, DV/DVCPRO, MJPEG |
| Adobe Flash (.flv) | AVC (H.264), Flash 9 File, H.263 |
| Matroska (.mkv) | AAC, Dolby Digital (AC3), Dolby Digital Plus (EAC3), Opus, WMA, WMA2 |
| WebM (.webm) | VP8, VP9 |
| Advanced Systems Format (.wmv) | WMA, WMA2, WMA Pro |
#### Audio
| Container | Audio codecs supported with container |
| ------------------------------ | ----------------------------------------------------------------------------------------------------------- |
| MPEG-4 (.mp4) | AAC, Dolby Digital (AC3), Dolby Digital Plus (EAC3), PCM, WMA, WMA2 |
| QuickTime (.mov) | AAC, MP3, PCM |
| Audio Video Interleave (.avi) | Dolby Digital (AC3), Dolby Digital Plus (EAC3), Dolby E frames carried in PCM streams, MP3, MPEG Audio, PCM |
| Adobe Flash (.flv) | AAC |
| Matroska (.mkv) | AAC, Dolby Digital (AC3), Dolby Digital Plus (EAC3), Opus, WMA, WMA2 |
| WebM (.webm) | Opus, Vorbis |
| Advanced Systems Format (.wmv) | WMA, WMA2, WMA Pro |
#### Other Attributes
| Attribute | Notes |
| ---------- | ------------------------------------------------------------------------- |
| Resolution | Maximum resolution is \[8192]x\[4320] or \[4320]x\[8192] in portrait mode |
### Outputs
#### Video
| Container | Video codecs supported with container |
| ------------- | ------------------------------------- |
| MPEG-4 (.mp4) | AVC (H.264) |
| HLS | AVC (H.264) |
#### Audio
| Container | Audio codecs supported with container |
| ------------- | ------------------------------------- |
| MPEG-4 (.mp4) | AAC |
## Livestream
### Ingest Support
| attribute | notes |
| ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Location | Global |
| Ingest Format | RTMP, SRT (Beta) |
| Ingest Codec | H264 + AAC |
| Ingest Authentication | Webhook based |
| Encoder Software | Supported tested: OBS 25.0.8, ffmpeg 4.3, Streamaxia Supported untested: Xsplit, other versions of OBS and ffmpeg, other RTMP encoders, SRT encoders Unsupported: WebRTC |
| Framerate | Between 5fps and 60fps, passthrough or custom |
| GOP Size (Keyframe Interval) | Supported tested: Constant GOP, Variable GOP of 0.5s to 8s Supported untested: Xsplit, Other versions of OBS and ffmpeg, other RTMP encoders Unsupported: Variable GOP not within 0.5s to 8s |
### Transcoding Support
| attribute | notes |
| ------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| Location | Global |
| Codec | H264 + AAC |
| H264 Transcoding Profiles | Baseline, Main, High |
| FPS | Supported tested: 24, 25, 30, 60 fps, uniform across all renditions Supported untested: custom fps, uniform across all renditions |
| Resolution | Supported tested: Custom resolution up to 1080pSupported untested: Custom resolution up to 4k |
| Pixel format | YUV4:2:0 |
### Video Workflow Support
| attribute | notes |
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| On Demand upload format | MP4 |
| Live latency | 10-18 seconds with good RTMP ingest health, 2s segment size, and standard 3 seg buffering in player |
| Live output format | HLS playback URL (m3u8) |
| H264 Transcoding Profiles | Baseline, Main, High |
| Video players | Supported tested: Livepeer UI Kit Player, video.js, hls.js, safari/ios native player, Theoplayer; Supported untested: JWPlayer, android native, Shaka, Exo, Bitmovin, Brightcove |
| Video Delivery Location | Supported tested: EU, USSupported untested: Asia, South America, Australia, Africa |
| Livestream recording | Only available for paying users. HLS playback URL (m3u8) available 5 minutes after session ends. Livepeer.Studio stores recording and serves playback via CDN. There is no limit on recording length. |
| Recording output format | HLS playback URL (m3u8) |
| CDN delivery | CDN delivery is only available for paying users. |
| Non-CDN Delivery | Non-CDN delivery for free tier users is limited to 10 viewers per account. Free tier users will have transcoding limited to 240p after 30 free minutes. |
| Custom CDN | Only for custom pricing tier users. |
| Stream Status | active or inactive |
| Stream length | We can support streams up to 12 hours in length. Please reach out to [contact@livepeer.studio](mailto:contact@livepeer.studio) if you’re looking to run longer uninterrupted streams through Livepeer.Studio. |
| Scalability | 1000 concurrent streams across all users. Please contact us at [contact@livepeer.studio](mailto:contact@livepeer.studio) for additional capacity |
# Awesome Livepeer
Source: https://docs.livepeer.org/v1/references/awesome-livepeer
# Contract Addresses
Source: https://docs.livepeer.org/v1/references/contract-addresses
Look up current Livepeer protocol contract addresses across supported networks and deployed versions — Arbitrum One (active) and Ethereum Mainnet (legacy).
**This page is no longer maintained.** Contract addresses on this page may be outdated or incorrect.
The canonical, automatically verified contract addresses are at:
**[Livepeer Contract Addresses](/v2/about/resources/livepeer-contract-addresses)**
All addresses on the canonical page are verified on-chain weekly and updated automatically from the protocol's governor-scripts repository.
Addresses of deployed contracts of the Livepeer protocol on multiple networks.
## Current
### Arbitrum One
All contracts on Arbitrum One implement the Delta version of the protocol.
* **Governor**: [`0xD9dEd6f9959176F0A04dcf88a0d2306178A736a6`](https://arbiscan.io/address/0xD9dEd6f9959176F0A04dcf88a0d2306178A736a6)
* **Controller**: [`0xD8E8328501E9645d16Cf49539efC04f734606ee4`](https://arbiscan.io/address/0xD8E8328501E9645d16Cf49539efC04f734606ee4)
* **LivepeerToken**: [`0x289ba1701C2F088cf0faf8B3705246331cB8A839`](https://arbiscan.io/address/0x289ba1701C2F088cf0faf8B3705246331cB8A839)
* **Minter**: [`0xc20DE37170B45774e6CD3d2304017fc962f27252`](https://arbiscan.io/address/0xc20DE37170B45774e6CD3d2304017fc962f27252)
* **BondingManager (Proxy)**: [`0x35Bcf3c30594191d53231E4FF333E8A770453e40`](https://arbiscan.io/address/0x35Bcf3c30594191d53231E4FF333E8A770453e40)
* **BondingManager (Target)**: [`0x4bA7E7531Ab56bC8d78dB4FDc88D21F621f34BB4`](https://arbiscan.io/address/0x4bA7E7531Ab56bC8d78dB4FDc88D21F621f34BB4)
* **TicketBroker (Proxy)**: [`0xa8bB618B1520E284046F3dFc448851A1Ff26e41B`](https://arbiscan.io/address/0xa8bB618B1520E284046F3dFc448851A1Ff26e41B)
* **TicketBroker (Target)**: [`0xea1b0F6c8D158328a6e3D3F924B86A759F41465c`](https://arbiscan.io/address/0xea1b0F6c8D158328a6e3D3F924B86A759F41465c)
* **RoundsManager (Proxy)**: [`0xdd6f56DcC28D3F5f27084381fE8Df634985cc39f`](https://arbiscan.io/address/0xdd6f56DcC28D3F5f27084381fE8Df634985cc39f)
* **RoundsManager (Target)**: [`0x92d804Ed49D92438aEA6fe552BD9163aacb7E841`](https://arbiscan.io/address/0x92d804Ed49D92438aEA6fe552BD9163aacb7E841)
* **BondingVotes (Proxy)**: [`0x0B9C254837E72Ebe9Fe04960C43B69782E68169A`](https://arbiscan.io/address/0x0B9C254837E72Ebe9Fe04960C43B69782E68169A)
* **BondingVotes (Target)**: [`0x68AF80376Bc1CA0C25a83b28e5570E8c7bdD3119`](https://arbiscan.io/address/0x68AF80376Bc1CA0C25a83b28e5570E8c7bdD3119)
* **Treasury**: [`0xf82C1FF415F1fCf582554fDba790E27019c8E8C4`](https://arbiscan.io/address/0xf82C1FF415F1fCf582554fDba790E27019c8E8C4)
* **LivepeerGovernor (Proxy)**: [`0xcFE4E2879B786C3aa075813F0E364bb5acCb6aa0`](https://arbiscan.io/address/0xcFE4E2879B786C3aa075813F0E364bb5acCb6aa0)
* **LivepeerGovernor (Target)**: [`0xd2Ce37BCB287CaDc40647f567C2D3C4220901634`](https://arbiscan.io/address/0xd2Ce37BCB287CaDc40647f567C2D3C4220901634)
* **ServiceRegistry (Proxy)**: [`0xC92d3A360b8f9e083bA64DE15d95Cf8180897431`](https://arbiscan.io/address/0xC92d3A360b8f9e083bA64DE15d95Cf8180897431)
* **ServiceRegistry (Target)**: [`0x38093CDca43aeCd7bb474983519A246e93A3b0a7`](https://arbiscan.io/address/0x38093CDca43aeCd7bb474983519A246e93A3b0a7)
* **AIServiceRegistry (Target)**: [`0x04C0b249740175999E5BF5c9ac1dA92431EF34C5`](https://arbiscan.io/address/0x04C0b249740175999E5BF5c9ac1dA92431EF34C5) (detached from controller)
* **SortedDoublyLL**: [`0xC45f6918F7Bcac7aBc8fe05302b3cDF39776cdeb`](https://arbiscan.io/address/0xC45f6918F7Bcac7aBc8fe05302b3cDF39776cdeb)
* **PollCreator**: [`0x8bb50806D60c492c0004DAD5D9627DAA2d9732E6`](https://arbiscan.io/address/0x8bb50806D60c492c0004DAD5D9627DAA2d9732E6)
* **MerkleSnapshot**: [`0x10736ffaCe687658F88a46D042631d182C7757f7`](https://arbiscan.io/address/0x10736ffaCe687658F88a46D042631d182C7757f7)
* **DelegatorPool**: [`0xfdb06109032AD3671a8f14f5f2E78f4B9E81b567`](https://arbiscan.io/address/0xfdb06109032AD3671a8f14f5f2E78f4B9E81b567)
* **L2LPTDataCache**: [`0xd78b6bD09cd28A83cFb21aFa0DA95c685A6bb0B1`](https://arbiscan.io/address/0xd78b6bD09cd28A83cFb21aFa0DA95c685A6bb0B1)
* **L2LPTGateway**: [`0x6D2457a4ad276000A615295f7A80F79E48CcD318`](https://arbiscan.io/address/0x6D2457a4ad276000A615295f7A80F79E48CcD318)
* **L2Migrator (Proxy)**: [`0x148D5b6B4df9530c7C76A810bd1Cdf69EC4c2085`](https://arbiscan.io/address/0x148D5b6B4df9530c7C76A810bd1Cdf69EC4c2085)
* **L2Migrator (Target)**: [`0x93BB030735747708b4D33093A98d4c804Cd6B58C`](https://arbiscan.io/address/0x93BB030735747708b4D33093A98d4c804Cd6B58C)
### Ethereum Mainnet
The following contracts on Ethereum Mainnet implement the Delta version of the protocol:
* Governor
* LivepeerToken
* L1Escrow
* L1LPTDataCache
* L1LPTGateway
* L1Migrator
* BridgeMinter
Since the Confluence upgrade, the protocol has been deployed to Arbitrum One and all contracts on Ethereum Mainnet besides the above are paused.
* **Governor**: [`0xFC3CBed6A3476F7616CC70f078397700136eEBFd`](https://etherscan.io/address/0xFC3CBed6A3476F7616CC70f078397700136eEBFd)
* **Controller**: [`0xf96d54e490317c557a967abfa5d6e33006be69b3`](https://etherscan.io/address/0xf96d54e490317c557a967abfa5d6e33006be69b3)
* **LivepeerToken**: [`0x58b6a8a3302369daec383334672404ee733ab239`](https://etherscan.io/address/0x58b6a8a3302369daec383334672404ee733ab239)
* **Minter**: [`0x505F8c2ee81f1C6fa0D88e918eF0491222E05818`](https://etherscan.io/address/0x505F8c2ee81f1C6fa0D88e918eF0491222E05818)
* **BondingManager (Proxy)**: [`0x511bc4556d823ae99630ae8de28b9b80df90ea2e`](https://etherscan.io/address/0x511bc4556d823ae99630ae8de28b9b80df90ea2e)
* **BondingManager (Target)**: [`0x5FE3565dB7F1Dd8d6A9E968D45BD2Aee3836a1D4`](https://etherscan.io/address/0x5FE3565dB7F1Dd8d6A9E968D45BD2Aee3836a1D4)
* **TicketBroker (Proxy)**: [`0x5b1ce829384eebfa30286f12d1e7a695ca45f5d2`](https://etherscan.io/address/0x5b1ce829384eebfa30286f12d1e7a695ca45f5d2)
* **TicketBroker (Target)**: [`0x6F582E2bB19ac31D4B1e6eDD0c2eFEabD700f808`](https://etherscan.io/address/0x6F582E2bB19ac31D4B1e6eDD0c2eFEabD700f808)
* **RoundsManager (Proxy)**: [`0x3984fc4ceeef1739135476f625d36d6c35c40dc3`](https://etherscan.io/address/0x3984fc4ceeef1739135476f625d36d6c35c40dc3)
* **RoundsManager (Target)**: [`0xC89fE48382F8fda6992dC590786A84275bCD1C57`](https://etherscan.io/address/0xC89fE48382F8fda6992dC590786A84275bCD1C57)
* **ServiceRegistry (Proxy)**: [`0x406a112f3218b988c66778fd72fc8467f2601366`](https://etherscan.io/address/0x406a112f3218b988c66778fd72fc8467f2601366)
* **ServiceRegistry (Target)**: [`0x72d9dfa25f75a5f2c27b7336e643a559ae6aeb8e`](https://etherscan.io/address/0x72d9dfa25f75a5f2c27b7336e643a559ae6aeb8e)
* **GenesisManager**: [`0x3a9543d4767b2c914ea22fd0b07e17b0901aaebf`](https://etherscan.io/address/0x3a9543d4767b2c914ea22fd0b07e17b0901aaebf)
* **MerkleMine**: [`0x8e306b005773bee6ba6a6e8972bc79d766cc15c8`](https://etherscan.io/address/0x8e306b005773bee6ba6a6e8972bc79d766cc15c8)
* **MultiMerkleMine**: [`0x182ebf4c80b28efc45ad992ecbb9f730e31e8c7f`](https://etherscan.io/address/0x182ebf4c80b28efc45ad992ecbb9f730e31e8c7f)
* **SortedDoublyLL**: [`0x1a0b2ca69ca2c7f96e2529faa6d63f881655d81a`](https://etherscan.io/address/0x1a0b2ca69ca2c7f96e2529faa6d63f881655d81a)
* **Refunder**: [`0x780c98cbb0cc21d6617c05332bd5cf6f847c71c2`](https://etherscan.io/address/0x780c98cbb0cc21d6617c05332bd5cf6f847c71c2)
* **PollCreator**: [`0xBf824EDb6b94D9B52d972d5B25bCc19b4e6E3F3C`](https://etherscan.io/address/0xBf824EDb6b94D9B52d972d5B25bCc19b4e6E3F3C)
* **MerkleSnapshot**: [`0x24ebEd82c681f435E944BEEbFAEEAaE443D08438`](https://etherscan.io/address/0x24ebEd82c681f435E944BEEbFAEEAaE443D08438)
* **L1Escrow**: [`0x6A23F4940BD5BA117Da261f98aae51A8BFfa210A`](https://etherscan.io/address/0x6A23F4940BD5BA117Da261f98aae51A8BFfa210A)
* **L1LPTDataCache**: [`0x1d24838b35A9c138Ac157A852e19e948aD6323D7`](https://etherscan.io/address/0x1d24838b35A9c138Ac157A852e19e948aD6323D7)
* **L1LPTGateway**: [`0x6142f1C8bBF02E6A6bd074E8d564c9A5420a0676`](https://etherscan.io/address/0x6142f1C8bBF02E6A6bd074E8d564c9A5420a0676)
* **L1Migrator**: [`0x21146B872D3A95d2cF9afeD03eE5a783DaE9A89A`](https://etherscan.io/address/0x21146B872D3A95d2cF9afeD03eE5a783DaE9A89A)
* **BridgeMinter**: [`0x8dDDB96CF36AC8860f1DE5C7c4698fd499FAB405`](https://etherscan.io/address/0x8dDDB96CF36AC8860f1DE5C7c4698fd499FAB405)
## Historical (DEPRECATED — FOR REFERENCE ONLY)
### Arbitrum One
#### BondingManager (Target)
* **V1**: [`0xe479B9fbA2Cd65f822f451fC8C145c663B995CE6`](https://arbiscan.io/address/0xe479B9fbA2Cd65f822f451fC8C145c663B995CE6)
* **V2**: [`0xC40df4db2f99e7e235780A93B192F1a934f0c45b`](https://arbiscan.io/address/0xC40df4db2f99e7e235780A93B192F1a934f0c45b)
* **V3**: [`0x3757DB506ECd9CBE643660C0F5b70db5b321202C`](https://arbiscan.io/address/0x3757DB506ECd9CBE643660C0F5b70db5b321202C)
* **V4**: [`0x0f9C425E7374602C20370d3fd263155B4c3bDc91`](https://arbiscan.io/address/0x0f9C425E7374602C20370d3fd263155B4c3bDc91)
* **V5**: [`0x3a941e1094B9E33efABB26a9047a8ABb4b257907`](https://arbiscan.io/address/0x3a941e1094B9E33efABB26a9047a8ABb4b257907)
* **V6**: [`0x9c9209c9ff6996513b3673d69ee7b36a6c58a8cf`](https://arbiscan.io/address/0x9c9209c9ff6996513b3673d69ee7b36a6c58a8cf)
* **V7**: [`0x363cdB9BaE210Ef182c60b5a496139E980330127`](https://arbiscan.io/address/0x363cdB9BaE210Ef182c60b5a496139E980330127)
* **V8**: [`0x557093B1Ab53412166beAd939f34244170b6525B`](https://arbiscan.io/address/0x557093B1Ab53412166beAd939f34244170b6525B)
* **V9**: [`0x6b397f20DC227B4E23fEc20BBDBe166d0DFFC452`](https://arbiscan.io/address/0x6b397f20DC227B4E23fEc20BBDBe166d0DFFC452)
* **V10**: [`0xd1C1F5d44D8F83ca2A05Baf40461e550cFDDecA2`](https://arbiscan.io/address/0xd1C1F5d44D8F83ca2A05Baf40461e550cFDDecA2)
* **V11 (current)**: [`0x4bA7E7531Ab56bC8d78dB4FDc88D21F621f34BB4`](https://arbiscan.io/address/0x4bA7E7531Ab56bC8d78dB4FDc88D21F621f34BB4)
#### BondingVotes (Target)
* **V1**: [`0x1561fC5F7Efc049476224005DFf38256dccfc509`](https://arbiscan.io/address/0x1561fC5F7Efc049476224005DFf38256dccfc509)
#### TicketBroker (Target)
* **V1**: [`0x7Beb84c52ce96DFd90431FAA97378994a8baa6df`](https://arbiscan.io/address/0x7Beb84c52ce96DFd90431FAA97378994a8baa6df)
* **V2 (current)**: [`0xea1b0F6c8D158328a6e3D3F924B86A759F41465c`](https://arbiscan.io/address/0xea1b0F6c8D158328a6e3D3F924B86A759F41465c)
#### Minter
* **V1**: [`0x4969dcCF5186e1c49411638fc8A2a020Fdab752E`](https://arbiscan.io/address/0x4969dcCF5186e1c49411638fc8A2a020Fdab752E)
#### L2Migrator (Target)
* **V1**: [`0x4F59b39e2ea628fe8371BDfd51B063319339c7EE`](https://arbiscan.io/address/0x4F59b39e2ea628fe8371BDfd51B063319339c7EE)
### Ethereum Mainnet
#### LivepeerVerifier
* **V1**: [`0xf623811b08b45792d0223d77d9c922dae29712ec`](https://etherscan.io/address/0xf623811b08b45792d0223d77d9c922dae29712ec)
* **V2**: [`0xe4be2a35dec0063f9dfccb9b740b1acb7eefefec`](https://etherscan.io/address/0xe4be2a35dec0063f9dfccb9b740b1acb7eefefec)
#### Minter
* **V1**: [`0x8573f2f5a3bd960eee3d998473e50c75cdbe6828`](https://etherscan.io/address/0x8573f2f5a3bd960eee3d998473e50c75cdbe6828)
#### BondingManager (Target)
* **V1**: [`0x81eb0b10ff8703905904e4d91cf6aa575d59736f`](https://etherscan.io/address/0x81eb0b10ff8703905904e4d91cf6aa575d59736f)
* **V2**: [`0x5A9512826EAAF1FE4190f89443314E95A515fE24`](https://etherscan.io/address/0x5A9512826EAAF1FE4190f89443314E95A515fE24)
* **V3**: [`0x633101b3f15f93c5f415830d48e56b9b1f7ba584`](https://etherscan.io/address/0x633101b3f15f93c5f415830d48e56b9b1f7ba584)
* **V4**: [`0x05C03EA0039f2e828A725A82939fc1e90de38B44`](https://etherscan.io/address/0x05C03EA0039f2e828A725A82939fc1e90de38B44)
* **V5**: [`0xCBAa6eA4886b535FC7ABACe3F3985Ed03b3b80a0`](https://etherscan.io/address/0xCBAa6eA4886b535FC7ABACe3F3985Ed03b3b80a0)
* **V6**: [`0xDC6eE74A18994caD3876a078B6fa4920FD9C507d`](https://etherscan.io/address/0xDC6eE74A18994caD3876a078B6fa4920FD9C507d)
* **V7**: [`0x1a6007d1D0583452Bd6f45a4e1a9190B15Fbd7E3`](https://etherscan.io/address/0x1a6007d1D0583452Bd6f45a4e1a9190B15Fbd7E3)
* **V8**: [`0xef5E170b679ddaF5e22ADC10fD23DDdB79E3C0c5`](https://etherscan.io/address/0xef5E170b679ddaF5e22ADC10fD23DDdB79E3C0c5)
* **V9**: [`0xc8a695155648F18B0cfd6989498B6f8b2c4cc56A`](https://etherscan.io/address/0xc8a695155648F18B0cfd6989498B6f8b2c4cc56A)
* **V10**: [`0x35F99F326681FE4F38719491be48Ab4950795013`](https://etherscan.io/address/0x35F99F326681FE4F38719491be48Ab4950795013)
* **V11**: [`0xAC0153a8C5227e43506901a4f3f83FD000c8178f`](https://etherscan.io/address/0xAC0153a8C5227e43506901a4f3f83FD000c8178f)
* **V12**: [`0x246edEBae14b186a67e3d466A485321169a8bcD5`](https://etherscan.io/address/0x246edEBae14b186a67e3d466A485321169a8bcD5)
* **V13**: [`0x223398d0BF9cc24960b3886CC481dBf5276EdeD2`](https://etherscan.io/address/0x223398d0BF9cc24960b3886CC481dBf5276EdeD2)
* **V14**: [`0x0da7c263eCF5cD3ddba275b9A2D63320E28fD287`](https://etherscan.io/address/0x0da7c263eCF5cD3ddba275b9A2D63320E28fD287)
#### JobsManager (Proxy)
* **V1**: [`0xbf07ff45f14c9ff0571b9fbdc7e2b62d29931224`](https://etherscan.io/address/0xbf07ff45f14c9ff0571b9fbdc7e2b62d29931224)
#### JobsManager (Target)
* **V1**: [`0x68b463bca7d561118636e9f028ff0f2e8398dd6a`](https://etherscan.io/address/0x68b463bca7d561118636e9f028ff0f2e8398dd6a)
* **V2**: [`0xB620c762dd4bC350602936d7401BB8393Ee6687c`](https://etherscan.io/address/0xB620c762dd4bC350602936d7401BB8393Ee6687c)
* **V3**: [`0x8eade5eec609572bf53deadb88d36f862ddec517`](https://etherscan.io/address/0x8eade5eec609572bf53deadb88d36f862ddec517)
#### RoundsManager (Target)
* **V1**: [`0xa3aa52ce79e85a21d9ccda705c57e426b160112c`](https://etherscan.io/address/0xa3aa52ce79e85a21d9ccda705c57e426b160112c)
* **V2**: [`0x857d4bf18a80f03d3d11f438825cd3d0aa0d9d68`](https://etherscan.io/address/0x857d4bf18a80f03d3d11f438825cd3d0aa0d9d68)
#### MerkleProof
* **V1**: [`0x289ba1701c2f088cf0faf8b3705246331cb8a839`](https://etherscan.io/address/0x289ba1701c2f088cf0faf8b3705246331cb8a839)
#### ECRecovery
* **V1**: [`0xd8e8328501e9645d16cf49539efc04f734606ee4`](https://etherscan.io/address/0xd8e8328501e9645d16cf49539efc04f734606ee4)
#### JobLib
* **V1**: [`0x4969dccf5186e1c49411638fc8a2a020fdab752e`](https://etherscan.io/address/0x4969dccf5186e1c49411638fc8a2a020fdab752e)
# Example Applications
Source: https://docs.livepeer.org/v1/references/example-applications
Curated collection of Livepeer example applications and integrations
Enjoy a curated collection of Livepeer example applications and integrations.
Use these starter projects to build your own video applications.
| Example | Description |
| -------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| [React Native Example App](https://github.com/suhailkakar/Livepeer-YouTube) | Example application which demonstrates how to use Livepeer React to create a React Native YouTube clone. |
| [Justcast.it](https://github.com/victorges/justcast.it) | Web app that provides code for adding "1-click starting a livestream" so that you can create a stream using the Livepeer API. |
| [EVM Token-Gated Livestream](https://github.com/suhailkakar/Livepeer-EVM-Tokengating) | Example application which demonstrates how to create and tokengate a livestream using Livepeer on EVM compatible chains. |
| [Decentralized storage playback](https://github.com/suhailkakar/livepeer-dStorage-playback/) | Example application which demonstrates how to play back a video from decentralized storage such as IPFS and Arweave using Livepeer. |
# Bandwidth Requirements
Source: https://docs.livepeer.org/v1/references/go-livepeer/bandwidth-requirements
The bandwidth requirements for video miners are based on the amount of video
data that needs to be uploaded and downloaded during transcoding.
The amount of available bandwidth will not only impact the number of streams
that can be transcoded on a machine, but also the speed of data upload/download
which needs to be fast so that video streaming applications can receive
transcoded results as soon as possible.
The amount of bandwidth required for a stream will depend on the bitrate of the
source stream and the bitrate of the output renditions. The download bandwidth
required for a single stream can be roughly estimated as the bitrate of the
source stream. The upload bandwidth required for a single stream can be roughly
estimated as the sum of the bitrates of each of the output renditions for the
stream. As a result, the total number of streams that can be transcoded given a
certain amount of available of bandwidth will vary.
While there is not a strict bandwidth requirement for video miners, past testing
has demonstrated that 1G upload/download bandwidth is a good starting point if
possible. If you do not have access to this amount of bandwidth you will still
be able to transcode on the network, but you will have a lower ceiling on the
number of streams you will be able to handle.
Upload/download bandwidth available can be tested with tools such as:
* [speedtest](https://www.speedtest.net/apps/cli)
* By default the tool will run a bandwidth test against the closest public
server, but there is also an option to run the test against a specified
public server
* Note: The results of this test also depend on the available bandwidth on the
server used
* [iperf3](https://iperf.fr/)
* This tool can be run on client and server machines that you have access to
* If you have access to a machine with good bandwidth availability in a region
that you expect/want to receive streams from, then this tool will likely be
more useful than speedtest
# CLI Reference
Source: https://docs.livepeer.org/v1/references/go-livepeer/cli-reference
The `livepeer` binary in `go-livepeer` has a number of configurable options. You
can set your configuration using command-line flags, environment variables, or a
config file.
A comprehensive list of options can be found below. They are sourced and
regularly updated from
[this file](https://github.com/livepeer/go-livepeer/blob/master/cmd/livepeer/livepeer.go).
The
[go-livepeer developer docs](https://github.com/livepeer/go-livepeer/tree/master/doc)
also contain instructions for using flags to enable certain functionality in
`livepeer`.
## Options
### Configuration
* config: Path to config file.
### Network and Addresses
* network: Network to connect to. Default `offchain`
* rtmpAddr: Address to bind for RTMP commands. Default `127.0.0.1:+RtmpPort`
* cliAddr: Address to bind for CLI commands. Default `127.0.0.1:+CliPort`
* httpAddr: Address to bind for HTTP commands. No default
* serviceAddr: Orchestrator only. Overrides the on-chain serviceURI that
gateways can use to contact this node; may be an IP or hostname. No default
* orchAddr: Orchestrator to connect to as a standalone transcoder. No default.
* verifierURL: URL of the verifier to use. No default.
* verifierPath: Path to verifier shared volume. No default.
* localVerify: Set to true to enable local verification i.e. pixel count and
signature verification. Default `true`. However, if you are running in
offchain mode, this will be set to false.
* httpIngest: Set to true to enable HTTP ingest. Default `true`. However, if (1)
you do not provide a value, (2) you provide a non-local URL for `httpAddr`,
and (3) you do not provide an `authWebhookURL`, this will be set to false.
### Transcoding
* orchestrator: Set to true to be an orchestrator. Default `false`
* transcoder: Set to true to be an transcoder. Default `false`
* gateway: Set to true to be an gateway (formerly known as *Broadcaster*).
Default `false`
* orchSecret: Shared secret with the orchestrator as a standalone transcoder or
path to file
* transcodingOptions: Transcoding options for broadcast job, or path to json
config. Default `P240p30fps16x9,P360p30fps16x9`
* maxAttempts: Maximum transcode attempts. Default `3`
* selectRandFreq: Frequency to randomly select unknown orchestrators (on-chain
mode only). Default `0.3`
* maxSessions: Maximum number of concurrent transcoding sessions for
Orchestrator, maximum number or RTMP streams for Gateway, or maximum capacity
for transcoder. Default `10`
* currentManifest: Expose the currently active ManifestID as
"/stream/current.m3u8". Default `false`
* nvidia: Comma-separated list of Nvidia GPU device IDs (or "all" for all
available devices). No default
* testTranscoder: Test Nvidia GPU transcoding at startup. Default `true`
* sceneClassificationModelPath: Path to scene classification model. No default
### Onchain
* ethAcctAddr: Existing Eth account address. For use when multiple ETH accounts
exist in the keystore directory
* ethPassword: Password for existing Eth account address or path to file
* ethKeystorePath: Path to ETH keystore directory or keyfile. If keyfile,
overrides -ethAcctAddr and uses parent directory
* ethOrchAddr: address of an on-chain registered orchestrator. No default
* ethUrl: EVM-compatible chain node JSON-RPC URL. No default
* txTimeout: Amount of time (ms) to wait for a transaction to confirm before
timing out. Default `300000 (5 mins)`
* maxTxReplacements: Number of times to automatically replace pending
transactions. Default `1`
* gasLimit: Gas limit for ETH transaction. Default `0`
* minGasPrice: Minimum gas price (priority fee + base fee) for ETH transactions
in wei, 10 Gwei = 10000000000. If not set, this will be the network's default
min gas fee.
* maxGasPrice: Maximum gas price (priority fee + base fee) for ETH transactions
in wei, 40 Gwei = 40000000000. Default `0`
* ethController: Protocol smart contract address. No default
* initializeRound: Set to true if running as a transcoder and the node should
automatically initialize new rounds. Default false.
* ticketEV: The expected value for PM tickets. Default `1000000000000`
* maxTicketEV: The maximum acceptable expected value for PM tickets. Default
`3000000000000`
* depositMultiplier: The deposit multiplier used to determine max acceptable
faceValue for PM tickets. Default `1`
* pricePerUnit: The price per 'pixelsPerUnit' amount pixels. Must be greater
than 0. Error if not set.
* maxPricePerUnit: The maximum transcoding price (in wei) per 'pixelsPerUnit' a
gateway is willing to accept. If not set explicitly, gateway is willing to
accept ANY price. Default `0`
* pixelsPerUnit: Amount of pixels per unit. Set to '> 1' to have smaller price
granularity than 1 wei / pixel. Default `1`
* pricePerGateway: json list of price per gateway or path to json config file.
Example:
`{"gateways":[{"ethaddress":"address1","priceperunit":1000,"pixelsperunit":1},{"ethaddress":"address2","priceperunit":1200,"pixelsperunit":1}]}`
* autoAdjustPrice: Enable/disable automatic price adjustments based on the
overhead for redeeming tickets. Default `true`
* blockPollingInterval: Interval in seconds at which different blockchain event
services poll for blocks. Default `5`
* redeemer: Set to true to run a ticket redemption service. Default `false`
* redeemerAddr: URL of the ticket redemption service to use. No default
* reward: Set to true to run a reward service. If you do not want to
automatically call `reward()`, you need to explicitly set this to `false` for
any node that's registered onchain. Otherwise, it will default to true.
* monitor: Set to true to send performance metrics. Default `false`
* version: Print out the version. Default `false`
* v: Log verbosity - . No default
* metadataQueueUri: URI for message broker to send operation metadata. No
default
* metadataAmqpExchange: Name of AMQP exchange to send operation metadata.
Default `lp_golivepeer_metadata`
* metadataPublishTimeout: Max time (ms) to wait in background for publishing
operation metadata events. Default `1000 (1s)`
* maxFaceValue: Set the maximum face value of a ticket (in wei). No default
### Storage
* datadir: Directory that data is stored in. No default
* objectstore: URL of primary object store. No default
* recordstore: URL of object store for recodings. No default
### API
* authWebhookURL: RTMP authentication webhook URL. No default
* orchWebhookURL: Orchestrator discovery callback URL. No default
* detectionWebhookURL: (Experimental) Detection results callback URL. No default
# GPU Support
Source: https://docs.livepeer.org/v1/references/go-livepeer/gpu-support
Livepeer enables node operators to transcode video on GPUs while concurrently
mining cryptocurrencies and performing other CUDA operations such as machine
learning. As there is a very wide range of GPU hardware out there, this document
aims to crowdsource a list of specific GPU models that have been tested and
verified to work on Livepeer. If you've tested an additional model, please
submit an update to this document.
## Overview
* Livepeer supports transcoding on NVIDIA GPUs with NVENC/NVDEC. Any GPU
[listed here](https://developer.nvidia.com/video-encode-and-decode-gpu-support-matrix-new)
with those chips should theoretically work. Note that different models may be
subject to different session limits that restrict the amount of video that can
be transcoded.
* See
[this document which lists tested driver versions](https://github.com/livepeer/go-livepeer/blob/master/doc/gpu.md)
on the NVIDIA cards.
| GPU Model | Tested Transcoding | Tested Concurrent Ethash Mining | Notes | |
| ----------------------------- | ------------------ | ------------------------------- | ------------------------------------------------------------------------------------------------------ | - |
| NVIDIA GeForce GTX 950 | ✅ | | [Benchmarks](https://forum.livepeer.org/t/gtx-950-quadro-p400-benchmarks/1497) | |
| NVIDIA GeForce GTX 1060 | ✅ | ✅ | | |
| NVIDIA GeForce GTX 1070 | ✅ | | | |
| NVIDIA GeForce GTX 1070 Ti | ✅ | ✅ | | |
| NVIDIA GeForce GTX 1080 | ✅ | | | |
| NVIDIA GeForce GTX 1080 Ti | ✅ | | | |
| NVIDIA Tesla T4 | ✅ | | | |
| NVIDIA GeForce GTX 1660 Ti | ✅ | | | |
| NVIDIA GeForce GTX 1660 SUPER | ✅ | | | |
| NVIDIA GeForce GTX 2080 Ti | ✅ | ✅ | | |
| NVIDIA GeForce RTX 3080 | ✅ | ✅ | [Benchmarks](https://forum.livepeer.org/t/dual-ethash-mining-transcoding-w-rtx-3080-10g-cuda-mps/1161) | |
| NVIDIA GeForce GTX 3090 | ✅ | ✅ | | |
| NVIDIA Titan V | ✅ | ✅ | | |
| NVIDIA Quadro P400 | ✅ | | [Benchmarks](https://forum.livepeer.org/t/gtx-950-quadro-p400-benchmarks/1497) | |
| NVIDIA Quadro T600 | ✅ | | [Benchmarks](https://forum.livepeer.org/t/nvidia-quadro-t600-benchmark/1650) | |
# Hardware Requirements
Source: https://docs.livepeer.org/v1/references/go-livepeer/hardware-requirements
The hardware requirements for video miners are based on the computational
resources required for transcoding.
## GPU
A GPU with a built-in hardware video encoder/decoder is **strongly** recommended
because it will significantly speed up transcoding and it will be difficult to
compete for work in the marketplace without one. Transcoding capacity will scale
with the number of GPUs available.
Currently, `livepeer` only supports Nvidia GPUs with
[NVENC (hardware video encoder) and NVDEC (hardware video decoder) support](https://developer.nvidia.com/video-encode-and-decode-gpu-support-matrix-new).
For a list of of GPUs that have been tested and that are known to be supported
by `livepeer`, see [this page](/references/go-livepeer/gpu-support).
## CPU
CPU transcoding using a software video encoder/decoder is possible, but not
recommended due to its significant speed disadvantage relative to GPU
transcoding. If you choose to do CPU transcoding (perhaps to try things out or
as a temporary measure until a GPU is available), generally a CPU with more
cores will improve transcoding speed.
## RAM
TBD.
## Disk
TBD.
# Prometheus Metrics
Source: https://docs.livepeer.org/v1/references/go-livepeer/prometheus-metrics
Livepeer exposes a number of metrics via the Prometheus exporter. This page
documents all metrics that you can scrape via the `/metrics` endpoint when the
[monitoring is enabled](/orchestrators/guides/monitor-metrics).
## Livepeer metrics
### General
| Name | Description | Node Type |
| -------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | ------------------------------------------- |
| `livepeer_versions` | Versions used by Livepeer node. | Gateway, Orchestrator, Transcoder, Redeemer |
| `livepeer_segment_source_appeared_total` | SegmentSourceAppeared | Gateway |
| `livepeer_segment_source_emerged_total` | SegmentEmerged | Gateway |
| `livepeer_segment_source_emerged_unprocessed_total` | Raw number of segments emerged from segmenter. | Gateway, Orchestrator |
| `livepeer_segment_source_uploaded_total` | SegmentUploaded | Gateway, Orchestrator, Transcoder |
| `livepeer_segment_source_upload_failed_total` | SegmentUploadedFailed | Gateway |
| `livepeer_segment_transcoded_downloaded_total` | SegmentDownloaded | Gateway, Orchestrator |
| `livepeer_segment_transcoded_total` | SegmentTranscoded | Gateway, Orchestrator |
| `livepeer_segment_transcoded_unprocessed_total` | Raw number of segments successfully transcoded. | Gateway |
| `livepeer_segment_transcode_failed_total` | SegmentTranscodeFailed | Gateway |
| `livepeer_segment_transcoded_all_appeared_total` | SegmentTranscodedAllAppeared | Gateway |
| `livepeer_stream_created_total` | StreamCreated | Gateway |
| `livepeer_stream_started_total` | StreamStarted | Gateway |
| `livepeer_stream_ended_total` | StreamEnded | Gateway |
| `livepeer_max_sessions_total` | Max Sessions | Gateway, Orchestrator, Transcoder, Redeemer |
| `livepeer_current_sessions_total` | Number of streams currently transcoding | Gateway, Orchestrator |
| `livepeer_discovery_errors_total` | Number of discover errors | Gateway |
| `livepeer_transcode_retried` | Number of times segment transcode was retried | Gateway |
| `livepeer_transcoders_number` | Number of transcoders currently connected to orchestrator | Gateway, Orchestrator, Transcoder, Redeemer |
| `livepeer_transcoders_capacity` | Total advertised capacity of transcoders currently connected to orchestrator | Gateway, Orchestrator, Transcoder, Redeemer |
| `livepeer_transcoders_load` | Total load of transcoders currently connected to orchestrator | Gateway, Orchestrator, Transcoder, Redeemer |
| `livepeer_success_rate` | Number of transcoded segments divided on number of source segments | Gateway, Orchestrator, Transcoder, Redeemer |
| `livepeer_success_rate_per_stream` | Number of transcoded segments divided on number of source segments, per stream | Gateway |
| `livepeer_transcode_time_seconds` | TranscodeTime, seconds | Gateway, Orchestrator |
| `livepeer_transcode_overall_latency_seconds` | Transcoding latency, from source segment emerged from segmenter till all transcoded segment apeeared in manifest | Gateway |
| `livepeer_upload_time_seconds` | UploadTime, seconds | Gateway, Orchestrator, Transcoder |
| `livepeer_download_time_seconds` | Download time | Gateway, Orchestrator |
| `livepeer_auth_webhook_time_milliseconds` | Authentication webhook execution time, milliseconds | Gateway |
| `livepeer_source_segment_duration_seconds` | Source segment's duration | Gateway, Orchestrator |
| `livepeer_http_client_timeout_1` | Number of times HTTP connection was dropped before transcoding complete | Gateway |
| `livepeer_http_client_timeout_2` | Number of times HTTP connection was dropped before transcoded segments was sent back to client | Gateway |
| `livepeer_http_client_segment_transcoded_realtime_ratio` | Ratio of source segment duration / transcode time as measured on HTTP client | Gateway |
| `livepeer_http_client_segment_transcoded_realtime_3x` | Number of segment transcoded 3x faster than realtime | Gateway |
| `livepeer_http_client_segment_transcoded_realtime_2x` | Number of segment transcoded 2x faster than realtime | Gateway |
| `livepeer_http_client_segment_transcoded_realtime_1x` | Number of segment transcoded 1x faster than realtime | Gateway |
| `livepeer_http_client_segment_transcoded_realtime_half` | Number of segment transcoded no more than two times slower than realtime | Gateway |
| `livepeer_http_client_segment_transcoded_realtime_slow` | Number of segment transcoded more than two times slower than realtime | Gateway |
| `livepeer_transcode_score` | Ratio of source segment duration vs. transcode time | Gateway, Orchestrator |
| `livepeer_recording_save_latency` | How long it takes to save segment to the OS | Gateway |
| `livepeer_recording_save_errors` | Number of errors during save to the recording OS | Gateway |
| `livepeer_recording_saved_segments` | Number of segments saved to the recording OS | Gateway |
| `livepeer_orchestrator_swaps` | Number of orchestrator swaps mid-stream | Gateway |
### Sending payments
| Name | Description | Node Type |
| -------------------------------- | ---------------------------------------------- | --------- |
| `livepeer_ticket_value_sent` | Ticket value sent | Gateway |
| `livepeer_tickets_sent` | Tickets sent | Gateway |
| `livepeer_payment_create_errors` | Errors when creating payments | Gateway |
| `livepeer_gateway_deposit` | Current remaining deposit for the gateway node | Gateway |
| `livepeer_gateway_reserve` | Current remaining reserve for the gateway node | Gateway |
### Receiving payments
| Name | Description | Node Type |
| ----------------------------------- | -------------------------------------------------- | ------------------------------- |
| `livepeer_ticket_value_recv` | Ticket value received | Orchestrator |
| `livepeer_tickets_recv` | Tickets received | Orchestrator |
| `livepeer_payment_recv_errors` | Errors when receiving payments | Orchestrator |
| `livepeer_winning_tickets_recv` | Winning tickets received | Orchestrator |
| `livepeer_value_redeemed` | Winning ticket value redeemed | Orchestrator, Redeemer |
| `livepeer_ticket_redemption_errors` | Errors when redeeming tickets | Orchestrator, Redeemer |
| `livepeer_suggested_gas_price` | Suggested gas price for winning ticket redemption | Gateway, Orchestrator, Redeemer |
| `livepeer_min_gas_price` | Minimum gas price to use for gas price suggestions | Gateway, Orchestrator, Redeemer |
| `livepeer_max_gas_price` | Maximum gas price to use for gas price suggestions | Gateway, Orchestrator, Redeemer |
| `livepeer_transcoding_price` | Transcoding price per pixel | Orchestrator |
### Pixel accounting
| Name | Description | Node Type |
| ------------------------------- | ------------------------ | --------------------- |
| `livepeer_mil_pixels_processed` | Million pixels processed | Gateway, Orchestrator |
### Fast verification
| Name | Description | Node Type |
| ----------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | --------- |
| `livepeer_fast_verification_done` | Number of fast verifications done | Gateway |
| `livepeer_fast_verification_failed` | Number of fast verifications failed | Gateway |
| `livepeer_fast_verification_enabled_current_sessions_total` | Number of currently transcoded streams that have fast verification enabled | Gateway |
| `livepeer_fast_verification_using_current_sessions_total` | Number of currently transcoded streams that have fast verification enabled and that are using an untrusted orchestrator | Gateway |
# Livestream
Source: https://docs.livepeer.org/v1/references/knowledge-base/livestream
Diagnose: We do not have a feature to livestream audio only, but it is being
planned. Visit our feature request page for updates.
[https://livepeer.canny.io/feature-requests](https://livepeer.canny.io/feature-requests) Workaround: Add `?video=false` to
the end of the playback URL. Ex.
[https://livepeercdn.com/hls/playbackId/index.m3u8?video=false](https://livepeercdn.com/hls/playbackId/index.m3u8?video=false)
Diagnose: This is supported but has not been thoroughly tested.
Workaround: When creating a stream, add the following to the profile:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"name": "1080p",
"bitrate": 5000000,
"fps": 30,
"width": 1920,
"height": 1080
}
```
Diagnose: At the moment, we do not offer closed captioning features.
Workaround: This has been added to the feature request [https://livepeer.canny.io/feature-requests/p/adding-subtitles-to-your-video-assets](https://livepeer.canny.io/feature-requests/p/adding-subtitles-to-your-video-assets)
Diagnose: You can suspend the stream
Workaround: Use either the API or SDK to suspend the stream. [https://docs.livepeer.org/reference/api#update-a-stream](https://docs.livepeer.org/reference/api#update-a-stream) or [https://docs.livepeer.org/reference/livepeer-js/stream/useUpdateStream#suspend](https://docs.livepeer.org/reference/livepeer-js/stream/useUpdateStream#suspend)
Diagnose: Yes, it is under the `sourceBytes` in the stream object.
Workaround: [https://docs.livepeer.org/reference/api#retrieve-a-stream](https://docs.livepeer.org/reference/api#retrieve-a-stream)
Diagnose: Short form videos need to use the MP4 playback as default
Workaround: Get the MP4 playback from the asset object and set it as the source. If you use the HLS instead for short form videos, this will affect the playback experience for users drastically.
Diagnose: If you're using livepeer.studio you can force a region.
Workaround: Replace the `rtmp://rtmp.livepeer.com/live/streamkey` with the region you want to force the broadcast to. Ex. `rtmp://sin-rtmp.livepeer.com/live/streamkey`, contact us for a list of regions available.
Diagnose: When creating a stream, set the profile object of the stream empty.
Workaround: `profile:[]`
Diagnose: You can use latency inject to increase the latency for a stream as a trade-off to reduce buffering.
Workaround: You add the query to the end of the playback URL in the amount of seconds you want to increase the latency. Ex. `&latency=10&buffer=10`
Diagnose: You can add a query to the end of the playback url.
Workaround: `?video=640x360,1m&pswait&trackcount=9`
# Playback
Source: https://docs.livepeer.org/v1/references/knowledge-base/playback
Diagnose: This is due to the low latency playback feature using WebRTC. If
there are bframes in the stream, the default behavior is to fallback to HLS
playback, which means a slight increase in latency. Workaround: In the
settings of the gateway, turn off the use of frames. If using OBS, select
Livepeer as the service for the video settings.
[https://docs.livepeer.org/guides/developing/stream-via-obs#input-your-stream-settings](https://docs.livepeer.org/guides/developing/stream-via-obs#input-your-stream-settings)
Diagnose: Reconnection: If a stream is down, attempt to retry for that stream
from other nodes nearby until there is a connection(using Livepeer player)
Workaround: Implement a retry logic or switch over to the Livepeer player with
the SDK or iframe embedded player.
Diagnose: We do not support pagination yet but it is a pending feature. You can use the playbackId as a workaround.
Workaround: A short term workaround could be to "paginate" by playbackId instead.
* First list all playback ids with: `/api/data/views/query?breakdownBy[]=playbackId`
* then viewers by playbackId with `/api/data/views/query?playbackId=&breakdownBy[]=viewerId`
Diagnose: Yes, you can use the iframe embedded player and set the width and
height in the iframe tag, however the best way to do this is to use the aspect
ratio.
There are two solutions to accomplish this:
1. If you are using react component, you can pass `lowLatency="force"` to the player component.
You can
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
2. If you are using the iframe embedded player, you can add `lowLatency=true` to
the query string. `lvpr.tv/?v={playbackid}&lowLatency=true`
You can use a poster image by default for a player, then, when playback info API returns the thumbnail url, you can start to use dynamic thumbnail for preview.
Here is how to set up a poster image in Player:
You can set the poster image for a video by utilizing the poster property in Livepeer’s Player component. This property can take either an image URL or a React component as its value.
To set the poster image with a URL, you can use the following code example:
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Player } from "@livepeer/react";
function PlayerComponent() {
return (
);
}
```
If you prefer using a React component, then you can create an image component
and pass it as a value to the poster property. Here is a code example that
illustrates how you can do this:
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
=
import { Player } from "@livepeer/react";
import Image from "next/image";
import yourPosterImage from "./images/your-image-file.png";
const PosterImageComponent = () => {
return (
);
};
function PlayerComponent() {
return (
}
/>
);
};
```
# Vod
Source: https://docs.livepeer.org/v1/references/knowledge-base/vod
Diagnose: The playback format is HLS and for any asset that is \< 2 minutes is MP4.
Workaround: N/A
Diagnose: You can use our webhook to get the status of an asset while it is
being uploaded. Workaround: You can use these events for asset statuses:
`asset.created` `asset.updated` `asset.ready` `asset.failed` `asset.deleted`
[https://docs.livepeer.org/guides/developing/listen-for-webhooks#request](https://docs.livepeer.org/guides/developing/listen-for-webhooks#request)
Diagnose: A new asset with a different Id will be created. Workaround: N/A
Diagnose: Check to make sure that the asset is not using access control.
Workaround: Check the playback information of the asset and make sure that the playback policy is set to `null` or `public`. Use the API endpoint to check: `https://livepeer.studio/api/playback/Playback_Id`
Diagnose: Anything with more than 1 video track will be reduced to 1 video
track. Workaround: N/A
Diagnose: Any other tracks and data types (subtitles/captions, metadata, track
titles, chapter data, etc) will be removed. Workaround: N/A
Diagnose: If the error specifies 401 or 403, this is indicating that there is
an issue with the credentials of your storage. Workaround: Make sure that the
storage credentials allow for both reading and writing to it.
Diagnose: If you close or refresh the page the video is being uploaded, this
can cause the asset to fail. Workaround: Do not refresh or close the page when
uploading with the Livepeer Studio dashboard, otherwise, it will cause the
asset to fail
Diagnose: Check to see if the asset had codecs that are being supported.
Workaround: No support for assets using VP9 codec in an MP4 container see our
[support matrix](https://docs.livepeer.org/references/api-support-matrix).
Diagnose: Make sure the asset is not over the size limit. Workaround: Only up
to 30GB file size is supported
Diagnose: Make sure that the amount of uploads is not exceeding the limit.
Workaround: Limited to 20 uploads at a time with 5 assets processing at the
same time
Diagnose: You can fetch usage of storage in a given time frame using the API
Workaround:
[https://livepeer.studio/data/usage/query?from=UNIX\_TIMESTAMP\_MILLISECONDS\&to=UNIX\_TIMESTAMP\_MILLISECONDS](https://livepeer.studio/data/usage/query?from=UNIX_TIMESTAMP_MILLISECONDS\&to=UNIX_TIMESTAMP_MILLISECONDS)
# AI Gateways
Source: https://docs.livepeer.org/v1/ai/builders/gateways
There are multiple AI gateways available in the Livepeer ecosystem that you can
use to interact with the Livepeer AI network. Each gateway has its own unique
features and capabilities. Here are some of the gateways that you can use to
interact with the Livepeer AI network.
}
>
The Livepeer Cloud Community Gateway, offered by [Livepeer Cloud
SPE](https://www.livepeer.cloud/), provides an effortless and free way to
experiment with the Livepeer AI network.
}
>
The [Livepeer Studio](https://livepeer.studio/) Gateway is a
production-ready solution for interacting with the Livepeer AI network,
offering advanced tools and resources for developers.
# Building on Livepeer AI
Source: https://docs.livepeer.org/v1/ai/builders/get-started
Livepeer AI, now in its **Beta** phase, is fully operational and already
powering a diverse range of cutting-edge [applications](/ai/builders/showcase).
Developers are actively building on the platform, with a rapidly growing
community. While the network continues to evolve with frequent updates, its
stable foundation offers an exciting space for innovation. With a variety of
[easy-to-use client SDKs](/ai/sdks/overview), developers can dive in and start
shaping the future of AI-powered solutions.
Discover the available AI pipelines.
Explore developer SDKs for interacting with the Livepeer AI API.
Choose an AI Gateway to interact with the AI Subnet.
Explore and interact with the Livepeer AI API.
Explore projects built on Livepeer AI.
# Showcase
Source: https://docs.livepeer.org/v1/ai/builders/showcase
If you would like your project to be featured, please contact us at
[ai@livepeer.org](mailto:ai@livepeer.org).
Several
[startups](https://mirror.xyz/livepeer.eth/XcpTZyAkc40kdQMGHZ7prAO7gnB2S1y45iacMtdzrII),
applications, and projects have been developed using Livepeer AI. Below are a
few that have agreed to be featured.
A mobile app that enables anyone to create **stunning gif expressions** with
generative AI, powered by the Livepeer network.
An open-source platform, built on **Stability-AI/StableStudio**, designed for
experimenting with all pipelines on the AI Subnet.
Create images and videos for **free** on the Livepeer network with this generator.
A robust open-source tool for testing and comparing the complete feature set
of Livepeers AI pipeline - including custom-built **experimental features**.
# Get Started
Source: https://docs.livepeer.org/v1/ai/contributors/coming-soon
Amazing that you decided to join our open-source community and help us
democratize AI! 🎉
All our software is open-source, and anyone can permissionlessly add their AI
compute job to the Livepeer network. We have a strong developer community with a
[core developer group](https://github.com/livepeer/project-management) and tens
of open-source developers. The best way to get in touch with this community and
start developing is by joining our [Discord](https://discord.gg/livepeer).
We also offer multiple opportunities for developers to get rewarded for their
contributions, such as our
[grants program](https://livepeer.notion.site/Livepeer-Grants-Program-f91071b5030d4c31ad4dd08e7c026526),
[software bounty program](https://github.com/livepeer/bounties), and
[bug bounty program](https://immunefi.com/bug-bounty/livepeer/information/) for
security researchers.
Let's build something amazing together! 🚀
Contribution guidelines are coming soon. In the meantime, join the `ai-video`
channel on the [Livepeer Discord](https://discord.gg/livepeer) for any
questions or assistance. Let's build something amazing together! 🚀
# Get Started
Source: https://docs.livepeer.org/v1/ai/gateways/get-started
If you're interested in joining Livepeer AI as a **Gateway** (formerly known as
a *Broadcaster*) to perform **AI inference task routing** and provide inference
services to customers, this guide is for you. It builds on the
[Gateway Setup Guide](/gateways/guides/gateway-overview) for the Mainnet
Transcoding Network, with additional steps specific to AI operations.
Dive into the **subpages** for a step-by-step walkthrough of the AI-specific
setup. For foundational knowledge on general Gateway operations, refer to the
[Gateway Setup Guide](/gateways/guides/gateway-overview). This guide extends it
with the steps needed for AI task routing.
Visit the Gateway Setup Guide for detailed instructions on setting up a
Gateway node on the Mainnet Transcoding Network.
## Prerequisites
Before you begin setting up your AI Gateway node, ensure you have:
* A [Linux](https://ubuntu.com/download/desktop) system (Support for Windows and
macOS coming soon)
* Root user access to the system
# Onchain
Source: https://docs.livepeer.org/v1/ai/gateways/onchain
### On-chain Setup
In the previous section, we covered the **off-chain** configuration of your AI
Gateway node. This section will explain how to connect your AI Gateway to the
Livepeer AI network to start requesting AI inference jobs **on-chain**.
## Prerequisites
* A dedicated static IP address or domain name for your AI Gateway node
* A funded Ethereum account with enough ETH to cover gas fees and AI inference
job payments
## Launching your On-chain AI Gateway
Once your AI Gateway is set up **off-chain**, it's time to connect it to the
Livepeer AI network for **on-chain** inference jobs. The process is similar to
setting up a Mainnet Transcoding Network Gateway, with a few extra flags
specific to Livepeer AI. You can refer to the
[Mainnet Transcoding Network Gateway](/gateways/guides/gateway-overview) guide
for more information. Here’s a summary of the key steps:
Ensure your AI Gateway node is functioning correctly **off-chain** before connecting it to the Livepeer AI network. Refer to [the previous section](/ai/gateways/start-gateway) for details.
Make sure your Ethereum account has enough ETH to cover gas fees and AI inference job payments. For more details, see the [Fund Gateway Guide](/gateways/guides/fund-gateway).
Deposit enough funds into your AI Gateway to cover the **deposit** and **reserve** needed for AI inference requests. Follow the steps in the [Deposit Gateway Funds via Livepeer CLI](/gateways/guides/fund-gateway#deposit-gateway-funds-via-livepeer-cli) guide.
Configure transcoding options even though the AI Gateway doesn’t handle transcoding, due to current Livepeer AI software requirements. See the [Transcoding Options](/gateways/guides/transcoding-options) guide for more information.
Now launch your AI Gateway node. The process is similar to the **docker** or **binary** setup in the [previous section](/ai/gateways/start-gateway), but requires additional flags to enable on-chain functionality. Example:
* `-aiServiceRegistry`: Ensures that the Gateway is connected to the Livepeer AI network.
* `-network=arbitrum-one-mainnet`: Connects the AI Gateway to the Arbitrum Mainnet network.
* `-ethUrl=https://arb1.arbitrum.io/rpc`: Sets the Arbitrum Mainnet RPC URL. Replace it with your own if necessary.
* `-ethKeystorePath=/root/.lpData/arbitrum-one-mainnet/keystore`: Sets the path to the Ethereum keystore file for the AI Gateway.
* `-ethAcctAddr `: Sets the Ethereum account address for the AI Gateway.
* `-ethPassword=/root/.lpData/.eth_secret`: Sets the path to the Ethereum keystore password file.
* `-ethOrchAddr=`: Sets the Ethereum address of the Mainnet Transcoding Network Gateway.
* `-maxTotalEV=100000000000000`: Ensures the AI Gateway complies with the max ticket value limits in `go-livepeer`.
* `-maxPricePerUnit=`: This defaults to 0. Set to acceptable max price in wei (or USD, e.g. 0.02USD) willing to pay. Note: this can impact amount of Orchestrators available to process the work.
* `-ignoreMaxPriceIfNeeded=`: This defaults to false. Set to true if want to process requests if no Orchestrators are under maxPricePerUnit or do not want to use a max price.
* `-maxPricePerCapability=/path/to/maxPrices.json`: This flag sets the max price per unit for one or many pipeline/models. Refer to the [Set Max Price Per Pipeline and Model](#set-max-price-per-pipeline-and-model-optional) section for more details.
## Set Max Price Per Pipeline and Model (Optional)
To avoid overpaying for AI inference jobs, you can set a maximum price per unit
for each pipeline and model. This feature is optional and can be configured
using the `-maxPricePerCapability` flag. If a price is not set for a specific
pipeline/model, the `-maxPricePerUnit` price will be used. The flag input should
be a JSON file with the specified max prices. The example below demonstrates the
following configurations:
* Set the price for the `image-to-image` pipeline and model
`ByteDance/SDXL-Lightning` to 1,700,000 wei per unit (pixels).
* Set the price for the `text-to-image` pipeline and model
`stabilityai/stable-diffusion-3-medium-diffusers` to 4,768,371 wei per unit
(pixels).
* Set the price for the `upscale` pipeline for all models to 4,768,371 wei per
unit. The `pixels_per_unit` defaults to `1` if not specified.
* Set the price for the `image-to-video` pipeline for all models to 3,390,842
wei per unit (pixels).
* Set the price for the `audio-to-text` pipeline for all models to 12,882,811
wei per unit (milliseconds of audio).
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"capabilities_prices": [
{
"pipeline": "image-to-image",
"model_id": "ByteDance/SDXL-Lightning",
"price_per_unit": 1700000,
"pixels_per_unit": 1
},
{
"pipeline": "text-to-image",
"model_id": "stabilityai/stable-diffusion-3-medium-diffusers",
"price_per_unit": 4768371,
"pixels_per_unit": 1
},
{
"pipeline": "upscale",
"model_id": "default",
"price_per_unit": 4768371
},
{
"pipeline": "image-to-video",
"price_per_unit": 3390842,
"pixels_per_unit": 1
},
{
"pipeline": "audio-to-text",
"price_per_unit": 12882811
}
]
}
```
# Start gateway
Source: https://docs.livepeer.org/v1/ai/gateways/start-gateway
### Start your AI Gateway
The Livepeer AI network is currently in **Beta** but is already integrated into
the main [go-livepeer](https://github.com/livepeer/go-livepeer) software. 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.
## Start the AI Gateway
Follow the steps below to start your Livepeer AI Gateway node:
Fetch the latest [Livepeer AI Docker image](https://hub.docker.com/r/livepeer/go-livepeer) with the following command:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
docker pull livepeer/go-livepeer:master
```
Run the Docker container for your AI Gateway node:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
docker run \
--name livepeer_ai_gateway \
-v ~/.lpData2/:/root/.lpData2 \
-p 8937:8937 \
--network host \
livepeer/go-livepeer:master \
-datadir ~/.lpData2 \
-gateway \
-orchAddr \
-httpAddr 0.0.0.0:8937 \
-v 6 \
-httpIngest
```
This command launches an **off-chain** AI Gateway node. The flags are similar to those used for a Mainnet Transcoding Network Gateway. See the [go-livepeer CLI reference](/references/go-livepeer/cli-reference) for details.
Upon successful startup, you should see output similar to:
```bash 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:8937
I0501 11:07:47.609963 1 lpms.go:92] LPMS Server listening on rtmp://127.0.0.1:1935
```
Ensure that port `8937` is open and accessible, and configure your router for port forwarding if necessary to make the Gateway accessible from the internet.
Download the latest Livepeer AI binary for your system:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
wget https://build.livepeer.live/go-livepeer/livepeer--.tar.gz
```
Replace `` and `` with your operating system and architecture (e.g., `linux-amd64` for Linux AMD64). For more details, see the [go-livepeer installation guide](/orchestrators/guides/install-go-livepeer#install-using-a-binary-release).
The Windows and MacOS (amd64) binaries of Livepeer AI are not available yet.
Once downloaded, extract the binary to a directory of your choice.
Start the AI Gateway node with the following command:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
./livepeer \
-datadir ~/.lpData2 \
-gateway \
-orchAddr \
-httpAddr 0.0.0.0:8937 \
-v 6 \
-httpIngest
```
This command launches an **off-chain** AI Gateway node. Refer to the [go-livepeer CLI reference](/references/go-livepeer/cli-reference) for more details on the flags.
Check the terminal for the following output to confirm successful startup:
```bash 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:8937
I0501 11:07:47.609963 1 lpms.go:92] LPMS Server listening on rtmp://127.0.0.1:1935
```
Ensure that port `8937` is open and accessible, and configure port forwarding if needed.
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 [Livepeer installation guide](/orchestrators/guides/install-go-livepeer#install-using-a-binary-release) or reach out to the Livepeer community on [Discord](https://discord.gg/livepeer) for assistance.
## Confirm the AI Gateway is Operational
After launching your Livepeer AI Gateway node, verify its operation by sending
an AI inference request. Ensure that the Gateway is connected to an active
**off-chain** AI Orchestrator node. For instructions on setting up an AI
Orchestrator, refer to the
[AI Orchestrator Setup Guide](/ai/orchestrators/get-started).
Start an AI Orchestrator node on port `8936` by following the [AI Orchestrator Setup Guide](/ai/orchestrators/get-started). Ensure that the Orchestrator has loaded the necessary model (e.g., "ByteDance/SDXL-Lightning").
Specify the Orchestrator's address when launching the Gateway. Replace `` with the Orchestrator's address:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
-orchAddr 0.0.0.0:8936
```
To submit an AI inference request, refer to the [AI API reference](/ai/api-reference/text-to-image). For example, to generate an image from text, use the following `curl` command:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -X POST "http://0.0.0.0:8937/text-to-image" \
-H "Content-Type: application/json" \
-d '{
"model_id":"ByteDance/SDXL-Lightning",
"prompt":"A cool cat on the beach",
"width": 1024,
"height": 1024
}'
```
If the request is successful, you should see a response like this:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"images": [
{
"seed": 2562822894,
"url": "https://0.0.0.0:8937/stream/d0fc1fc6/8fdf5a94.png"
}
]
}
```
Refer to the [Text-to-image Pipeline Documentation](/ai/pipelines/text-to-image) for more information.
# What is Livepeer AI?
Source: https://docs.livepeer.org/v1/ai/introduction
The Livepeer AI network is in its **Beta** phase. Bugs or issues may be
encountered. Contributions to improvement are appreciated - please report
problems via the [issue
tracker](https://github.com/livepeer/go-livepeer/issues/new/choose). Feedback
is invaluable for enhancing the Livepeer AI network. Thank you for your
contributions!
Livepeer AI, also known as the **Livepeer AI (Video) Network**, is the first
step toward bringing powerful AI video capabilities into the Livepeer network.
It enables video developers to add a rapidly growing suite of **generative AI
features** such as [text-to-image](/ai/pipelines/text-to-image),
[image-to-image](/ai/pipelines/image-to-image),
[image-to-video](/ai/pipelines/image-to-video), and
[upscaling](/ai/pipelines/upscale) to their applications. Livepeer Node
operators are able to **earn revenue by deploying their GPU resources** for AI
processing tasks. Ready to dive in? Choose one of the cards below to kickstart
your journey with the AI Subnet.
## Kickstart Your Journey
Explore the available AI pipelines.
Set up your AI Orchestrator node and earn fees from AI tasks.
Establish an AI Gateway to serve a broad customer base with AI tasks.
Develop your innovative app on the AI Subnet efficiently and at scale.
Discover projects built on the AI Subnet.
Explore developer SDKs for interacting with the Livepeer AI API.
Choose an AI Gateway to interact with the AI Subnet.
Explore the AI Subnet API to integrate AI capabilities into your projects.
## Background on Livepeer AI
Livepeer AI, initially proposed in
[this SPE treasury proposal](https://explorer.livepeer.org/treasury/82843445347363563575858115586375001878287509193479217286690041153234635982713),
represents a significant evolution within the Livepeer ecosystem. This
**decentralized**, **open-source** framework seamlessly integrates a variety of
**generative image and video AI inference** tasks into the existing Livepeer
network infrastructure. These enhancements strengthen Livepeer's transcoding
services, celebrated for their **low cost** and **high reliability**, while also
paving the way for groundbreaking applications across both emerging Web3
environments and established Web2 sectors.
Designed to revolutionize creative processes, Livepeer AI reflects Livepeer's
commitment to creating a **globally accessible open video infrastructure**. By
striving to **democratize AI**, Livepeer AI empowers users to leverage any form
of image and video compute with advanced AI tools. By equipping video
applications with these tools and reducing reliance on centralized computing
resources, we are dedicated to extending **cutting-edge AI capabilities** to a
broader audience, fostering a more equitable digital landscape. Additionally, we
are committed to
[supporting open-source research](https://livepeer.notion.site/Livepeer-Grants-Program-f91071b5030d4c31ad4dd08e7c026526)
by funding researchers who develop in the open, further driving innovation and
collaboration within the community.
### Advantages of Livepeer AI
* **Decentralization**: Enhances security and resilience by eliminating single
points of failure.
* **Cost-Effectiveness**: Provides AI inference capabilities at a significantly
lower cost compared to traditional cloud services.
* **Scalability**: Easily scales in response to user demand, ensuring reliable
service without interruptions.
* **Open-Source Innovation**: Encourages collaborative development, accelerating
innovation and broadening the range of supported applications.
### How It Works
Livepeer AI, built on the established Livepeer network, leverages a
**decentralized payment infrastructure** for compensating AI orchestrator nodes
for performing AI inference tasks. The network consists of two primary actors:
* **AI Gateway Nodes**: These nodes manage the flow of AI tasks from
applications and users, directing them to the appropriate Orchestrator nodes
based on capability and current load, ensuring efficient task allocation and
system scalability.
* **AI Orchestrator Nodes**: These nodes manage the execution of AI tasks. They
can perform AI inference tasks on GPUs located on the same machine or be
connected to multiple machines with multiple GPUs, known as **AI Worker
Nodes**. The orchestrator or its worker nodes keep AI models
[warm](/ai/pipelines/overview#warm-models) on their GPUs for immediate
processing and can
[dynamically load models](/ai/pipelines/overview#on-demand-models) as tasks
arrive, optimizing both response time and resource utilization.
This architecture is designed for **scalability**, enabling easy integration of
additional Orchestrator and Gateway nodes as demand increases. Under the hood,
it relies on a specialized
[ai-runner Docker](https://hub.docker.com/r/livepeer/ai-runner) image to execute
inference requests on AI models, simplifying deployment and enhancing the
scalability of new pipelines. Ongoing developments aim to enhance
**performance** and **broaden the container's capabilities** to support
increasingly complex AI models and custom user-defined pipelines.
Below is a simplified diagram illustrating the **complete AI inference
pipeline** within Livepeer AI. Only one AI Orchestrator with one GPU on the same
machine is shown for clarity. In reality, the AI Gateway is connected to
multiple Orchestrators, each of which can have multiple worker nodes with
various GPUs attached.
```mermaid theme={"theme":{"light":"github-light","dark":"dark-plus"}}
graph TD
A[AI Gateway Node] -->|Task Routing| B[AI Orchestrator Node]
B -->|Tasks Execution| C[ai-runner Docker Container]
C -->|Uses Pre-loaded Model| D[GPU Ready/Warm Models]
C -->|Dynamically Loads Model| E[GPU On-Demand]
D -->|Perform Inference| G[Task Completion]
E -->|Perform Inference| G
G -->|Return Results| B
B -->|Send Results Back| A
```
This flow starts at the AI Gateway nodes, which route tasks from applications or
users to an appropriate AI Orchestrator node. The selection of the AI
Orchestrator node is based on factors such as the speed of previous inference
requests, orchestrator stake, advertised price, and more. The AI Orchestrator
node then executes the task in the ai-runner Docker Container. In this
container, the AI Orchestrator can either:
* **Pre-load a model**: Orchestrators keep frequently used models
[warm](ai/pipelines/overview#warm-models) on GPUs, speeding up task
processing.
* **Dynamically load a model**: Orchestrators can
[load models on demand](ai/pipelines/overview#on-demand-models), allowing
flexibility to handle various tasks.
During the selection process, to ensure quick response times, Gateways first
check if there are any Orchestrators available with the requested model 'warm'
on their GPU. If not, they route the task to an Orchestrator that can
dynamically load the model. Once the model is loaded, the task is executed on
the GPU, and the results are returned to the Orchestrator node, which then sends
them back to the Gateway node and finally to the application or user that
requested the task. This architecture ensures Livepeer AI is both **efficient**
and **flexible**, ready to scale and adapt to various AI applications.
### Explore AI Pipelines
Livepeer AI hosts a variety of generative AI pipelines, each supporting
different models. Current offerings primarily utilize
[Diffusion models](https://huggingface.co/docs/diffusers/en/index). Plans are in
place to expand support to include other model types in future updates.
Explore the [AI Pipelines](/ai/pipelines) page to learn more about each
pipeline and the models they support.
### Current Limitations and Future Directions
* **Beta Phase**: Livepeer AI is currently in its **Beta** phase, and users may
encounter bugs or issues during this early stage. It is not yet intended for
high-demand production workloads.
* **Limited Set of Open-source Models Supported**: Livepeer AI currently
supports a limited set of open-source AI models and pipelines available on
[Hugging Face](https://huggingface.co/models). However, this range is
gradually expanding with the goal of supporting custom models in the future.
* **High VRAM GPUs Required for Most Pipelines**: Currently, Livepeer AI
requires GPUs with at least 16GB of VRAM to run most AI inference tasks
effectively. For optimal performance and a higher chance of being selected for
jobs, 30/40 series GPUs or comparable models are recommended. The exact GPU
requirements can be found in the documentation for each pipeline on the
[AI Pipelines](/ai/pipelines) page.
### Livepeer AI Terminology
* **Mainnet Transcoding Network**: Comprises **Orchestrator** and **Gateway**
nodes that perform or coordinate transcoding tasks. The **Orchestrator**
handles the supply-side operations, while the **Gateway** handles the
demand-side.
* **Livepeer AI Network**: A specialized subnet within the Livepeer network
designed for managing AI inference tasks, connecting **Providers**,
**Gateways**, **Orchestrators**, and **Workers** in a decentralized manner.
* **Mainnet Transcoding Network Orchestrator**: A node responsible for handling
transcoding jobs within the Mainnet Transcoding Network. The **Orchestrator**
is a supply-side node that coordinates and ensures the completion of
transcoding tasks. This term is distinct from the **Worker**, which executes
the actual compute jobs.
* **Mainnet Transcoding Network Gateway**: A node that acts as the
**clearinghouse** or middleware, responsible for routing transcoding tasks to
the appropriate **Orchestrator** nodes within the Mainnet Transcoding Network.
Often referred to as the **Gateway** (formerly **Broadcaster**), it remains
**stateless**, ensuring it only holds essential information for task routing
and job verification.
* **Provider**: An entity that operates one or more **Gateways**, potentially
with additional services or developer experience (DevX) abstractions layered
on top. **Providers** facilitate demand-side tasks in both the **Mainnet
Transcoding Network** and the **Livepeer AI Network**.
* **Worker**: Formerly referred to as the **Transcoder**, the **Worker** is a
node that executes compute jobs. This can be running on the same machine as
the **Orchestrator** or remotely. In the **Livepeer AI Network**, **Workers**
execute AI inference tasks, while in the **Mainnet Transcoding Network**, they
handle transcoding jobs.
* **AI Orchestrator**: A specialized node within the **Livepeer AI Network**,
responsible for executing AI inference tasks. The **AI Orchestrator** runs the
required software and handles compute jobs for AI tasks, coordinating with
**Workers** when needed.
* **AI Gateway**: A demand-side node within the **Livepeer AI Network**
responsible for directing AI-related tasks to the appropriate **AI
Orchestrator** nodes. Similar to the **Mainnet Gateway**, it does not manage
developer-related tasks (e.g., DevX persistence) and primarily handles job
instruction and verification for AI inference.
# Attach Remote AI Workers
Source: https://docs.livepeer.org/v1/ai/orchestrators/ai-worker
## Introduction
The **AI Worker** is a crucial component of the Livepeer AI network, responsible
for performing AI inference tasks. It can be run as a separate process on
compute machines distinct from the Orchestrator or combined with the
Orchestrator on the same machine.
## Key Setup Considerations
* **Startup Configuration**: If you decide to use separate AI Workers, this
**must** be selected at the Orchestrator's startup. A combined Orchestrator
**cannot** simultaneously support remote AI Workers.
* **Shared Configuration File**: Both the Orchestrator and AI Workers use the
`aiModels.json` file (see
[Configuring AI Models](/ai/orchestrators/models-config)).
* The **Orchestrator** uses `aiModels.json` to set model pricing.
* The **AI Worker** uses it to manage the runner containers for each model.
## Remote AI Worker Setup
When using experimental external runner containers, ensure they connect to the
AI Worker and not directly to the Orchestrator.
In a split configuration, the Orchestrator manages multiple AI Workers and
allocates tasks based on the connected workers' capacity. Worker **capacity** is
determined by the following formula:
```
runner container count per pipeline/model_id = capacity per pipeline/model_id
```
The **Orchestrator's capacity** is the sum of the capacities of all connected AI
Workers. This setup enables flexible scaling of compute resources by adding or
removing AI Workers as needed.
### Launch Commands for Remote AI Worker
Below are the launch commands for both the Orchestrator and AI Worker nodes.
For the full Orchestrator launch command, see [Start Your AI
Orchestrator](/ai/orchestrators/start-orchestrator).
#### Orchestrator Command
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
docker run \
--name livepeer_ai_orchestrator \
...
livepeer/go-livepeer:master \
-orchestrator \
...
-orchSecret
-serviceAddr
```
#### AI Worker Command
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
docker run \
--name livepeer_ai_worker \
...
livepeer/go-livepeer:master \
-aiWorker \
...
-orchSecret \
-orchAddr
```
**Pricing**: Prices in this example may vary and should be adjusted based on
market research and the operational costs of providing compute.
### Configuration Files (`aiModels.json`)
The `aiModels.json` file configures AI model parameters separately for the
Orchestrator and the AI Worker, with each configuration tailored to the specific
needs of that node.
For detailed guidance on configuring `aiModels.json` with advanced model
settings, see [Configuring AI Models](/ai/orchestrators/models-config).
#### Orchestrator Configuration
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
[
{
"pipeline": "text-to-image",
"model_id": "SG161222/RealVisXL_V4.0_Lightning",
"price_per_unit": 4768371,
"pixels_per_unit": 1
}
]
```
#### AI Worker Configuration
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
[
{
"pipeline": "text-to-image",
"model_id": "SG161222/RealVisXL_V4.0_Lightning",
"warm": true,
"optimization_flags": {
"SFAST": true
}
}
]
```
## Verifying Remote AI Worker Operation
After starting your **remote AI Worker** node, you can verify it is operational
by following the same inference test instructions used for the Orchestrator, as
described in the
[Orchestrator Confirmation Section](/ai/orchestrators/start-orchestrator#confirm-combined-ai-orchestrator-operation).
When accessing the AI Runner from a separate machine, replace `localhost` with
the **Worker Node's IP address** in the inference test instructions.
# Perform Benchmarking
Source: https://docs.livepeer.org/v1/ai/orchestrators/benchmarking
To ensure your GPU(s) are performing optimally and to identify any bottlenecks,
you can run a benchmark test. Optimal performance significantly increases your
chances of being selected for jobs, as inference speed is a crucial factor in
the selection process. This guide will show you how to run a benchmark test on
your GPU(s) to determine the best [pipeline/model](/ai/pipelines/overview)
combination to serve on your GPU(s), thereby maximizing your revenue.
## Prerequisites
Before running a benchmarking test, make sure you have met all the
[prerequisites](/ai/orchestrators/get-started#prerequisites) for running an
Orchestrator node.
## Benchmarking Steps
First, pull the latest AI runner Docker image from [Docker Hub](https://hub.docker.com/r/livepeer/ai-runner). This image contains the necessary tools for benchmarking.
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
docker pull livepeer/ai-runner:latest
```
Next, pull any pipeline-specific images if needed. Check the [pipelines](/ai/pipelines/overview) documentation for more information. For example, to pull the image for the [segment-anything-2](/ai/pipelines/segment-anything-2#pipeline-specific-image) pipeline:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
docker pull livepeer/ai-runner:segment-anything-2
```
Download the AI models you want to benchmark. For more information see the [Download AI Models](/ai/orchestrators/models-download) guide.
Run the benchmark test using the following command. This will simulate the pipeline/model combination on your GPU(s) and measure performance.
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
docker run --gpus -v ./models:/models livepeer/ai-runner:latest python bench.py --pipeline --model_id --runs --num_inference_steps --batch_size
```
Example command:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
docker run --gpus '"device=0"' -v ./models:/models livepeer/ai-runner:latest python bench.py --pipeline text-to-image --model_id stabilityai/sd-turbo --runs 3 --batch_size 3
```
In this command, the following parameters are used:
* ``: Specify which GPU(s) to use. For example, `'"device=0"'` for GPU 0, `'"device=0,1"'` for GPU 0 and GPU 1, or `'"device=all"'` for all GPUs.
* ``: The pipeline to benchmark (e.g., `text-to-image`).
* ``: The model ID to use for benchmarking (e.g., `stabilityai/sd-turbo`).
* ``: The number of benchmark runs to perform.
* ``: The number of inference steps to perform (optional).
For benchmarking script usage information:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
docker run livepeer/ai-runner:latest python bench.py -h
```
After running the benchmark, you should see output similar to the following:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
----AGGREGATE METRICS----
pipeline load time: 5.199s
pipeline load max GPU memory allocated: 5.876GiB
pipeline load max GPU memory reserved: 6.043GiB
avg inference time: 7.538s
avg inference max GPU memory allocated: 6.407GiB
avg inference max GPU memory reserved: 6.729GiB
```
This output shows the performance of your GPU(s) and helps you determine the best pipeline/model combination to serve on your GPU(s).
# Get Started
Source: https://docs.livepeer.org/v1/ai/orchestrators/get-started
If you're interested in joining Livepeer AI as an **Orchestrator** to perform
**AI inference** on the Livepeer AI Network and earn fees, this guide is for
you. It is tailored to help you set up an AI Orchestrator node, building upon
the [Orchestrator Setup Guide](/orchestrators/guides/get-started) for the
Mainnet Transcoding Network, but with additional steps for AI operations.
For a step-by-step walkthrough, refer to the **subpages** of this guide. For a
more general understanding of Orchestrator operations, you can consult the
[Orchestrator Setup Guide](/orchestrators/guides/get-started) for the Mainnet
Transcoding Network, as the AI guide extends upon the foundational knowledge
provided there.
Visit the Orchestrator Setup Guide for detailed instructions on setting up an
Orchestrator node on the Mainnet Transcoding Network.
## Prerequisites
Before setting up your AI Orchestrator node, ensure you meet the following
requirements:
* You are operating a Top 100
[Mainnet Orchestrator](/orchestrators/guides/get-started) on the Mainnet
Transcoding Network
* **High VRAM GPUs Required**: Livepeer AI requires GPUs with at least 16GB of
VRAM for most tasks. For optimal performance and higher job selection chances,
30/40 series GPUs or comparable models are recommended. Exact requirements are
in the [AI Pipelines](/ai/pipelines) documentation.
* **[Docker](https://docs.docker.com/engine/install)** is installed on your
machine
* **[CUDA 12.4](https://developer.nvidia.com/cuda-12-4-0-download-archive)** is
installed on your machine
* **[Nvidia Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html)**
is installed on your machine
* You are using a **[Linux](https://ubuntu.com/download/desktop)** system
(Support for Windows and macOS is coming soon)
* You have
**[Python 3.10](https://www.python.org/downloads/release/python-3100/)** or
higher installed (for downloading and managing AI models)
# Configuring AI Models
Source: https://docs.livepeer.org/v1/ai/orchestrators/models-config
Before deploying your AI Orchestrator node on the Livepeer AI network, you must
choose the AI models you want to serve for AI inference tasks. This guide
assists in configuring these models. The following page,
[Download AI Models](/ai/orchestrators/models-download), provides instructions
for their download. For details on supported pipelines and models, refer to
[Pipelines](/ai/pipelines/text-to-image).
## Configuration File Format
Orchestrators specify supported AI models in an `aiModels.json` file, typically
located in the `~/.lpData` directory. Below is an example configuration showing
currently **recommended** models and their respective prices.
Pricing used in this example is subject to change and should be set
competitively based on market research and costs to provide the compute.
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
[
{
"pipeline": "text-to-image",
"model_id": "SG161222/RealVisXL_V4.0_Lightning",
"price_per_unit": 4768371
},
{
"pipeline": "upscale",
"model_id": "stabilityai/stable-diffusion-x4-upscaler",
"price_per_unit": "0.5e-2USD",
"warm": true,
"optimization_flags": {
"SFAST": true,
"DEEPCACHE": false
}
},
{
"pipeline": "audio-to-text",
"model_id": "openai/whisper-large-v3",
"price_per_unit": 12882811,
"pixels_per_unit": 1,
"currency": "USD",
"url": ":",
"token": "",
"capacity": 1
}
]
```
### Key Configuration Fields
During the **Beta** phase, only one "warm" model per GPU is supported.
The inference pipeline to which the model belongs (e.g., `text-to-image`).
The [Hugging Face model
ID](https://huggingface.co/docs/transformers/en/main_classes/model).
The price in [Wei](https://ethdocs.org/en/latest/ether.html) per unit, which
varies based on the pipeline (e.g., per pixel for `image-to-video`).
If `true`, the model is preloaded on the GPU to decrease runtime.
Optional flags to enhance performance (details below).
Optional URL and port where the model container or custom container manager
software is running. [See External Containers](#external-containers)
Optional token required to interact with the model container or custom
container manager software. [See External Containers](#external-containers)
Optional capacity of the model. This is the number of inference tasks the
model can handle at the same time. This defaults to 1. [See External
Containers](#external-containers)
### Optimization Flags
These flags are still **experimental** and may not always perform as expected.
If you encounter any issues, please report them to the [go-livepeer
repository](https://github.com/livepeer/go-livepeer/issues/new/choose).
At this time, these flags are only compatible with **warm** models.
The Livepeer AI pipelines offer a suite of optimization flags. These are
designed to enhance the performance of **warm** models by either increasing
**inference speed** or reducing **VRAM** usage. Currently, the following flags
are available:
#### Image-to-video Pipeline Optimization
The `SFAST` flag enables the [Stable
Fast](https://github.com/chengzeyi/stable-fast) optimization framework,
potentially boosting inference speed by up to **25%** with **no quality
loss**. Cannot be used in conjunction with `DEEPCACHE`.
#### Text-to-image Pipeline Optimization
**DO NOT** enable `DEEPCACHE` for Lightning/Turbo models since they're already
optimized. Due to [known
limitations](https://github.com/horseee/DeepCache/issues/27), it does not
provide speed benefits and may significantly lower image quality.
The `DEEPCACHE` flag enables the
[DeepCache](https://github.com/horseee/DeepCache) optimization framework,
which can enhance inference speed by up to **50%** with **minimal quality
loss**. The speedup becomes more pronounced as the number of inference steps
increases. Cannot be used simultaneously with `SFAST`.
### External Containers
This feature is intended for advanced users. Incorrect setup can lead to a
lower orchestrator score and reduced fees. If external containers are used, it
is the Orchestrator's responsibility to ensure the correct container with the
correct endpoints is running behind the specified `url`.
External containers can be for one model to stack on top of managed model
containers, an auto-scaling GPU cluster behind a load balancer or anything in
between. Orchestrators can use external containers to extend the models served
or fully replace the AI Worker managed model containers using the
[Docker client Go library](https://pkg.go.dev/github.com/docker/docker/client)
to start and stop containers specified at startup of the AI Worker.
External containers can be used by specifying the `url`, `capacity` and `token`
fields in the model configuration. The only requirement is that the `url`
specified responds as expected to the AI Worker same as the managed containers
would respond (including http error codes). As long as the container management
software acts as a pass through to the model container you can use any container
management software to implement the custom management of the runner containers
including [Kubernetes](https://kubernetes.io/), [Podman](https://podman.io/),
[Docker Swarm](https://docs.docker.com/engine/swarm/),
[Nomad](https://www.nomadproject.io/), or custom scripts to manage container
lifecycles based on request volume
* The `url` set will be used to confirm a model container is running at startup
of the AI Worker using the `/health` endpoint. Inference requests will be
forwarded to the `url` same as they are to the managed containers after
startup.
* The `capacity` should be set to the maximum amount of requests that can be
processed concurrently for the pipeline/model id (default is 1). If auto
scaling containers, take care that the startup time is fast if setting
`warm: true` because slow response time will negatively impact your selection
by Gateways for future requests.
* The `token` field is used to secure the model container `url` from
unauthorized access and is strongly suggested to use if the containers are
exposed to external networks.
We welcome feedback to improve this feature, so please reach out to us if you
have suggestions to enable better experience running external containers.
# Download AI Models
Source: https://docs.livepeer.org/v1/ai/orchestrators/models-download
AI Orchestrators on the Livepeer AI network can choose from various AI models to
advertise on the network. A comprehensive list of currently supported models for
each Livepeer AI pipeline is available on the [Pipelines](/ai/pipelines) page.
Before specifying which models to advertise on the Livepeer AI network, you must
first download the models to your machine. The following steps will guide you
through downloading the **recommended** models for Livepeer AI.
Use the following command to install the HuggingFace CLI:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
pip install huggingface_hub
```
Follow the instructions on the [Hugging Face website](https://huggingface.co/docs/hub/en/security-tokens) to generate an access token with **read** permissions. Then, use the Hugging Face CLI to install the token:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
hf auth login
```
You will be prompted to paste the access token you created on the Hugging Face website.
If you have trouble locating `hf` in your path, it may be necessary to add `/home/$USER/.local/bin/` to your local path.
The currently recommended models include one **gated** model. Therefore, you must accept the terms of the [SVD1.1 model](https://huggingface.co/stabilityai/stable-video-diffusion-img2vid-xt-1-1) on its model page before downloading.
Use the following command to download the **recommended** models for Livepeer AI:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
cd ~/.lpData
latest=$(curl -s https://api.github.com/repos/livepeer/ai-runner/releases/latest | grep '"tag_name":' | cut -d'"' -f4)
curl -s https://raw.githubusercontent.com/livepeer/ai-runner/tags/$latest/runner/dl_checkpoints.sh | bash -s -- --beta
```
This command downloads the recommended models for Livepeer AI and stores them in your machine's `~/.lpData/models` directory. To obtain a complete set of models, omit the `--beta` flag. This will require additional disk space.
# On-chain Setup
Source: https://docs.livepeer.org/v1/ai/orchestrators/onchain
Contract addresses in this guide may be outdated. For current verified addresses, see:
**[Livepeer Contract Addresses](/v2/about/resources/livepeer-contract-addresses)**
The previous section covered the **off-chain** configuration of the AI
Orchestrator node. This section details how to connect an AI Orchestrator node
to the Livepeer AI network and earn fees for processing AI inference jobs.
## Prerequisites
* An established [Mainnet Orchestrator](/orchestrators/guides/get-started)
within the Top 100 on the Livepeer network
* A dedicated static IP address or domain name for your AI Orchestrator node
* An Ethereum wallet funded with enough ETH to cover transaction fees for ticket
redemption
## Ensure you can Redeem Tickets
The Livepeer AI network is currently in **Beta** but is already integrated into
the main [go-livepeer](https://github.com/livepeer/go-livepeer) software.
However, it still uses a separate port for the AI Orchestrator. This means that
your **Mainnet Transcoding Network Orchestrator** is currently unable to
directly redeem AI-related tickets. There are two methods to enable your AI
Orchestrator node to redeem tickets:
To enable ticket redemption for your **AI Orchestrator**, set the ticket recipient to your **Mainnet Transcoding Network Orchestrator**'s Ethereum address. This method allows the earned fees to be credited directly to your main Orchestrator without requiring additional setup or causing disruption.
For security, it's advised to use a separate account from your **Mainnet Transcoding Network Orchestrator**.
Create a new Ethereum wallet for your **AI Orchestrator**. Follow the [Wallet Creation](/orchestrators/guides/get-started#automatic-eth-account-creation) guide in the [Orchestrator](/orchestrators/guides/get-started) documentation for detailed instructions.
Transfer sufficient ETH to the new wallet to cover the gas costs for redeeming AI tickets on-chain.
To direct the fees earned by your AI Orchestrator to your main Orchestrator, set the ticket recipient as the Ethereum address of your main Orchestrator. This can be done by adding the following flag when launching your AI Orchestrator node:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
./livepeer \
-ethOrchAddr \
... \
```
While this method is possible, it's not recommended because it can disrupt performance and add complexity to your **Mainnet Transcoding Network Orchestrator**. Only proceed with this method if you are unable to create a separate wallet for your **AI Orchestrator** and understand the potential implications.
If creating a separate wallet for your **AI Orchestrator** isn't an option, you might want to use a [redemption service](https://github.com/livepeer/go-livepeer/blob/master/doc/redeemer.md). This service allows your **Mainnet Transcoding Network Orchestrator** to redeem tickets for your AI Orchestrator. For more details, check out the [redemption service documentation](https://github.com/livepeer/go-livepeer/blob/master/doc/redeemer.md) and the [go-livepeer CLI documentation](/references/go-livepeer/cli-reference#onchain).
## Advertising Your AI Service URI
To make your AI Orchestrator node discoverable by AI Gateway nodes on the
Livepeer AI network, you need to advertise your **AI service URI** on-chain. You
can do this by registering your service URI with the
[AIServiceRegistry](https://arbiscan.io/address/0x04C0b249740175999E5BF5c9ac1dA92431EF34C5)
contract on the [Arbitrum Mainnet](https://arbitrum.io).
The easiest and recommended method is to use the [Foundry](https://book.getfoundry.sh/getting-started/installation) smart contract deployment toolchain.
Install [Foundry Cast](https://book.getfoundry.sh/cast/) by executing the following commands in your terminal:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -L https://foundry.paradigm.xyz | bash
source /home//.bashrc
foundryup
```
No need to move your **Mainnet Transcoding Network Orchestrator** wallet. You can run Foundry Cast and register your AI Orchestrator from any machine.
Set your Service URI, ensuring it starts with `https://`, using the `SetServiceURI` function on the [AIServiceRegistry](https://arbiscan.io/address/0x04C0b249740175999E5BF5c9ac1dA92431EF34C5) contract. Use the KeyStore file and password from your **Mainnet Transcoding Network Orchestrator** wallet:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
cast send --keystore '' --password '' --rpc-url 0x04C0b249740175999E5BF5c9ac1dA92431EF34C5 "setServiceURI(string)" https://:
```
After successful execution, the output should look like this:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
blockHash: 0x214a65d2dffd1732e971bd3662dcb681663c2eb0c95a33c8918bab0a44e2d3ed
blockNumber: 200370198
```
Verify your Service URI by invoking the `getServiceURI` function on the [AIServiceRegistry](https://arbiscan.io/address/0x04C0b249740175999E5BF5c9ac1dA92431EF34C5) contract:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
cast call --rpc-url 0x04C0b249740175999E5BF5c9ac1dA92431EF34C5 "getServiceURI(address)" | xxd -r -p
```
If successful, the output should be:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
https://:
```
Congratulations! Your **AI Orchestrator** node is now discoverable by **AI Gateway** nodes and ready to execute AI inference tasks on the Livepeer AI network! 🚀
If you prefer to interact with the contract through your browser, use the [Arbitrum Explorer](https://arbiscan.io/address/0x04C0b249740175999E5BF5c9ac1dA92431EF34C5) to call the `setServiceURI` function on the [AIServiceRegistry](https://arbiscan.io/address/0x04C0b249740175999E5BF5c9ac1dA92431EF34C5) contract.
Import the Ethereum wallet associated with your **Mainnet Transcoding Network Orchestrator** into your wallet browser extension. The steps to import your wallet may vary depending on the extension you are using. The steps for MetaMask can be found [here](https://support.metamask.io/hc/en-us/articles/360015489331-How-to-import-an-account).
Visit the [AIServiceRegistry](https://arbiscan.io/address/0x04C0b249740175999E5BF5c9ac1dA92431EF34C5) contract page on the Arbitrum Explorer and click on the `Contract` tab.
On the contract page, click the `Write Contract` button and connect your wallet to the Arbitrum Explorer by clicking the `Connect to Web3` button. Then, select the wallet you imported in the first step.
Access the [setServiceURI](https://arbiscan.io/address/0x04C0b249740175999E5BF5c9ac1dA92431EF34C5#writeContract#F2) function on the contract page and input the **Service URI** for your AI Orchestrator in the `_serviceURI` field. Make sure the Service URI starts with `https://`. After clicking the `Write` button to execute the function, you must confirm the transaction in your wallet extension. Once the transaction is confirmed, your AI Orchestrator's Service URI will
be successfully set.
To verify that the Service URI has been set correctly, click the `Read Contract` button on the contract page. Access the [getServiceURI](https://arbiscan.io/address/0x04C0b249740175999E5BF5c9ac1dA92431EF34C5#readContract#F2) function and input the address of your **Mainnet Transcoding Network Orchestrator** in the `_addr` field. Click the `Query` button to retrieve the Service URI set for your AI Orchestrator.
Congratulations! Your AI Orchestrator node is now discoverable by **AI Gateway** nodes and ready to execute AI inference tasks on the Livepeer AI network! 🚀
Currently, setting your AI service URI using the Livepeer CLI is not supported during the **Beta** phase of the Livepeer AI network. This feature is planned for future releases.
## Launch your On-chain AI Orchestrator
Once you've set your AI service URI on-chain, you can launch your AI
Orchestrator node to start processing AI inference jobs on the Livepeer AI
network. The commands to start the AI Orchestrator are similar to those for the
[off-chain Orchestrator](/ai/orchestrators/start-orchestrator), but with
additional flags to enable on-chain functionality:
* `-AIServiceRegistry`: Ensures that the Orchestrator is connected to the
Livepeer AI network.
* `-network=arbitrum-one-mainnet`: Connects the AI Orchestrator node to the
Arbitrum Mainnet network.
* `-ethUrl=https://arb1.arbitrum.io/rpc`: Sets the Arbitrum Mainnet RPC URL. You
can replace this with your own RPC URL.
* `-ethKeystorePath=/root/.lpData/arbitrum-one-mainnet/keystore`: Sets the path
to the AI Orchestrator's Ethereum keystore file.
* `-ethAcctAddr `: Sets the Ethereum address of the AI
Orchestrator.
* `-ethPassword=/root/.lpData/.eth_secret`: Sets the Ethereum keystore password
file path.
* `-ethOrchAddr=`: Sets the Ethereum address of the
Mainnet Transcoding Network Orchestrator.
Due to current limitations in the Livepeer AI software, the following flag is
required:
* `-ticketEV=2999999999999`: This flag ensures that the AI Orchestrator doesn't
trigger maximum ticket limits set by the `go-livepeer` software.
# Start your AI Orchestrator
Source: https://docs.livepeer.org/v1/ai/orchestrators/start-orchestrator
The Livepeer AI network is currently in its **Beta** stage and is undergoing
active development. Running it on the same machine as your main Orchestrator
or Gateway node may cause stability issues. Please proceed with caution.
The Livepeer AI network is currently in **Beta** but is already integrated into
the main [go-livepeer](https://github.com/livepeer/go-livepeer) software. 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.
## Orchestrator Node Architecture
In the Livepeer AI network, orchestrator operations rely on two primary **node
types**:
* **Orchestrator**: Manages and routes incoming jobs to available compute
resources.
* **Worker**: Performs the actual computation tasks.
The simplest configuration combines both roles on a single machine, utilizing
the machine's GPUs for AI inference tasks, where the orchestrator also functions
as a worker (known as a **combined AI orchestrator**). In this setup, capacity
is limited by the available GPUs and is set as
`runner container count per pipeline/model_id = capacity per pipeline/model_id`.
For expanded scalability, operators can deploy dedicated (remote) worker nodes
that connect to the orchestrator, increasing overall compute capacity.
Instructions for setting up remote workers are available on the
[next page](/ai/orchestrators/ai-worker).
## Start a Combined AI Orchestrator
Please follow the steps below to start your **combined AI orchestrator** node.
Fetch the latest Livepeer AI Docker image from the [Livepeer Docker Hub](https://hub.docker.com/r/livepeer/go-livepeer) with the following command:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
docker pull livepeer/go-livepeer:master
```
The Livepeer AI network employs a [containerized workflow](https://www.ibm.com/topics/containerization) for running AI models. Fetch the latest [AI Runner](https://hub.docker.com/r/livepeer/ai-runner) image with this command:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
docker pull livepeer/ai-runner:latest
```
Next, pull any pipeline-specific images if needed. Check the [pipelines](/ai/pipelines/overview) documentation for more information. For example, to pull the image for the [segment-anything-2](/ai/pipelines/segment-anything-2#pipeline-specific-image) pipeline:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
docker pull livepeer/ai-runner:segment-anything-2
```
The Livepeer AI network leverages pre-trained AI models for inference tasks. Before launching the AI Orchestrator node, verify that the weights of these models are accessible on your machine. For more information, visit the [Download AI Models](/ai/orchestrators/models-download) page.
Confirm that the AI models are correctly set up in the `aiModels.json` file in the `~/.lpData/` directory. For guidance on configuring the `aiModels.json` file, refer to the [AI Models Configuration](/ai/orchestrators/models-config) page. The configuration file should resemble:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
[
{
"pipeline": "text-to-image",
"model_id": "ByteDance/SDXL-Lightning",
"price_per_unit": 4768371,
"warm": true
}
]
```
Execute the Livepeer AI Docker image using the following command:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
docker run \
--name livepeer_ai_orchestrator \
-v ~/.lpData/:/root/.lpData/ \
-v /var/run/docker.sock:/var/run/docker.sock \
--network host \
--gpus all \
livepeer/go-livepeer:master \
-orchestrator \
-serviceAddr 0.0.0.0:8936 \
-v 6 \
-nvidia 0 \
-aiWorker \
-aiModels /root/.lpData/aiModels.json \
-aiModelsDir ~/.lpData/models \
-aiRunnerImage livepeer/ai-runner:latest # OPTIONAL
```
This command launches an **off-chain** AI Orchestrator node. While most of the commands are similar to those used when operating a Mainnet Transcoding Network Orchestrator node (explained in the [go-livepeer CLI reference](/references/go-livepeer/cli-reference)), there are a few **Livepeer AI** specific flags:
* `-aiWorker`: This flag enables the AI Worker functionality.
* `-aiModels`: This flag sets the path to the JSON file that contains the AI models.
* `-aiModelsDir`: This flag indicates the directory where the AI models are stored on the host machine.
* `-aiRunnerImage`: This optional flag specifies which version of the ai-runner image is used. Example: `livepeer/ai-runner:0.0.2`
Moreover, the `--network host` flag facilitates communication between the AI Orchestrator and the AI Runner container.
Lastly, the `-nvidia` can be configured in a few ways. Use a comma seperated list of GPUs ie. `0,1` to activate specific GPU slots, each GPU will need it's own config item in `aiModels.json`. Alternativly we can use `"all"` to activate all GPUs on the machine with a single model loaded in `aiModels.json` (Warning: If different RAM size GPUs are installed it may cause containers to fail if they have less than the required RAM).
Please note that since we use [docker-out-of-docker](https://tdongsi.github.io/blog/2017/04/23/docker-out-of-docker/), the `aiModelsDir` path should be defined as being on the host machine.
If your Livepeer AI Orchestrator node is functioning correctly, you should see the following output:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
2024/05/01 09:01:39 INFO Starting managed container gpu=0 name=text-to-image_ByteDance_SDXL-Lightning modelID=ByteDance/SDXL-Lightning
...
I0405 22:03:17.427058 2655655 rpc.go:301] Connecting RPC to uri=https://0.0.0.0:8936
I0405 22:03:17.430371 2655655 rpc.go:254] Received Ping request
```
To make your Livepeer AI Orchestrator node accessible from the internet, you need to configure your network settings. Ensure that port `8936` is unblocked on your machine. Additionally, consider setting up port forwarding on your router, allowing the Gateway node to be reachable from the internet.
Download the latest Livepeer AI binary for your system:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
wget https://build.livepeer.live/go-livepeer/livepeer--gpu-.tar.gz
```
Replace `` and `` with your system's operating system and architecture. For example, for a Linux system with an AMD64 architecture, the command would be:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
wget https://build.livepeer.live/go-livepeer/livepeer-linux-gpu-amd64.tar.gz
```
See the [go-livepeer installation guide](/orchestrators/guides/install-go-livepeer#install-using-a-binary-release) for more information on the available binaries.
The Windows and MacOS (amd64) binaries of **Livepeer AI** are not available yet.
Once downloaded, extract the binary to a directory of your choice.
The Livepeer AI network employs a [containerized workflow](https://www.ibm.com/topics/containerization) for running AI models. Fetch the latest [AI Runner](https://hub.docker.com/r/livepeer/ai-runner) image with this command:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
docker pull livepeer/ai-runner:latest
```
Next, pull any pipeline-specific images if needed. Check the [pipelines](/ai/pipelines/overview) documentation for more information. For example, to pull the image for the [segment-anything-2](/ai/pipelines/segment-anything-2#pipeline-specific-image) pipeline:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
docker pull livepeer/ai-runner:segment-anything-2
```
The Livepeer AI network leverages pre-trained AI models for inference tasks. Before launching the AI Orchestrator node, verify that the weights of these models are accessible on your machine. For more information, visit the [Download AI Models](/ai/orchestrators/models-download) page.
Confirm that the AI models are correctly set up in the `aiModels.json` file in the `~/.lpData/` directory. For guidance on configuring the `aiModels.json` file, refer to the [AI Models Configuration](/ai/orchestrators/models-config) page. The configuration file should resemble:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
[
{
"pipeline": "text-to-image",
"model_id": "ByteDance/SDXL-Lightning",
"price_per_unit": 4768371,
"warm": true
}
]
```
Run the following command to start your Livepeer AI Orchestrator node:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
./livepeer \
-orchestrator \
-serviceAddr 0.0.0.0:8936 \
-v 6 \
-nvidia "all" \
-aiWorker \
-aiModels ~/.lpData/aiModels.json \
-aiModelsDir ~/.lpData/models \
-aiRunnerImage livepeer/ai-runner:latest # OPTIONAL
```
This command launches an **off-chain** AI Orchestrator node. While most of the commands are similar to those used when operating a Mainnet Transcoding Network Orchestrator node (explained in the [go-livepeer CLI reference](/references/go-livepeer/cli-reference)), there are a few **Livepeer AI** specific flags:
* `-aiWorker`: This flag enables the AI Worker functionality.
* `-aiModels`: This flag sets the path to the JSON file that contains the AI models.
* `-aiModelsDir`: This flag indicates the directory where the AI models are stored.
* `-aiRunnerImage`: This optional flag specifies which version of the ai-runner image is used. Example: `livepeer/ai-runner:0.0.2`
If your Livepeer AI Orchestrator node is functioning correctly, you should see the following output:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
2024/05/01 09:01:39 INFO Starting managed container gpu=0 name=text-to-image_ByteDance_SDXL-Lightning modelID=ByteDance/SDXL-Lightning
...
I0405 22:03:17.427058 2655655 rpc.go:301] Connecting RPC to uri=https://0.0.0.0:8936
I0405 22:03:17.430371 2655655 rpc.go:254] Received Ping request
```
To make your Livepeer AI Orchestrator node accessible from the internet, you need to configure your network settings. Ensure that port `8936` is unblocked on your machine. Additionally, consider setting up port forwarding on your router, allowing the Gateway node to be reachable from the internet.
If no binaries are available 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 by following the instructions in the [Livepeer repository](/orchestrators/guides/install-go-livepeer) or by reaching out to the Livepeer community on [Discord](https://discord.gg/livepeer).
## Verify Combined AI Orchestrator Operation
Once your **combined Livepeer AI Orchestrator** node is running, verify that the
worker is operational by sending an AI inference request directly to the
[ai-runner](https://hub.docker.com/r/livepeer/ai-runner) container. You can
either use the [Swagger UI](https://fastapi.tiangolo.com/features/) interface or
a `curl` command for this check.
Open your web browser and navigate to `http://localhost:8000/docs` to access the Swagger UI interface.
In the Swagger UI, locate the `POST /text-to-image` endpoint and click the `Try it out` button. Use the following example JSON payload:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"prompt": "A cool cat on the beach."
}
```
This request will instruct the AI model to generate an image based on the text in the `prompt` field.
If the AI Orchestrator node is functioning correctly, you should receive a response similar to the following:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"images": [
{
"url": "data:image/png;base64,iVBORw0KGgoAA...",
"seed": 2724904334
}
]
}
```
The `url` field contains the base64 encoded image generated by the AI model. To convert this image to PNG, use a base64 decoder such as [Base64.guru](https://base64.guru/converter/decode/image/png).
Alternatively, you can use the `curl` command to test the AI inference capabilities directly. Run the following command, replacing `` with the IP address of your worker node:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -X POST "http://localost:8000/text-to-image" -H "Content-Type: application/json" -d '{"prompt": "A cool cat on the beach."}'
```
This sends a POST request to the `text-to-image` endpoint on the worker node with the specified JSON payload.
If the AI Worker node is functioning correctly, you should receive a response similar to this:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"images": [
{
"url": "data:image/png;base64,iVBORw0KGgoAA...",
"seed": 2724904334
}
]
}
```
As with the Swagger UI response, the `url` field contains a base64 encoded image that can be decoded into PNG format using a tool like [Base64.guru](https://base64.guru/converter/decode/image/png).
# Audio-to-Text
Source: https://docs.livepeer.org/v1/ai/pipelines/audio-to-text
## Overview
The `audio-to-text` pipeline converts audio from media files into text,
utilizing cutting-edge diffusion models from HuggingFace's
[automatic-speech-recognition (ASR) pipeline](https://huggingface.co/models?pipeline_tag=automatic-speech-recognition).
## Models
### Warm Models
The current warm model requested for the `audio-to-text` pipeline is:
* [openai/whisper-large-v3](https://huggingface.co/openai/whisper-large-v3):
Whisper is a pre-trained model for automatic speech recognition (ASR) and
speech translation.
For faster responses with different
[audio-to-text](https://huggingface.co/models?pipeline_tag=automatic-speech-recognition)
diffusion models, ask Orchestrators to load it on their GPU via the `ai-video`
channel in [Discord Server](https://discord.gg/livepeer).
### On-Demand Models
The following models have been tested and verified for the `audio-to-text`
pipeline:
If a specific model you wish to use is not listed, please submit a [feature
request](https://github.com/livepeer/ai-worker/issues/new?assignees=\&labels=enhancement%2Cmodel\&projects=\&template=model_request.yml)
on GitHub to get the model verified and added to the list.
* [openai/whisper-large-v3](https://huggingface.co/openai/whisper-large-v3): A high-performance ASR model by Open AI.
## Basic Usage Instructions
For a detailed understanding of the `audio-to-text` endpoint and to experiment
with the API, see the [Livepeer AI API
Reference](/ai/api-reference/audio-to-text).
To create an audio transcript using the `audio-to-text` pipeline, submit a
`POST` request to the Gateway's `audio-to-text` API endpoint:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -X POST "https:///audio-to-text" \
-F model_id=openai/whisper-large-v3 \
-F audio=@
```
In this command:
* `` should be replaced with your AI Gateway's IP address.
* `model_id` is the diffusion model for audio transcription.
* `audio` is the path to the audio file to be transcribed.
- Supported file types: `mp4`, `webm`, `mp3`, `flac`, `wav` and `m4a` -
Maximum request size: 50 MB
For additional optional parameters, refer to the
[Livepeer AI API Reference](/ai/api-reference/audio-to-text).
After execution, the Orchestrator processes the request and returns the response
to the Gateway:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"chunks": [
{
"text": " Explore the power of automatic speech recognition",
"timestamp": [0, 1.35]
},
{
"text": " By extracting the text from audio",
"timestamp": [1.35, 2.07]
}
],
"text": " Explore the power of automatic speech recognition By extracting the text from audio"
}
```
## Orchestrator Configuration
To configure your Orchestrator to serve the `audio-to-text` pipeline, refer to
the [Orchestrator Configuration](/ai/orchestrators/get-started) guide.
### System Requirements
The following system requirements are recommended for optimal performance:
* [NVIDIA GPU](https://developer.nvidia.com/cuda-gpus) with **at least 12GB** of
VRAM.
## Recommended Pipeline Pricing
We are planning to simplify the pricing in the future so orchestrators can set
one AI price per compute unit and have the system automatically scale based on
the model's compute requirements.
The pricing for the `audio-to-text` pipeline is based on competitor pricing.
However, we strongly encourage orchestrators to set their own pricing based on
their costs and requirements. Setting a competitive price will help attract more
jobs, as Gateways can set their maximum price for a job. The currently
recommended pricing for this pipeline is `0.02e-6 USD` per **milliseconds** of
audio input.
## API Reference
Explore the `audio-to-text` endpoint and experiment with the API in the
Livepeer AI API Reference.
# Image-to-Image
Source: https://docs.livepeer.org/v1/ai/pipelines/image-to-image
## Overview
The `image-to-image` pipeline of the Livepeer AI network enables **advanced
image manipulations** including style transfer, image enhancement, and more.
This pipeline leverages cutting-edge diffusion models from the HuggingFace
[image-to-image](https://huggingface.co/models?pipeline_tag=image-to-image)
pipeline.
```mermaid theme={"theme":{"light":"github-light","dark":"dark-plus"}}
graph LR
A[
] --> B[Gateway]
E["A hat"] --> B
B --> C[Orchestrator]
C --> B
B --> D[
]
```
## Models
### Warm Models
The current warm model requested for the `image-to-image` pipeline is:
* [timbrooks/instruct-pix2pix](https://huggingface.co/timbrooks/instruct-pix2pix):
A powerful diffusion model that edits images to a high-quality standard based
on human-written instructions.
For faster responses with different
[image-to-image](https://huggingface.co/models?pipeline_tag=image-to-image)
diffusion models, ask Orchestrators to load it on their GPU via the `ai-video`
channel in [Discord Server](https://discord.gg/livepeer).
### On-Demand Models
The following models have been tested and verified for the `image-to-image`
pipeline:
If a specific model you wish to use is not listed, please submit a [feature
request](https://github.com/livepeer/ai-worker/issues/new?assignees=\&labels=enhancement%2Cmodel\&projects=\&template=model_request.yml)
on GitHub to get the model verified and added to the list.
* [timbrooks/instruct-pix2pix](https://huggingface.co/timbrooks/instruct-pix2pix): A powerful diffusion model that edits images to a high-quality standard based on human-written instructions.
* [ByteDance/SDXL-Lightning](https://huggingface.co/ByteDance/SDXL-Lightning): A lightning-fast diffusion model by ByteDance, optimized for high-speed image-to-image transformations.
* [SG161222/RealVisXL\_V4.0](https://huggingface.co/SG161222/RealVisXL_V4.0): A diffusion model that excels in generating high-quality, photorealistic images.
* [SG161222/RealVisXL\_V4.0\_Lightning](https://huggingface.co/SG161222/RealVisXL_V4.0_Lightning): A streamlined version of RealVisXL\_V4.0, designed for faster inference while still aiming for photorealism.
* [stabilityai/sd-turbo](https://huggingface.co/stabilityai/sd-turbo): A robust diffusion model by Stability AI, designed for efficient and high-quality image generation ([limited-commercial use license](https://stability.ai/license)).
* [stabilityai/sdxl-turbo](https://huggingface.co/stabilityai/sdxl-turbo): An extended version of the sd-turbo model, offering enhanced performance for larger and more complex tasks ([limited-commercial use license](https://stability.ai/license)).
## Basic Usage Instructions
For a detailed understanding of the `image-to-image` endpoint and to
experiment with the API, see the [Livepeer AI API
Reference](/ai/api-reference/image-to-image).
To generate an image with the `image-to-image` pipeline, send a `POST` request
to the Gateway's `image-to-image` API endpoint:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -X POST https:///image-to-image \
-F model_id="timbrooks/instruct-pix2pix" \
-F image=@/cool-cat.png \
-F prompt="a hat"
```
In this command:
* `` should be replaced with your AI Gateway's IP address.
* `model_id` is the diffusion model for image generation.
* The `image` field holds the **absolute** path to the image file to be
transformed.
* `prompt` is the text description for the image.
For additional optional parameters, refer to the
[Livepeer AI API Reference](/ai/api-reference/image-to-image).
After execution, the Orchestrator processes the request and returns the response
to the Gateway:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"images": [
{
"nsfw": false,
"seed": 3197613440,
"url": "https:///stream/dd5ad78d/7adde483.png"
}
]
}
```
The `url` in the response is the URL of the generated image. Download the image
with:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -O "https:///stream/dd5ad78d/7adde483.png"
```
## Applying LoRa Models
To apply LoRa filters to an image, include the `loras` field in your request:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -X POST https:///image-to-image \
-F model_id="ByteDance/SDXL-Lightning" \
-F image=@/cool-cat.png \
-F prompt="a hat" \
-F loras='{ "nerijs/pixel-art-xl": 1.2 }'
```
You can find a list of available LoRa models for various models on
[lora-studio](https://huggingface.co/spaces/enzostvs/lora-studio).
## Orchestrator Configuration
To configure your Orchestrator to serve the `image-to-image` pipeline, refer to
the [Orchestrator Configuration](/ai/orchestrators/get-started) guide.
### System Requirements
The following system requirements are recommended for optimal performance:
* [NVIDIA GPU](https://developer.nvidia.com/cuda-gpus) with **at least 20GB** of
VRAM.
## Recommended Pipeline Pricing
We are planning to simplify the pricing in the future so orchestrators can set
one AI price per compute unit and have the system automatically scale based on
the model's compute requirements.
The pricing for the `image-to-image` pipeline is based on competitor pricing.
However, we strongly encourage orchestrators to set their own pricing based on
their costs and requirements. Setting a competitive price will help attract more
jobs, as Gateways can set their maximum price for a job. The current recommended
pricing for this pipeline is `1.9073484e-08 USD` per **input pixel**
(`height * width * output images`).
## API Reference
Explore the `image-to-image` endpoint and experiment with the API in the
Livepeer AI API Reference.
# Image-to-Text
Source: https://docs.livepeer.org/v1/ai/pipelines/image-to-text
## Overview
The `image-to-text` pipeline converts images into text captions. This pipeline
is powered by the latest models in the HuggingFace
[text-to-image](https://huggingface.co/models?pipeline_tag=text-to-image)
pipeline.
## Models
### Warm Models
The current warm model requested for the `image-to-text` pipeline is:
* [Salesforce/blip-image-captioning-large](https://huggingface.co/Salesforce/blip-image-captioning-large)
For faster responses with different
[image-to-text](https://huggingface.co/models?pipeline_tag=text-to-image)
diffusion models, ask Orchestrators to load it on their GPU via the `ai-video`
channel in [Discord Server](https://discord.gg/livepeer).
### On-Demand Models
The following models have been tested and verified for the `image-to-text`
pipeline:
If a specific model you wish to use is not listed, please submit a [feature
request](https://github.com/livepeer/ai-worker/issues/new?assignees=\&labels=enhancement%2Cmodel\&projects=\&template=model_request.yml)
on GitHub to get the model verified and added to the list.
* [Salesforce/blip-image-captioning-large](https://huggingface.co/Salesforce/blip-image-captioning-large)
## Basic Usage Instructions
For a detailed understanding of the `image-to-text` endpoint and to experiment
with the API, see the [Livepeer AI API
Reference](/ai/api-reference/image-to-text).
To create an image caption using the `image-to-text` pipeline, submit a `POST`
request to the Gateway's `image-to-text` API endpoint:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -X POST "https:///image-to-text" \
-F model_id=Salesforce/blip-image-captioning-large \
-F image=@
```
In this command:
* `` should be replaced with your AI Gateway's IP address.
* `model_id` is the diffusion model to use.
* `image` is the path to the image file to be captioned.
Maximum request size: 50 MB
For additional optional parameters, refer to the
[Livepeer AI API Reference](/ai/api-reference/image-to-text).
## Orchestrator Configuration
To configure your Orchestrator to serve the `image-to-text` pipeline, refer to
the [Orchestrator Configuration](/ai/orchestrators/get-started) guide.
### System Requirements
The following system requirements are recommended for optimal performance:
* [NVIDIA GPU](https://developer.nvidia.com/cuda-gpus) with **at least 4GB** of
VRAM.
## Recommended Pipeline Pricing
We are planning to simplify the pricing in the future so orchestrators can set
one AI price per compute unit and have the system automatically scale based on
the model's compute requirements.
The pricing for the `image-to-text` pipeline is based on competitor pricing.
However, we strongly encourage orchestrators to set their own pricing based on
their costs and requirements. Setting a competitive price will help attract more
jobs, as Gateways can set their maximum price for a job. The current recommended
pricing for this pipeline is `2.5e-10 USD` per **input pixel**
(`height * width`).
## API Reference
Explore the `image-to-text` endpoint and experiment with the API in the
Livepeer AI API Reference.
# Image-to-Video
Source: https://docs.livepeer.org/v1/ai/pipelines/image-to-video
## Overview
The `image-to-video` pipeline of the Livepeer AI network allows you to generate
animated **high-quality** videos from images. This pipeline is powered by the
latest diffusion models in the HuggingFace
[image-to-video](https://huggingface.co/models?pipeline_tag=image-to-video)
pipeline.
```mermaid theme={"theme":{"light":"github-light","dark":"dark-plus"}}
graph LR
A[
] --> B[Gateway]
B --> C[Orchestrator]
C --> B
B --> D[
]
```
## Models
### Warm Models
The current warm model requested for the `image-to-video` pipeline is:
* [stabilityai/stable-video-diffusion-img2vid-xt-1-1](https://huggingface.co/stabilityai/stable-video-diffusion-img2vid-xt-1-1):
An updated version of the stable-video-diffusion-img2vid-xt model with
enhanced performance
([limited-commercial use license](https://stability.ai/license)).
For faster responses with different
[image-to-video](https://huggingface.co/models?pipeline_tag=image-to-video)
diffusion models, ask Orchestrators to load it on their GPU via the `ai-video`
channel in [Discord Server](https://discord.gg/livepeer).
### On-Demand Models
The following models have been tested and verified for the `image-to-video`
pipeline:
If a specific model you wish to use is not listed, please submit a [feature
request](https://github.com/livepeer/ai-worker/issues/new?assignees=\&labels=enhancement%2Cmodel\&projects=\&template=model_request.yml)
on GitHub to get the model verified and added to the list.
* [stable-video-diffusion-img2vid-xt](https://huggingface.co/stabilityai/stable-video-diffusion-img2vid-xt):
A model by Stability AI designed for stable video diffusion from images ([limited-commercial use license](https://stability.ai/license)).
* [stabilityai/stable-video-diffusion-img2vid-xt-1-1](https://huggingface.co/stabilityai/stable-video-diffusion-img2vid-xt-1-1):
An updated version of the stable-video-diffusion-img2vid-xt model with enhanced performance ([limited-commercial use license](https://stability.ai/license)).
## Basic Usage Instructions
For a detailed understanding of the `image-to-video` endpoint and to
experiment with the API, see the [Livepeer AI API
Reference](/ai/api-reference/image-to-video).
To generate a video with the `image-to-video` pipeline, send a `POST` request to
the Gateway's `image-to-video` API endpoint:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -X POST "https:///image-to-video" \
-F model_id=stabilityai/stable-video-diffusion-img2vid-xt-1-1 \
-F image=@
```
In this command:
* `` should be replaced with your AI Gateway's IP address.
* `model_id` is the diffusion model for video generation.
* The `image` field holds the **absolute** path to the image file to be
transformed.
For additional optional parameters, refer to the
[Livepeer AI API Reference](/ai/api-reference/image-to-video).
After execution, the Orchestrator processes the request and returns the response
to the Gateway:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"images": [
{
"nsfw": false,
"seed": 1914955328,
"url": "/stream/2b835716/01c0e9a6.mp4"
}
]
}
```
The `url` in the response is the URL of the generated video. Download the video
with:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -O "https:///stream/2b835716/01c0e9a6.mp4"
```
## Orchestrator Configuration
To configure your Orchestrator to serve the `image-to-video` pipeline, refer to
the [Orchestrator Configuration](/ai/orchestrators/get-started) guide.
### System Requirements
The following system requirements are recommended for optimal performance:
* [NVIDIA GPU](https://developer.nvidia.com/cuda-gpus) with **at least 24GB** of
VRAM.
## Recommended Pipeline Pricing
We are planning to simplify the pricing in the future so orchestrators can set
one AI price per compute unit and have the system automatically scale based on
the model's compute requirements.
The pricing for the `image-to-video` pipeline is based on competitor pricing.
However, we strongly encourage orchestrators to set their own pricing based on
their costs and requirements. Setting a competitive price will help attract more
jobs, as Gateways can set their maximum price for a job. The current recommended
pricing for this pipeline is `1.3563368e-08 USD` per **output pixel**
(`height * width * frames`).
## API Reference
Explore the `image-to-video` endpoint and experiment with the API in the
Livepeer AI API Reference.
# LLM
Source: https://docs.livepeer.org/v1/ai/pipelines/llm
## Overview
The `llm` pipeline provides an OpenAI-compatible interface for text generation,
designed to integrate seamlessly into media workflows.
## Models
The `llm` pipeline supports **any Hugging Face-compatible LLM model**. Since
models evolve quickly, the set of warm (preloaded) models on Orchestrators
changes regularly.
To see which models are currently available, check the
[Network Capabilities dashboard](https://tools.livepeer.cloud/ai/network-capabilities).\
At the time of writing, the most commonly available model is
[meta-llama/Meta-Llama-3.1-8B-Instruct](https://huggingface.co/meta-llama/Llama-3.1-8B-Instruct).
For faster responses with different
[LLM](https://huggingface.co/models?pipeline_tag=text-generation) models, ask
Orchestrators to load it on their GPU via the `ai-research` channel in
[Discord Server](https://discord.gg/livepeer).
## Basic Usage Instructions
For a detailed understanding of the `llm` endpoint and to experiment with the
API, see the [Livepeer AI API Reference](/ai/api-reference/llm).
To generate text with the `llm` pipeline, send a `POST` request to the Gateway's
`llm` API endpoint:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -X POST "https:///llm" \
-H "Authorization: Bearer " \
-H "Content-Type: application/json" \
-d '{
"model": "meta-llama/Meta-Llama-3.1-8B-Instruct",
"messages": [
{ "role": "user", "content": "Tell a robot story." }
]
}'
```
In this command:
* `` should be replaced with your AI Gateway's IP address.
* `` should be replaced with your API token if required by the AI
Gateway.
* `model` is the LLM model to use for generation.
* `messages` is the conversation or prompt input for the model.
For additional optional parameters such as `temperature`, `max_tokens`, or
`stream`, refer to the [Livepeer AI API Reference](/ai/api-reference/llm).
After execution, the Orchestrator processes the request and returns the response
to the Gateway which forwards the response in response to the request.
Example partial non-streaming response below:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"id": "chatcmpl-abc123",
"model": "meta-llama/Meta-Llama-3.1-8B-Instruct",
"choices": [
{
"message": {
"role": "assistant",
"content": "Once upon a time, in a gleaming city of circuits..."
}
}
]
}
```
By default, responses are returned as a single JSON object. To stream output
token-by-token using **Server-Sent Events (SSE)**, set `"stream": true` in the
request body.
## Orchestrator Configuration
To configure your Orchestrator to serve the `llm` pipeline, refer to the
[Orchestrator Configuration](/ai/orchestrators/get-started) guide.
### Tuning Environment Variables
The `llm` pipeline supports several environment variables that can be adjusted
to optimize performance based on your hardware and workload. These are
particularly helpful for managing memory usage and parallelism when running
large models.
Enables 8-bit quantization using `bitsandbytes` for lower memory usage. Set to
`true` to enable. Defaults to `false`.
Number of pipeline parallel stages. Defaults to `1`.
Number of tensor parallel units. Must divide evenly into the number of
attention heads in the model. Defaults to `1`.
Maximum number of tokens per input sequence. Defaults to `8192`.
Maximum number of tokens processed in a single batch. Should be greater than
or equal to `MAX_MODEL_LEN`. Defaults to `8192`.
Maximum number of sequences processed per batch. Defaults to `128`.
Target GPU memory utilization as a float between `0` and `1`. Higher values
make fuller use of GPU memory. Defaults to `0.85`.
### System Requirements
The following system requirements are recommended for optimal performance:
* [NVIDIA GPU](https://developer.nvidia.com/cuda-gpus) with **at least 16GB** of
VRAM.
## Recommended Pipeline Pricing
We are planning to simplify the pricing in the future so orchestrators can set
one AI price per compute unit and have the system automatically scale based on
the model's compute requirements.
The `/llm` pipeline is currently priced based on the **maximum output tokens**
specified in the request — not actual usage — due to current payment system
limitations. We're actively working to support usage-based pricing to better
align with industry standards.
The LLM pricing landscape is highly competitive and rapidly evolving.
Orchestrators should set prices based on their infrastructure costs and
[market positioning](https://llmpricecheck.com/). As a reference, inference on
`llama-3-8b-instruct` is currently around `0.08 USD` per 1 million **output
tokens**.
## API Reference
Explore the `llm` endpoint and experiment with the API in the Livepeer AI API
Reference.
# Overview
Source: https://docs.livepeer.org/v1/ai/pipelines/overview
The Livepeer AI network offers a variety of **generative AI pipelines** that
applications can use to request AI inference jobs on the Livepeer network.
Currently, the focus is on Diffusion models developed using Huggingface's
[Diffusers library](https://huggingface.co/docs/diffusers/en/index), but future
updates will extend support to other model types. This section introduces the
available pipelines, the models they support, and provides a basic usage
example. For a comprehensive guide on integrating the Livepeer AI network into
your application, refer to the
[Building on Livepeer AI](/ai/builders/get-started) section.
## Models on the Livepeer AI network
### Warm Models
During the **Beta** phase of the Livepeer AI network, Orchestrators are
encouraged to keep at least **one model** per pipeline active on their GPUs
("warm models"). This approach ensures quicker response times for **early
builders**. We're optimizing GPU model loading/unloading to relax this
requirement. The current warm models for each pipeline are listed on their
respective pages.
For faster responses with different [Diffusion
models](https://huggingface.co/docs/diffusers/en/index), request Orchestrators
to load it on their GPU via the `ai-video` channel in [Discord
Server](https://discord.gg/livepeer).
### On-Demand Models
Orchestrators can theoretically load **any**
[diffusion model](https://huggingface.co/docs/diffusers/en/index) from
[Hugging Face](https://huggingface.co/models) on-demand, optimizing GPU
resources by loading models only when needed. However, during the **Beta**
phase, Orchestrators need to pre-download a model.
If a specific model you wish to use is not listed on the respective pipeline
page, submit a [feature
request](https://github.com/livepeer/ai-worker/issues/new?assignees=\&labels=enhancement%2Cmodel\&projects=\&template=model_request.yml)
on GitHub to get the model verified and added to the list.
## Generative AI Pipelines
The Livepeer AI network currently supports the following generative AI
pipelines:
The audio-to-text pipeline uses automatic speech recognition (ASR) to
translate audio to text with timestamps
The image-to-image pipeline enables advanced image manipulations, including
style transfer, image enhancement, and more
The image-to-text pipeline generates captions for input images, with an
optional prompt to guide the process.
The image-to-video pipeline creates animated high-quality videos from images
The segment-anything-2 pipeline offers promptable visual segmentation for
images and videos.
The text-to-image pipeline generates high-quality images from text
descriptions
The text-to-speech pipeline generates high-quality, natural sounding speech
in the style of a given speaker (gender, pitch, speaking style, etc).
The upscale pipeline transforms low-resolution images into high-quality ones
without distortion
The LLM pipeline provides an OpenAI-compatible interface for text
generation, enabling seamless integration into media workflows.
# Segment-Anything-2
Source: https://docs.livepeer.org/v1/ai/pipelines/segment-anything-2
## Overview
The `segment-anything-2` pipeline provides direct access to the
[Segment Anything 2 pipeline](https://ai.meta.com/sam2/) developed by
[Meta AI Research](https://research.facebook.com/). In its current version, it
supports only image segmentation, enabling it to segment any object in an image.
Future versions will also support direct video input, allowing the object to be
consistently tracked across all frames of a video in real-time. This advancement
will unlock new possibilities for video editing and enhance experiences in mixed
reality. The pipeline is powered by the latest diffusion models from
HuggingFace's
[facebook/sam2-hiera-large](https://huggingface.co/facebook/sam2-hiera-large).
## Models
### Warm Models
The current warm model requested for the `segment-anything-2` pipeline is:
* [facebook/sam2-hiera-large](https://huggingface.co/facebook/sam2-hiera-large):
The largest model in the Segment Anything 2 model suite, designed for the most
accurate image segmentation.
For faster responses with different
[segment-anything-2](https://github.com/facebookresearch/segment-anything-2)
diffusion models, ask Orchestrators to load it on their GPU via the `ai-video`
channel in [Discord Server](https://discord.gg/livepeer).
### On-Demand Models
The following models have been tested and verified for the `segment-anything-2`
pipeline:
If a specific model you wish to use is not listed, please submit a [feature
request](https://github.com/livepeer/ai-worker/issues/new?assignees=\&labels=enhancement%2Cmodel\&projects=\&template=model_request.yml)
on GitHub to get the model verified and added to the list.
* [facebook/sam2-hiera-base-plus](https://huggingface.co/facebook/sam2-hiera-base-plus): The second largest model in the Segment Anything 2 model suite, providing a balance between speed and accuracy.
* [facebook/sam2-hiera-small](https://huggingface.co/facebook/sam2-hiera-small): A smaller model in the Segment Anything 2 model suite, designed for faster image segmentation.
* [facebook/sam2-hiera-tiny](https://huggingface.co/facebook/sam2-hiera-tiny): The smallest model in the Segment Anything 2 model suite, optimized for real-time image segmentation.
## Basic Usage Instructions
For a detailed understanding of the `segment-anything-2` endpoint and to
experiment with the API, see the [Livepeer AI API
Reference](/ai/api-reference/segment-anything-2).
To generate an image with the `segment-anything-2` pipeline, send a `POST`
request to the Gateway's `segment-anything-2` API endpoint:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -X POST http:///segment-anything-2 \
-F model_id="facebook/sam2-hiera-large" \
-F point_coords="[[120,100],[120,50]]" \
-F point_labels="[1,0]" \
-F image=@/cool-cat.png
```
In this command:
* `` should be replaced with your AI Gateway's IP address.
* `model_id` is the diffusion model for image segmentation.
* The `point_coords` field holds the coordinates of the points to be segmented.
* The `point_labels` field holds the labels for the points to be segmented.
* The `image` field holds the **absolute** path to the image file to be
transformed.
For additional optional parameters, refer to the
[Livepeer AI API Reference](/ai/api-reference/segment-anything-2).
After execution, the Orchestrator processes the request and returns the response
to the Gateway:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"masks": "[[[2.84, 2.83, ...], [2.92, 2.91, ...], [3.22, 3.56, ...], ...]]",
"scores": "[0.50, 0.37, ...]",
"logits": "[[[2.84, 2.66, ...], [3.59, 5.20, ...], [5.07, 5.68, ...], ...]]"
}
```
## Orchestrator Configuration
To configure your Orchestrator to serve the `segment-anything-2` pipeline, refer
to the [Orchestrator Configuration](/ai/orchestrators/get-started) guide.
### System Requirements
The following system requirements are recommended for optimal performance:
* [NVIDIA GPU](https://developer.nvidia.com/cuda-gpus) with **at least 6GB** of
VRAM.
## Recommended Pipeline Pricing
We are planning to simplify the pricing in the future so orchestrators can set
one AI price per compute unit and have the system automatically scale based on
the model's compute requirements.
The pricing for the `segment-anything-2` pipeline is based on competitor
pricing. However, we strongly encourage orchestrators to set their own pricing
based on their costs and requirements. Setting a competitive price will help
attract more jobs, as Gateways can set their maximum price for a job. The
current recommended pricing for this pipeline is `3.22e-11 USD` per **input
pixel** (`height * width`).
### Pipeline-Specific Image
To serve the `segment-anything-2` pipeline, you must use a pipeline specific AI
Runner container. Pull the required container from
[Docker Hub](https://hub.docker.com/r/livepeer/ai-runner/tags?name=segment-anything-2-latest)
using the following command:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
docker pull livepeer/ai-runner:segment-anything-2
```
## API Reference
Explore the `segment-anything-2` endpoint and experiment with the API in
Livepeer AI API Reference.
# Text-to-Image
Source: https://docs.livepeer.org/v1/ai/pipelines/text-to-image
## Overview
The `text-to-image` pipeline of the Livepeer AI network allows you to generate
**high-quality** images from text descriptions. This pipeline is powered by the
latest diffusion models in the HuggingFace
[text-to-image](https://huggingface.co/models?pipeline_tag=text-to-image)
pipeline.
```mermaid theme={"theme":{"light":"github-light","dark":"dark-plus"}}
graph LR
A["A cool cat on the beach"] --> B[Gateway]
B --> C[Orchestrator]
C --> B
B --> D[
]
```
## Models
### Warm Models
The current warm model requested for the `text-to-image` pipeline is:
* [SG161222/RealVisXL\_V4.0\_Lightning](https://huggingface.co/SG161222/RealVisXL_V4.0_Lightning):
A streamlined version of RealVisXL\_V4.0, designed for faster inference while
still aiming for photorealism.
Furthermore, several Orchestrators are currently maintaining the following model
in a ready state:
* [ByteDance/SDXL-Lightning](https://huggingface.co/ByteDance/SDXL-Lightning): A
high-performance diffusion model developed by ByteDance.
For faster responses with different
[text-to-image](https://huggingface.co/models?pipeline_tag=text-to-image)
diffusion models, ask Orchestrators to load it on their GPU via the `ai-video`
channel in [Discord Server](https://discord.gg/livepeer).
### On-Demand Models
The following models have been tested and verified for the `text-to-image`
pipeline:
If a specific model you wish to use is not listed, please submit a [feature
request](https://github.com/livepeer/ai-worker/issues/new?assignees=\&labels=enhancement%2Cmodel\&projects=\&template=model_request.yml)
on GitHub to get the model verified and added to the list.
* [SG161222/Realistic\_Vision\_V6.0\_B1\_noVAE](https://huggingface.co/SG161222/Realistic_Vision_V6.0_B1_noVAE): Latest (experimental) release of the Realistic Vision model specialized in creating photorealistic portraits.
* [stabilityai/stable-diffusion-xl-base-1.0](https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0): A base model for stable diffusion by Stability AI.
* [runwayml/stable-diffusion-v1-5](https://huggingface.co/runwayml/stable-diffusion-v1-5): A stable diffusion model by Runway ML.
* [prompthero/openjourney-v4](https://huggingface.co/prompthero/openjourney-v4): A model by Prompthero for open-ended journey generation.
* [ByteDance/SDXL-Lightning](https://huggingface.co/ByteDance/SDXL-Lightning): A lightning-fast diffusion model by ByteDance.
* [SG161222/RealVisXL\_V4.0](https://huggingface.co/SG161222/RealVisXL_V4.0): A diffusion model that excels in generating high-quality, photorealistic images.
* [SG161222/RealVisXL\_V4.0\_Lightning](https://huggingface.co/SG161222/RealVisXL_V4.0_Lightning): A streamlined version of RealVisXL\_V4.0, designed for faster inference while still aiming for photorealism.
* [stabilityai/sd-turbo](https://huggingface.co/stabilityai/sd-turbo): A high-performance diffusion model by Stability AI ([limited-commercial use license](https://stability.ai/license)).
* [stabilityai/sdxl-turbo](https://huggingface.co/stabilityai/sdxl-turbo): An extended version of sd-turbo with enhanced capabilities ([limited-commercial use license](https://stability.ai/license)).
* [stabilityai/stable-diffusion-3-medium-diffusers](https://huggingface.co/stabilityai/stable-diffusion-3-medium-diffusers/): A Multimodal Diffusion Transformer (MMDiT) model with superior image quality, advanced typography, and enhanced prompt comprehension ([limited-commercial use license](https://stability.ai/license)).
## Basic Usage Instructions
For a detailed understanding of the `text-to-image` endpoint and to experiment
with the API, see the [Livepeer AI API
Reference](/ai/api-reference/text-to-image). For examples of effective
prompts, visit [PromptHero](https://prompthero.com/).
To generate an image with the `text-to-image` pipeline, send a `POST` request to
the Gateway's `text-to-image` API endpoint:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -X POST "https:///text-to-image" \
-H "Content-Type: application/json" \
-d '{
"model_id":"ByteDance/SDXL-Lightning",
"prompt":"A cool cat on the beach",
"width": 1024,
"height": 1024
}'
```
In this command:
* `` should be replaced with your AI Gateway's IP address.
* `model_id` is the diffusion model for image generation.
* `prompt` is the text description for the image.
For additional optional parameters, refer to the
[Livepeer AI API Reference](/ai/api-reference/text-to-image).
After execution, the Orchestrator processes the request and returns the response
to the Gateway:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"images": [
{
"nsfw": false,
"seed": 2562822894,
"url": "https:///stream/d0fc1fc6/8fdf5a94.png"
}
]
}
```
The `url` in the response is the URL of the generated image. Download the image
with:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -O "https:///stream/d0fc1fc6/8fdf5a94.png"
```
## Applying LoRa Models
To apply LoRa filters to an image, include the `loras` field in your request:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -X POST "https:///text-to-image" \
-H "Content-Type: application/json" \
-d '{
"model_id":"stabilityai/stable-diffusion-xl-base-1.0",
"prompt":"A cool cat on the beach",
"width": 1024,
"height": 1024,
"loras": "{ \"latent-consistency/lcm-lora-sdxl\": 1.0, \"nerijs/pixel-art-xl\": 1.2}"
}'
```
You can find a list of available LoRa models for various models on
[lora-studio](https://huggingface.co/spaces/enzostvs/lora-studio).
## Orchestrator Configuration
To configure your Orchestrator to serve the `text-to-image` pipeline, refer to
the [Orchestrator Configuration](/ai/orchestrators/get-started) guide.
### System Requirements
The following system requirements are recommended for optimal performance:
* [NVIDIA GPU](https://developer.nvidia.com/cuda-gpus) with **at least 24GB** of
VRAM.
## Recommended Pipeline Pricing
We are planning to simplify the pricing in the future so orchestrators can set
one AI price per compute unit and have the system automatically scale based on
the model's compute requirements.
The pricing for the `text-to-image` pipeline is based on competitor pricing.
However, we strongly encourage orchestrators to set their own pricing based on
their costs and requirements. Setting a competitive price will help attract more
jobs, as Gateways can set their maximum price for a job. The current recommended
pricing for this pipeline is `1.9073484e-08 USD` per **output pixel**
(`height * width * output images`).
## API Reference
Explore the `text-to-image` endpoint and experiment with the API in the
Livepeer AI API Reference.
# Text-to-Speech
Source: https://docs.livepeer.org/v1/ai/pipelines/text-to-speech
## Overview
The text-to-speech endpoint in Livepeer utilizes
[Parler-TTS](https://github.com/huggingface/parler-tts), specifically
`parler-tts/parler-tts-large-v1`. This model can generate speech with
customizable characteristics such as voice type, speaking style, and audio
quality.
## Basic Usage Instructions
For a detailed understanding of the `text-to-speech` endpoint and to
experiment with the API, see the [Livepeer AI API
Reference](/ai/api-reference/text-to-speech).
To use the text-to-speech feature, submit a POST request to the
`/text-to-speech` endpoint. Here's an example of how to structure your request:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -X POST "http:///text-to-speech" \
-H "Content-Type: application/json" \
-d '{
"model_id": "parler-tts/parler-tts-large-v1",
"text": "A cool cat on the beach",
"description": "Jon his voice is monotone yet slightly fast in delivery, with a very close recording that almost has no background noise."
}'
```
### Request Parameters
* `model_id`: The ID of the text-to-speech model to use. Currently, this should
be set to `"parler-tts/parler-tts-large-v1"`.
* `text`: The text you want to convert to speech.
* `description`: A description of the desired voice characteristics. This can
include details about the speaker's voice, speaking style, and audio quality.
### Voice Customization
You can customize the generated voice by adjusting the `description` parameter.
Some aspects you can control include:
* Speaker identity (e.g., "Jon's voice")
* Speaking style (e.g., "monotone", "expressive")
* Speaking speed (e.g., "slightly fast")
* Audio quality (e.g., "very close recording", "no background noise")
The checkpoint was trained on 34 speakers. The full list of available speakers
includes: Laura, Gary, Jon, Lea, Karen, Rick, Brenda, David, Eileen, Jordan,
Mike, Yann, Joy, James, Eric, Lauren, Rose, Will, Jason, Aaron, Naomie, Alisa,
Patrick, Jerry, Tina, Jenna, Bill, Tom, Carol, Barbara, Rebecca, Anna, Bruce,
and Emily.
However, the models performed better with certain speakers. A list of the top 20
speakers for each model variant, ranked by their average speaker similarity
scores can be found
[here](https://github.com/huggingface/parler-tts/blob/main/INFERENCE.md#speaker-consistency)
## Limitations and Considerations
* The maximum length of the input text may be limited. For long-form content,
you will need to split your text into smaller chunks. The training default
configuration in parler-tts is max 30sec, max text length 600 characters.
[https://github.com/huggingface/parler-tts/blob/main/training/README.md#3-training](https://github.com/huggingface/parler-tts/blob/main/training/README.md#3-training)
* While the model supports various voice characteristics, the exact replication
of a specific speaker's voice is not guaranteed.
* The quality of the generated speech can vary based on the complexity of the
input text and the specificity of the voice description.
## Orchestrator Configuration
To configure your Orchestrator to serve the `text-to-speech` pipeline, refer to
the [Orchestrator Configuration](/ai/orchestrators/get-started) guide.
### System Requirements
The following system requirements are recommended for optimal performance:
* [NVIDIA GPU](https://developer.nvidia.com/cuda-gpus) with **at least 12GB** of
VRAM.
## Recommended Pipeline Pricing
We are planning to simplify the pricing in the future so orchestrators can set
one AI price per compute unit and have the system automatically scale based on
the model's compute requirements.
The pricing for the `text-to-speech` pipeline is based on competitor pricing.
However, we strongly encourage orchestrators to set their own pricing based on
their costs and requirements. Setting a competitive price will help attract more
jobs, as Gateways can set their maximum price for a job. The current recommended
pricing for this pipeline is `1.5e-6 USD` per **character**.
### Pipeline-Specific Image
To serve the `text-to-speech` pipeline, you must use a pipeline specific AI
Runner container. Pull the required container from
[Docker Hub](https://hub.docker.com/r/livepeer/ai-runner/tags?name=text-to-speech-latest)
using the following command:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
docker pull livepeer/ai-runner:text-to-speech
```
## API Reference
Explore the `text-to-speech` endpoint and experiment with the API in the
Livepeer AI API Reference.
# Upscale
Source: https://docs.livepeer.org/v1/ai/pipelines/upscale
## Overview
The Livepeer AI network's `upscale` pipeline provides **advanced image
upscaling**. Powered by the latest diffusion models in HuggingFace's
[super-resolution](https://huggingface.co/docs/diffusers/en/api/pipelines/stable_diffusion/upscale)
pipeline, it enhances the resolution of input images by a factor of 4.
```mermaid theme={"theme":{"light":"github-light","dark":"dark-plus"}}
graph LR
A[
] --> B[Gateway]
P[A white cat wearing sunglasses on the beach] --> B
B --> C[Orchestrator]
C --> B
B --> D[
]
```
## Models
### Warm Models
The current warm model requested for the `upscale` pipeline is:
* [stabilityai/stable-diffusion-x4-upscaler](https://huggingface.co/stabilityai/stable-diffusion-x4-upscaler):
A text-guided upscaling diffusion model trained on large LAION images,
offering enhanced resolution and controlled noise addition.
For faster responses with different
[upscale](https://huggingface.co/docs/diffusers/en/api/pipelines/stable_diffusion/upscale)
compatible diffusion models, ask Orchestrators to load it on their GPU via the
`ai-video` channel in [Discord Server](https://discord.gg/livepeer).
### On-Demand Models
The following models have been tested and verified for the `upscale` pipeline:
If a specific model you wish to use is not listed, please submit a [feature
request](https://github.com/livepeer/ai-worker/issues/new?assignees=\&labels=enhancement%2Cmodel\&projects=\&template=model_request.yml)
on GitHub to get the model verified and added to the list.
* [stabilityai/stable-diffusion-x4-upscaler](https://huggingface.co/stabilityai/stable-diffusion-x4-upscaler):
A text-guided upscaling diffusion model trained on large LAION images,
offering enhanced resolution and controlled noise addition.
## Basic Usage Instructions
For a detailed understanding of the `upscale` endpoint and to experiment with
the API, see the [Livepeer AI API Reference](/ai/api-reference/upscale).
To generate an image with the `upscale` pipeline, send a `POST` request to the
Gateway's `upscale` API endpoint:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -X POST https:///upscale \
-F model_id="stabilityai/stable-diffusion-x4-upscaler" \
-F image=@/low_res_cat.png \
-F prompt="A white cat"
```
In this command:
* `` should be replaced with your AI Gateway's IP address.
* `model_id` is the diffusion model for image generation.
* The `image` field holds the **absolute** path to the image file to be
upscaled.
* `prompt` is a descriptive text that provides context about the content of the
image.
For additional optional parameters, refer to the
[Livepeer AI API Reference](/ai/api-reference/upscale).
After execution, the Orchestrator processes the request and returns the response
to the Gateway:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"images": [
{
"nsfw": false,
"seed": 3197613440,
"url": "https:///stream/dd5ad78d/7adde483.png"
}
]
}
```
The `url` in the response is the URL of the generated image. Download the image
with:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -O "https:///stream/dd5ad78d/7adde483.png"
```
## Orchestrator Configuration
To configure your Orchestrator to serve the `upscale` pipeline, refer to the
[Orchestrator Configuration](/ai/orchestrators/get-started) guide.
### System Requirements
The following system requirements are recommended for optimal performance:
* [NVIDIA GPU](https://developer.nvidia.com/cuda-gpus) with **at least 24GB** of
VRAM.
## Recommended Pipeline Pricing
We are planning to simplify the pricing in the future so orchestrators can set
one AI price per compute unit and have the system automatically scale based on
the model's compute requirements.
The pricing for the `upscale` pipeline is based on competitor pricing. However,
we strongly encourage orchestrators to set their own pricing based on their
costs and requirements. Setting a competitive price will help attract more jobs,
as Gateways can set their maximum price for a job. The current recommended
pricing for this pipeline is `1.9073484e-08 USD` per **input pixel**
(`height * width`).
## API Reference
Explore the `upscale` endpoint and experiment with the API in the Livepeer AI
API Reference.
# Go
Source: https://docs.livepeer.org/v1/ai/sdks/go
Learn how to run your first AI inference job using the Livepeer AI Go SDK.
To get the most out of this guide, you’ll need to:
* [Choose an AI Gateway](/ai/builders/gateways)
* **Optional**: Get an API key (required for some gateways).
Get the Livepeer AI Golang SDK.
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
go get github.com/livepeer/livepeer-ai-go
```
The first step is to initialize the SDK (with your API key if required).
```go theme={"theme":{"light":"github-light","dark":"dark-plus"}}
package main
import (
"context"
livepeeraigo "github.com/livepeer/livepeer-ai-go"
"github.com/livepeer/livepeer-ai-go/models/components"
"log"
)
func main() {
s := livepeeraigo.New(
livepeeraigo.WithSecurity(""),
)
}
```
Now that you have the SDK installed and initialized, you can use it to request one of the [available AI services](/ai/pipelines/overview).
```go theme={"theme":{"light":"github-light","dark":"dark-plus"}}
package main
import (
"context"
livepeeraigo "github.com/livepeer/livepeer-ai-go"
"github.com/livepeer/livepeer-ai-go/models/components"
"log"
)
func main() {
s := livepeeraigo.New(
livepeeraigo.WithSecurity(""),
)
ctx := context.Background()
res, err := s.Generate.TextToImage(ctx, components.TextToImageParams{
Prompt: "",
})
if err != nil {
log.Fatal(err)
}
if res.ImageResponse != nil {
// handle response
}
}
```
See the examples on GitHub.
## Next steps
Checkout Livepeer AI [API Reference](/ai/api-reference) to learn more about the
Livepeer AI API and the Golang SDK.
# JavaScript
Source: https://docs.livepeer.org/v1/ai/sdks/javascript
Learn how to run your first AI inference job using the Livepeer AI JS SDK.
To get the most out of this guide, you’ll need to:
* [Choose an AI Gateway](/ai/builders/gateways)
* **Optional**: Get an API key (required for some gateways).
Get the Livepeer AI JavaScript SDK.
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
npm add @livepeer/ai
```
The first step is to initialize the SDK (with your API key if required).
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Livepeer } from "@livepeer/ai";
const livepeer = new Livepeer({
httpBearer: "",
});
```
Now that you have the SDK installed and initialized, you can use it to request one of the [available AI services](/ai/pipelines/overview).
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Livepeer } from "@livepeer/ai";
const livepeer = new Livepeer({
httpBearer: "",
});
async function run() {
const result = await livepeer.generate.textToImage({
prompt: "",
});
// Handle the result
console.log(result);
}
run();
```
See the examples on GitHub.
## Next steps
Checkout Livepeer AI [API Reference](/ai/api-reference) to learn more about the
Livepeer AI API and the Javascript SDK.
# AI SDKs
Source: https://docs.livepeer.org/v1/ai/sdks/overview
Explore developer SDKs for interacting with the Livepeer AI API.
## Client-side SDKs
Client-side SDKs simplify the process of using the Livepeer AI API. Just install
a language-specific SDK into your application, choose a
[AI Gateway](/ai/builders/gateways), and get started with only 2 lines of code.
For some gateways, initialisation with an API key is optional.
# Python
Source: https://docs.livepeer.org/v1/ai/sdks/python
Learn how to run your first AI inference job using the Livepeer AI Python SDK.
To get the most out of this guide, you’ll need to:
* [Choose an AI Gateway](/ai/builders/gateways)
* **Optional**: Get an API key (required for some gateways).
Get the Livepeer AI Python SDK.
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
pip install livepeer-ai
```
The first step is to initialize the SDK (with your API key if required).
```python theme={"theme":{"light":"github-light","dark":"dark-plus"}}
from livepeer_ai import Livepeer
s = Livepeer(
http_bearer="",
)
```
Now that you have the SDK installed and initialized, you can use it to request one of the [available AI services](/ai/pipelines/overview).
```python theme={"theme":{"light":"github-light","dark":"dark-plus"}}
from livepeer_ai import Livepeer
s = Livepeer(
http_bearer="",
)
res = s.generate.text_to_image(request={
"prompt": "",
})
if res.image_response is not None:
# handle response
pass
```
See the examples on GitHub.
## Next steps
Checkout Livepeer AI [API Reference](/ai/api-reference) to learn more about the
Livepeer AI API and the Python SDK.
# What's New
Source: https://docs.livepeer.org/v1/ai/whats-new
# Retrieve Playback Info
Source: https://docs.livepeer.org/v1/api-reference/playback/get
GET /playback/{id}
# Transcode a video
Source: https://docs.livepeer.org/v1/api-reference/transcode/create
POST /transcode
`POST /transcode` transcodes a video file and uploads the results to the
specified storage service.
\
\
Transcoding is asynchronous so you will need to check the status of the
task in order to determine when transcoding is complete. The `id` field
in the response is the unique ID for the transcoding `Task`. The task
status can be queried using the [GET tasks
endpoint](https://docs.livepeer.org/reference/api/get-tasks):
\
\
When `status.phase` is `completed`, transcoding will be complete and
the results will be stored in the storage service and the specified
output location.
\
\
The results will be available under `params.outputs.hls.path` and
`params.outputs.mp4.path` in the specified storage service.
## Input
\
This endpoint currently supports the following inputs:
- HTTP
- S3 API Compatible Service
\
\
**HTTP**
\
A public HTTP URL can be used to read a video file.
```json
{
"url": "https://www.example.com/video.mp4"
}
```
| Name | Type | Description |
| ---- | ------ | ------------------------------------ |
| url | string | A public HTTP URL for the video file. |
Note: For IPFS HTTP gateway URLs, the API currently only supports “path
style” URLs and does not support “subdomain style” URLs. The API will
support both styles of URLs in a future update.
\
\
**S3 API Compatible Service**
\
\
S3 credentials can be used to authenticate with a S3 API compatible
service to read a video file.
```json
{
"type": "s3",
"endpoint": "https://gateway.storjshare.io",
"credentials": {
"accessKeyId": "$ACCESS_KEY_ID",
"secretAccessKey": "$SECRET_ACCESS_KEY"
},
"bucket": "inbucket",
"path": "/video/source.mp4"
}
```
## Storage
\
This endpoint currently supports the following storage services:
- S3 API Compatible Service
- Web3 Storage
\
\
**S3 API Compatible Service**
```json
{
"type": "s3",
"endpoint": "https://gateway.storjshare.io",
"credentials": {
"accessKeyId": "$ACCESS_KEY_ID",
"secretAccessKey": "$SECRET_ACCESS_KEY"
},
"bucket": "mybucket"
}
```
**Web3 Storage**
```json
{
"type": "web3.storage",
"credentials": {
"proof": "$UCAN_DELEGATION_PROOF",
}
}
```
## Outputs
\
This endpoint currently supports the following output types:
- HLS
- MP4
**HLS**
```json
{
"hls": {
"path": "/samplevideo/hls"
}
}
```
**MP4**
```json
{
"mp4": {
"path": "/samplevideo/mp4"
}
}
```
# Overview
Source: https://docs.livepeer.org/v1/api-reference/transcode/overview
The Transcode API is used to create transcode object from pipeline.
### Transcode Object
Task ID.
Type of the task, such as upload, import, export, etc.
Timestamp (in milliseconds) at which the task was created.
Timestamp (in milliseconds) at which the task was scheduled for execution.
ID of the input asset for the task.
ID of the output asset for the task.
Parameters of the task, which vary depending on the task type.
Status of the task, including phase, update time, and error message.
Output of the task, specifics depend on the task type.
```json Response theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"id": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"type": "upload",
"createdAt": 1587667174725,
"scheduledAt": 1587667174725,
"inputAssetId": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"outputAssetId": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"params": {
"upload": {
"url": "https://cdn.livepeer.com/ABC123/filename.mp4",
"encryption": {
"encryptedKey": "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JR0hBZ0VBTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEJHMHdhd0lCQVFRZ1RDRzhRWDZKdkR0eC95ZDMKdlpkUHJKR25LcjhiWHRsdXNIL2FOYW5XdHEraFJBTkNBQVE0QnZ6ODI2L2lDaXV1U0NiZVkwc3FmOXljYWh0OApDRFYyUFF2bDFVM1FLSVRBcWRpaktLa0FSUFVkcWRrYWZzR21PMzBDeElPaDBLNWJSQW5XQzd4KwotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tCg=="
},
"recordedSessionId": "78df0075-b5f3-4683-a618-1086faca35dc"
},
"import": {
"url": "https://cdn.livepeer.com/ABC123/filename.mp4",
"encryption": {
"encryptedKey": "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JR0hBZ0VBTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEJHMHdhd0lCQVFRZ1RDRzhRWDZKdkR0eC95ZDMKdlpkUHJKR25LcjhiWHRsdXNIL2FOYW5XdHEraFJBTkNBQVE0QnZ6ODI2L2lDaXV1U0NiZVkwc3FmOXljYWh0OApDRFYyUFF2bDFVM1FLSVRBcWRpaktLa0FSUFVkcWRrYWZzR21PMzBDeElPaDBLNWJSQW5XQzd4KwotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tCg=="
},
"recordedSessionId": "78df0075-b5f3-4683-a618-1086faca35dc"
},
"exportData": {
"content": "object",
"ipfs": {
"nftMetadataTemplate": "file",
"nftMetadata": "object",
"pinata": {
"jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MDI4NjQwNzcsImlhdCI6MTYwMjI3NjA3NywiaXNzIjoiYXBpLmlzc3VlciIsInN1YiI6I"
}
},
"type": "string",
"id": "string"
},
"transcode": {
"profile": {
"width": 1280,
"name": "720p",
"height": 720,
"bitrate": 4000,
"fps": 30,
"fpsDen": 1,
"gop": "60",
"profile": "H264High",
"encoder": "h264"
}
},
"transcode-file": {
"input": {
"url": "https://cdn.livepeer.com/ABC123/filename.mp4"
},
"storage": {
"url": "s3+https://accessKeyId:secretAccessKey@s3Endpoint/bucket"
},
"outputs": {
"hls": {
"path": "/samplevideo/hls"
},
"mp4": {
"path": "/samplevideo/mp4"
}
},
"profiles": [
{
"width": 1280,
"name": "720p",
"height": 720,
"bitrate": 4000,
"fps": 30,
"fpsDen": 1,
"gop": "60",
"profile": "H264High",
"encoder": "h264"
}
],
"targetSegmentSizeSecs": "number",
"c2pa": "boolean"
}
},
"clip": {
"url": "string",
"clipStrategy": {
"startTime": "number",
"endTime": "number",
"playbackId": "string"
},
"catalystPipelineStrategy": "catalyst",
"sessionId": "string",
"inputId": "string"
},
"status": {
"phase": "pending",
"updatedAt": 1587667174725,
"progress": "number",
"errorMessage": "string",
"retries": "number",
"step": "string"
},
"output": {
"upload": {
"videoFilePath": "string",
"metadataFilePath": "string",
"assetSpec": {
"id": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"type": "video",
"playbackId": "eaw4nk06ts2d0mzb",
"staticMp4": "boolean",
"c2pa": "boolean",
"playbackUrl": "https://livepeercdn.com/asset/ea03f37e-f861-4cdd-b495-0e60b6d753ad/index.m3u8",
"downloadUrl": "https://livepeercdn.com/asset/eaw4nk06ts2d0mzb/video",
"playbackPolicy": {
"type": "public",
"webhookId": "3e02c844-d364-4d48-b401-24b2773b5d6c",
"webhookContext": {
"foo": "bar"
}
},
"source": {
"type": "url",
"url": "https://example.com/video.mp4",
"gatewayUrl": "https://example.com/video.mp4"
},
"creatorId": "object",
"storage": {
"ipfs": {
"spec": {
"nftMetadataTemplate": "file",
"nftMetadata": {
"name": "My NFT",
"description": "My NFT description"
}
}
}
},
"status": {
"phase": "ready",
"updatedAt": 1587667174725,
"progress": 100
},
"name": "filename.mp4",
"createdAt": 1587667174725,
"size": 84934509,
"hash": [
{
"hash": "9b560b28b85378a5004117539196ab24e21bbd75b0e9eb1a8bc7c5fd80dc5b57",
"algorithm": "sha256"
}
],
"videoSpec": {
"format": "mp4",
"duration": 23.8328,
"bitrate": 1000000,
"tracks": [
{
"type": "video",
"codec": "h264",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"width": 1920,
"height": 1080,
"pixelFormat": "yuv420p",
"fps": 30
},
{
"type": "audio",
"codec": "aac",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"channels": 2,
"sampleRate": 44100,
"bitDepth": 16
}
]
}
}
},
"import": {
"videoFilePath": "string",
"metadataFilePath": "string",
"assetSpec": {
"id": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"type": "video",
"playbackId": "eaw4nk06ts2d0mzb",
"staticMp4": "boolean",
"c2pa": "boolean",
"playbackUrl": "https://livepeercdn.com/asset/ea03f37e-f861-4cdd-b495-0e60b6d753ad/index.m3u8",
"downloadUrl": "https://livepeercdn.com/asset/eaw4nk06ts2d0mzb/video",
"playbackPolicy": {
"type": "public",
"webhookId": "3e02c844-d364-4d48-b401-24b2773b5d6c",
"webhookContext": {
"foo": "bar"
}
},
"source": {
"type": "url",
"url": "https://example.com/video.mp4",
"gatewayUrl": "https://example.com/video.mp4"
},
"creatorId": "object",
"storage": {
"ipfs": {
"spec": {
"nftMetadataTemplate": "file",
"nftMetadata": {
"name": "My NFT",
"description": "My NFT description"
}
}
}
},
"status": {
"phase": "ready",
"updatedAt": 1587667174725,
"progress": 100
},
"name": "filename.mp4",
"createdAt": 1587667174725,
"size": 84934509,
"hash": [
{
"hash": "9b560b28b85378a5004117539196ab24e21bbd75b0e9eb1a8bc7c5fd80dc5b57",
"algorithm": "sha256"
}
],
"videoSpec": {
"format": "mp4",
"duration": 23.8328,
"bitrate": 1000000,
"tracks": [
{
"type": "video",
"codec": "h264",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"width": 1920,
"height": 1080,
"pixelFormat": "yuv420p",
"fps": 30
},
{
"type": "audio",
"codec": "aac",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"channels": 2,
"sampleRate": 44100,
"bitDepth": 16
}
]
}
}
},
"export": {
"ipfs": {
"videoFileCid": "string",
"videoFileUrl": "string",
"videoFileGatewayUrl": "string",
"nftMetadataCid": "string",
"nftMetadataUrl": "string",
"nftMetadataGatewayUrl": "string"
}
},
"exportData": {
"ipfs": {
"cid": "string"
}
},
"transcode": {
"asset": {
"videoFilePath": "string",
"metadataFilePath": "string",
"assetSpec": {
"id": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"type": "video",
"playbackId": "eaw4nk06ts2d0mzb",
"staticMp4": "boolean",
"c2pa": "boolean",
"playbackUrl": "https://livepeercdn.com/asset/ea03f37e-f861-4cdd-b495-0e60b6d753ad/index.m3u8",
"downloadUrl": "https://livepeercdn.com/asset/eaw4nk06ts2d0mzb/video",
"playbackPolicy": {
"type": "public",
"webhookId": "3e02c844-d364-4d48-b401-24b2773b5d6c",
"webhookContext": {
"foo": "bar"
}
},
"source": {
"type": "url",
"url": "https://example.com/video.mp4",
"gatewayUrl": "https://example.com/video.mp4"
},
"creatorId": "object",
"storage": {
"ipfs": {
"spec": {
"nftMetadataTemplate": "file",
"nftMetadata": {
"name": "My NFT",
"description": "My NFT description"
}
}
}
},
"status": {
"phase": "ready",
"updatedAt": 1587667174725,
"progress": 100
},
"name": "filename.mp4",
"createdAt": 1587667174725,
"size": 84934509,
"hash": [
{
"hash": "9b560b28b85378a5004117539196ab24e21bbd75b0e9eb1a8bc7c5fd80dc5b57",
"algorithm": "sha256"
}
],
"videoSpec": {
"format": "mp4",
"duration": 23.8328,
"bitrate": 1000000,
"tracks": [
{
"type": "video",
"codec": "h264",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"width": 1920,
"height": 1080,
"pixelFormat": "yuv420p",
"fps": 30
},
{
"type": "audio",
"codec": "aac",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"channels": 2,
"sampleRate": 44100,
"bitDepth": 16
}
]
}
}
}
}
}
}
```
# Query creator viewership metrics
Source: https://docs.livepeer.org/v1/api-reference/viewership/get-creators-metrics
GET /data/views/query/creator
Requires a proof of ownership to be sent in the request, which for now is just the assetId or streamId parameters (1 of those must be in the query-string).
# Query public total views metrics
Source: https://docs.livepeer.org/v1/api-reference/viewership/get-public-total-views
GET /data/views/query/total/{playbackId}
Allows querying for the public metrics for viewership about a video.
This can be called from the frontend with a CORS key, or even
unauthenticated.
# Query realtime viewership
Source: https://docs.livepeer.org/v1/api-reference/viewership/get-realtime-viewership
GET /data/views/now
Requires a private (non-CORS) API key to be used.
# Query usage metrics
Source: https://docs.livepeer.org/v1/api-reference/viewership/get-usage-metrics
GET /data/usage/query
# Query viewership metrics
Source: https://docs.livepeer.org/v1/api-reference/viewership/get-viewership-metrics
GET /data/views/query
Requires a private (non-CORS) API key to be used.
# Go
Source: https://docs.livepeer.org/v1/sdks/go
Learn how to create your first stream using the Livepeer Go SDK.
To get the most out of this guide, you’ll need to:
* [Create an API key](https://livepeer.studio/dashboard/developers/api-keys)
Get the Livepeer Go SDK.
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
go get github.com/livepeer/livepeer-go
```
The first step is to initialize the SDK with your Livepeer Studio API key.
```go theme={"theme":{"light":"github-light","dark":"dark-plus"}}
package main
import (
"context"
livepeer "github.com/livepeer/livepeer-go"
"github.com/livepeer/livepeer-go/models/components"
"log"
)
func main() {
lpClient := livepeer.New(
livepeer.WithSecurity(""),
)
}
```
Now that you have the SDK installed and initialized, you can use it in your app.
Let's create a stream.
```go theme={"theme":{"light":"github-light","dark":"dark-plus"}}
package main
import (
"context"
livepeer "github.com/livepeer/livepeer-go"
"github.com/livepeer/livepeer-go/models/components"
"log"
)
func main() {
lpClient := livepeer.New(
livepeer.WithSecurity(""),
)
ctx := context.Background()
res, err := lpClient.Stream.Create(ctx, components.NewStreamPayload{
Name: "test_stream",
})
if err != nil {
log.Fatal(err)
}
if res.Stream != nil {
log.Printf("Stream created successfully")
}
}
```
See an example on GitHub.
## Next steps
Checkout Livepeer [API Reference](/api-reference) to learn more about the
Livepeer API and the Go SDK.
# SDKs
Source: https://docs.livepeer.org/v1/sdks/introduction
Explore developer SDKs, pre-built UI components, and tools for interacting with the Livepeer Studio API.
## Server-side SDKs
Server-side SDKs reduce the amount of work required to use the Livepeer Studio
API. Install a language-specific SDK into your application, initialize with your
API key and get started with just 2 lines of code.
## React Components
Build with composable React primitives for both broadcasting and playback.
Fully customizable video player component for seamless playback
Full-featured broadcast component with controls, settings, and device
selection
# JavaScript
Source: https://docs.livepeer.org/v1/sdks/javascript
Learn how to create your first stream using the Livepeer Javascript SDK.
To get the most out of this guide, you’ll need to:
* [Create an API key](https://livepeer.studio/dashboard/developers/api-keys)
Get the Livepeer Javascript SDK.
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
npm install livepeer
```
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
yarn add livepeer
```
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
pnpm install livepeer
```
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
bun install livepeer
```
The first step is to initialize the SDK with your Livepeer Studio API key.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Livepeer } from "livepeer";
const livepeer = new Livepeer({
apiKey: "", // Your API key
});
```
Now that you have the SDK installed and initialized, you can use it in your app.
Let's create a stream.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Livepeer } from "livepeer";
const livepeer = new Livepeer({
apiKey: "",
});
const main = async () => {
const { stream } = await livepeer.stream.create({
name: "Hello from JS SDK!",
});
console.log(stream);
};
main();
```
See the full example on GitHub.
## Next steps
Checkout Livepeer [API Reference](/api-reference) to learn more about the
Livepeer API and the Javascript SDK.
# Python
Source: https://docs.livepeer.org/v1/sdks/python
Learn how to create your first stream using the Livepeer Python SDK.
To get the most out of this guide, you’ll need to:
* [Create an API key](https://livepeer.studio/dashboard/developers/api-keys)
Get the Livepeer Python SDK.
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
pip install git+https://github.com/livepeer/livepeer-python.git
```
The first step is to initialize the SDK with your Livepeer Studio API key.
```python theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import livepeer
from livepeer.models import components
lpClient = livepeer.Livepeer(
api_key="",
)
```
Now that you have the SDK installed and initialized, you can use it in your app.
Let's create a stream.
```python theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import livepeer
from livepeer.models import components
lpClient = livepeer.Livepeer(
api_key="",
)
req = components.NewStreamPayload(
name='test_stream',
)
res = s.stream.create(req)
if res.stream is not None:
# handle response
pass
```
See an example on GitHub.
## Next steps
Checkout Livepeer [API Reference](/api-reference) to learn more about the
Livepeer API and the Javascript SDK.
# Broadcast
Source: https://docs.livepeer.org/v1/sdks/react/Broadcast
A comprehensive example showcasing the integration of various `@livepeer/react/broadcast` components to create a full-featured broadcast interface with controls, settings, and device selection.
This comprehensive example includes broadcasting controls like audio and video
toggles, screenshare capabilities, fullscreen and picture-in-picture modes,
along with advanced settings for device selection and error handling.
It uses Tailwind CSS for styling, but this can be replaced with any styling
solution.
## Broadcast
### Usage
Here's how a full Broadcast experience can be built with the primitives:
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { cn } from "@/lib/utils";
import {
DisableAudioIcon,
DisableVideoIcon,
EnableAudioIcon,
EnableVideoIcon,
EnterFullscreenIcon,
ExitFullscreenIcon,
LoadingIcon,
OfflineErrorIcon,
PictureInPictureIcon,
SettingsIcon,
StartScreenshareIcon,
StopIcon,
StopScreenshareIcon,
} from "@livepeer/react/assets";
import * as Broadcast from "@livepeer/react/broadcast";
import * as Popover from "@radix-ui/react-popover";
import { CheckIcon, ChevronDownIcon, XIcon } from "lucide-react";
import React from "react";
import { toast } from "sonner";
export function BroadcastWithControls({
streamKey,
}: {
streamKey: string | null;
}) {
const ingestUrl = getIngest(streamKey);
return !ingestUrl ? (
) : (
<>
error?.type === "permissions"
? toast.error(
"You must accept permissions to broadcast. Please try again."
)
: null
}
aspectRatio={16 / 9}
ingestUrl={ingestUrl}
>
Broadcast failed
There was an error with broadcasting - it is retrying in the
background.
);
}
);
export const SourceSelectComposed = React.forwardRef(
(
{
name,
type,
className,
}: { name: string; type: "audioinput" | "videoinput"; className?: string },
ref: React.Ref | undefined
) => (
{(devices) =>
devices ? (
<>
{devices?.map((device) => (
{device.friendlyName}
))}
>
) : (
There was an error fetching the available devices.
)
}
)
);
const RateSelectItem = React.forwardRef<
HTMLDivElement,
Broadcast.SelectItemProps
>(({ children, className, ...props }, forwardedRef) => {
return (
{children}
);
});
```
# Player
Source: https://docs.livepeer.org/v1/sdks/react/Player
A comprehensive example showcasing the integration of various `@livepeer/react/player` components to create a full-featured player interface with controls and settings.
This comprehensive example includes broadcasting controls like fullscreen and
picture-in-picture modes, play/pause, etc.
It uses Tailwind CSS for styling, but this can be replaced with any styling
solution.
## Player
### Usage
Here's how a full Player experience can be built with the primitives:
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { cn } from "@/lib/utils";
import {
ClipIcon,
EnterFullscreenIcon,
ExitFullscreenIcon,
LoadingIcon,
MuteIcon,
PauseIcon,
PictureInPictureIcon,
PlayIcon,
SettingsIcon,
UnmuteIcon,
} from "@livepeer/react/assets";
import * as Player from "@livepeer/react/player";
import * as Popover from "@radix-ui/react-popover";
import { ClipPayload } from "livepeer/dist/models/components";
import { CheckIcon, ChevronDownIcon, XIcon } from "lucide-react";
import React, { useCallback, useTransition } from "react";
import { toast } from "sonner";
import { Src } from "@livepeer/react";
import { createClip } from "./actions";
export function PlayerWithControls(props: { src: Src[] | null }) {
if (!props.src) {
return (
);
}
return (
Stream is offline
Playback will start automatically once the stream has started
Stream is private
It looks like you don't have permission to view this content
);
function Clip({ className }: { className?: string }) {
const [isPending, startTransition] = useTransition();
const createClipComposed = useCallback((opts: ClipPayload) => {
startTransition(async () => {
const result = await createClip(opts);
if (result.success) {
toast.success(
{
"You have created a new clip - in a few minutes, you will be able to view it at "
}
this link
{"."}
);
} else {
toast.error(
"Failed to create a clip. Please try again in a few seconds."
);
}
});
}, []);
return (
{isPending ? (
) : (
)}
);
}
const Settings = React.forwardRef(
(
{ className }: { className?: string },
ref: React.Ref | undefined
) => {
return (
e.stopPropagation()}
>
Settings
0.5x0.75x1x (normal)1.25x1.5x1.75x2x
Auto (HD+)
1080p (HD)
720p
480p
360p
);
}
);
const RateSelectItem = React.forwardRef<
HTMLDivElement,
Player.RateSelectItemProps
>(({ children, className, ...props }, forwardedRef) => {
return (
{children}
);
});
const VideoQualitySelectItem = React.forwardRef<
HTMLDivElement,
Player.VideoQualitySelectItemProps
>(({ children, className, ...props }, forwardedRef) => {
return (
{children}
);
});
```
# Audio
Source: https://docs.livepeer.org/v1/sdks/react/broadcast/Audio
The `AudioEnabledTrigger` and `AudioEnabledIndicator` components provide controls and visual cues for audio input state during media broadcast.
`AudioEnabledTrigger` and `AudioEnabledIndicator` integrate together to form
the typical microphone on/off interaction for broadcasts. They do not have to
be used together and can combine with other components.
## Features
* Controls the audio input state and conditionally renders based on audio input
on/off status, customizable with the `matcher` pattern
* Keyboard hotkeys and adheres to [WAI-ARIA](https://w3c.github.io/aria/) design
patterns
* Handles all common browser APIs, and old WebKit/Firefox APIs (see
[caniuse](https://caniuse.com/mdn-api_mediadevices_getusermedia))
The `getUserMedia` browser API used to get the audio is only available in
secure contexts (HTTPS).
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Broadcast from "@livepeer/react/broadcast";
export default () => (
);
```
## Props
### `AudioEnabledTrigger`
Accepts all props for a typical button element.
### `AudioEnabledIndicator`
##### `forceMount`
A boolean that, when true, ensures the component is always mounted. This is
particularly useful for managing animations with external animation libraries.
##### `matcher`
A prop intended to define the circumstances under which the
`AudioEnabledIndicator` should be visible. It can be a boolean that corresponds
directly to the audio state or a function that provides custom logic for
visibility determination based on the audio state.
## Data Attributes
### `AudioEnabledTrigger`
#### `data-livepeer-controls-audio-enabled-trigger`
Serves to identify the component's role within the broadcast interface.
#### `data-enabled`
Indicates the current audio state, `"true"` when audio is enabled and `"false"`
when it is disabled.
### `AudioEnabledIndicator`
#### `data-livepeer-controls-audio-enabled-indicator`
Identifies the component's role as a visual indicator of the audio state within
the broadcast interface.
#### `data-enabled`
Shows the current audio state, `"true"` when audio is enabled and `"false"` when
it is disabled.
#### `data-visible`
Reflects the visibility status of the indicator, with `"true"` meaning it's
currently visible based on the `matcher` or audio state and `"false"` denoting
it's not visible.
This is often used for dynamically applying enter/exit CSS animations.
# Camera
Source: https://docs.livepeer.org/v1/sdks/react/broadcast/Camera
The `VideoEnabledTrigger` and `VideoEnabledIndicator` components provide gateways with interactive controls and visual cues to manage the video enabled state during a broadcast.
`VideoEnabledTrigger` and `VideoEnabledIndicator` integrate together to form
the typical video on/off interaction for broadcasts. They do not have to be
used together and can combine with other components.
## Features
* Controls the video input state and conditionally renders based on video input
on/off status, customizable with the `matcher` pattern
* Keyboard hotkeys and adheres to [WAI-ARIA](https://w3c.github.io/aria/) design
patterns
* Handles all common browser APIs, and old WebKit/Firefox APIs (see
[caniuse](https://caniuse.com/mdn-api_mediadevices_getusermedia))
The `getUserMedia` browser API used to get the video is only available in
secure contexts (HTTPS).
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Broadcast from "@livepeer/react/broadcast";
export default () => (
);
```
## Props
### `VideoEnabledTrigger`
Accepts all props for a typical button element.
### `VideoEnabledIndicator`
##### `forceMount`
A boolean that, when true, ensures the component is always mounted. This is
particularly useful for managing animations with external animation libraries.
##### `matcher`
A prop intended to define the circumstances under which the
`VideoEnabledIndicator` should be visible. It can be a boolean that corresponds
directly to the audio state or a function that provides custom logic for
visibility determination based on the audio state.
## Data Attributes
### `VideoEnabledTrigger`
#### `data-livepeer-controls-video-enabled-trigger`
Serves to identify the component's role within the broadcast interface.
#### `data-enabled`
Indicates the current video state, `"true"` when video is enabled and `"false"`
when it is disabled.
### `VideoEnabledIndicator`
#### `data-livepeer-controls-video-enabled-indicator`
Identifies the component's role as a visual indicator of the video state within
the broadcast interface.
#### `data-enabled`
Shows the current video enabled state, `"true"` when video is enabled and
`"false"` when it is disabled.
#### `data-visible`
Reflects the visibility status of the indicator, with `"true"` meaning it's
currently visible based on the `matcher` or video state and `"false"` denoting
it's not visible.
This is often used for dynamically applying enter/exit CSS animations.
# Container
Source: https://docs.livepeer.org/v1/sdks/react/broadcast/Container
The `Container` component is the container element for Broadcast. It wraps all other elements and acts as an aspect ratio container by default.
The `Container` component acts as the container div element for the Broadcast,
using either
[@radix-ui/react-aspect-ratio](https://www.radix-ui.com/primitives/docs/components/aspect-ratio)
or a standard div element. It selectively renders one of these based on the
presence of an `aspectRatio` prop. We show above how to disable the aspect
ratio element.
## Features
* Provides an aspect ratio container to reduce
[Cumulative Layout Shift](https://web.dev/cls/)
* Dynamic data attributes for custom styling based on the current media state
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Broadcast from "@livepeer/react/broadcast";
export default () => (
{/* Place child elements here, like Video and Controls */}
{/* Or place other controls outside of here, to not be bound by the aspect ratio Container */}
);
```
## Data Attributes
These attributes are dynamically updated based on the current state.
### `data-livepeer-aspect-ratio` or `data-livepeer-wrapper`
Indicates the container type. It's present if the container is an aspect ratio
container (with `data-livepeer-aspect-ratio`) or a regular div (with
`data-livepeer-wrapper`).
When `aspectRatio` is set to `null` on the Root component, then it will be a
regular div wrapper with `position: relative`.
### `data-fullscreen`
Reflects whether the content is in fullscreen mode.
* `"true"`: The content is in fullscreen mode.
* `"false"`: The content is not in fullscreen mode.
### `data-playing`
Indicates if the content is currently playing.
* `"true"`: The content is playing.
* `"false"`: The content is not playing.
### `data-can-play`
Shows if the content can be played.
* `"true"`: The content can be played.
* `"false"`: The content cannot be played due to some restrictions or lack of
data.
### `data-playback-rate`
Displays the current playback rate.
* `"normal"`: The playback is at normal speed.
* `"fast"`: The playback is at a speed faster than normal.
* `"slow"`: The playback is at a speed slower than normal.
* `"constant"`: The playback rate is constant (neither fast nor slow).
### `data-error`
Indicates if there is an error in the content.
* `"true"`: There is an error in the content.
* `"false"`: There are no errors in the content.
### `data-loading`
Shows if the content is loading.
* `"true"`: The content is loading.
* `"false"`: The content is not loading.
### `data-live`
Indicates if the content is live.
* `"true"`: The content is live.
* `"false"`: The content is not live.
### `data-has-played`
Reflects if the content has been played.
* `"true"`: The content has been played at least once.
* `"false"`: The content has not been played yet.
### `data-controls-hidden`
Shows if the controls are hidden.
* `"true"`: The controls are hidden.
* `"false"`: The controls are visible.
### `data-picture-in-picture`
Indicates if the picture-in-picture mode is active.
* `"true"`: The picture-in-picture mode is active.
* `"false"`: The picture-in-picture mode is not active.
### `data-video-quality`
Displays the current video quality, directly reflecting the `videoQuality` value
from the state. It can be a string indicating the quality level (e.g., `"720p"`,
`"1080p"`).
# Controls
Source: https://docs.livepeer.org/v1/sdks/react/broadcast/Controls
The `Controls` component provides an interactive container for all other broadcast control elements such as `AudioTrigger`, `Fullscreen`, etc.
`Controls` serves as the interactive layer for broadcast control actions, dynamically displayed based on the broadcast state, loading state, or presence of an error. It is designed to automatically show upon user interaction with the Container element and hides based on the `Root` component's `autohide` property.
By default, controls are shown during hover or interaction.
## Features
* Automatic conditional rendering based on user interactions
* Compatible with CSS animations for dynamic enter/exit animations
The visibility of `Controls` is managed automatically, relying on the
`autohide` property of the `Root` component to determine how long after a user
interaction to wait before hiding.
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Broadcast from "@livepeer/react/broadcast";
export default () => (
{/* Place interactive control elements here, like enable/disable broadcast, screenshare toggle, etc. */}
);
```
## Props
### `forceMount`
Ensures the component is always in the DOM, useful for animation controls.
### `autoHide`
Defines the auto-hide delay in milliseconds after user interaction. Default is
3000ms. Set to 0 to disable auto-hide.
## Data Attributes
### `data-livepeer-controls`
Serves to identify the component's role within the broadcast interface.
### `data-visible`
Reflects the visibility status of the controls. It's `"true"` when the controls
are currently visible (not hidden, not loading, no error present, and WebRTC is
supported), and `"false"` when they're not visible.
This is often used for dynamically applying enter/exit CSS animations.
# Enable
Source: https://docs.livepeer.org/v1/sdks/react/broadcast/Enabled
The `EnabledTrigger` and `EnabledIndicator` components provide gateways with interactive controls and visual cues to manage the "enabled" state of the broadcast.
The `Enabled` components are used to generally start and stop the broadcast.
The broadcast, by default, starts disabled so the user can preview their video
before going live.
## Features
* Conditional rendering based on the enabled state, customizable with the
`matcher` pattern
* Dynamic data attributes for custom styling based on the current enabled state
Toggling "enabled" turns WHIP WebRTC ingest on or off, which when "on" the
Broadcast component will make a POST request with an SDP payload to the WHIP
endpoint. When "off", it will stop sending data to the WebRTC ingest.
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Broadcast from "@livepeer/react/broadcast";
export default () => (
);
```
## Props
### `EnabledTrigger`
The component accepts all props suitable for a button element.
### `EnabledIndicator`
The component accepts all props for a span element.
##### `forceMount`
A boolean that, when true, ensures the component is always mounted. This is
particularly useful for managing animations with external animation libraries
and ensuring visibility during dynamic broadcast scenarios.
##### `matcher`
A prop intended to define the circumstances under which the `EnabledIndicator`
should be visible. It can be a boolean that directly corresponds to the enabled
state or a function providing custom logic for visibility determination based on
the enabled state.
## Data Attributes
### `EnabledTrigger`
#### `data-livepeer-controls-enabled-trigger`
Serves to identify the component's role within the broadcast interface.
#### `data-enabled`
Indicates the current broadcast state, `"true"` when broadcasting is enabled and
`"false"` when it is disabled.
### `EnabledIndicator`
#### `data-livepeer-controls-enabled-indicator`
Identifies the component's role as a visual indicator of the broadcast state
within the broadcast interface.
#### `data-enabled`
Shows the current broadcast state, `"true"` when broadcasting is enabled and
`"false"` when it is disabled.
#### `data-visible`
Reflects the visibility status of the indicator, with `"true"` meaning it's
currently visible based on the `matcher` or broadcast state and `"false"`
denoting it's not visible.
This is often used for dynamically applying enter/exit CSS animations.
# Error
Source: https://docs.livepeer.org/v1/sdks/react/broadcast/Error
The `ErrorIndicator` component is a visual representation of error states in broadcast based on error types.
The `Error` component can be shown for all error types, or a subset of them.
It is usually recommended to be more granular in the error types, since some
errors are more "fatal" and some cannot be recovered from.
## Features
* Conditional rendering based on the error state, customizable with the
`matcher` pattern
* Dynamic data attributes for custom styling based on the current error state
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Broadcast from "@livepeer/react/broadcast";
export default () => (
);
```
## Props
The component accepts all props suitable for a div element, in addition to the
following specific props:
### `forceMount`
A boolean to force the component's presence in the DOM, useful for controlling
animations with external libraries.
### `matcher`
A prop to define the condition under which the `ErrorIndicator` should be
visible. It can be a string indicating a broad category of errors (like `"all"`
or `"not-permissions"`) or a more specific error type. Alternatively, it can be
a function for custom logic, receiving the PlaybackError type and returning a
boolean for whether it should be shown.
## Data Attributes
### `data-livepeer-error-indicator`
Always present to indicate the component's role.
### `data-error-state`
Indicates whether there is an error (`"true"` or `"false"`).
### `data-error-type`
Specifies the type of the current error or `"none"` if no error is present.
Could be one of:
`"offline" | "access-control" | "fallback" | "permissions" | "unknown" | "none"`
### `data-visible`
Reflects whether the indicator is currently visible (`"true"` or `"false"`).
This is often used for dynamically applying enter/exit CSS animations.
# Fullscreen
Source: https://docs.livepeer.org/v1/sdks/react/broadcast/Fullscreen
The `FullscreenIndicator` and `FullscreenTrigger` components provide visual cues and interactive elements for fullscreen functionality.
## Features
* Automatic conditional rendering based on fullscreen status and browser API
availability, customizable with the `matcher` pattern
* Handles all browser APIs back to IE11, with special handling for iOS
* Compatible with CSS animations for dynamic enter/exit animations
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Broadcast from "@livepeer/react/broadcast";
export default () => (
);
```
## Props
### `FullscreenIndicator`
#### `forceMount`
A boolean that, when true, keeps the component mounted at all times, useful for
controlling animations with external libraries.
#### `matcher`
A prop to define the condition under which the `FullscreenIndicator` should be
visible. It can be a boolean directly matching the fullscreen state or a
function providing custom logic to determine visibility.
### `FullscreenIndicator`
#### `forceMount`
A boolean that, when true, keeps the component mounted at all times, useful for
controlling animations with external libraries.
#### `matcher`
A prop to define the condition under which the `FullscreenIndicator` should be
visible. It can be a boolean directly matching the fullscreen state or a
function providing custom logic to determine visibility.
## Data Attributes
### `FullscreenIndicator`
#### `data-livepeer-controls-fullscreen-indicator`
Indicates the component's role.
#### `data-fullscreen`
Shows the current fullscreen state (`"true"` or `"false"`).
#### `data-visible`
Reflects whether the indicator is currently visible (`"true"` or `"false"`).
This is often used for dynamically applying enter/exit CSS animations.
### `FullscreenTrigger`
#### `data-livepeer-controls-fullscreen-trigger`
Indicates the component's role.
#### `data-fullscreen-state`
Shows the current fullscreen state (`"true"` or `"false"`). lscreen state
(`"true"` or `"false"`).
# Loading
Source: https://docs.livepeer.org/v1/sdks/react/broadcast/Loading
The `LoadingIndicator` component is a visual indicator of the loading state of the media.
The `Loading` component can be composed with any other elements. Typically it
is combined with Poster
## Features
* Conditional rendering based on the error state, customizable with the
`matcher` pattern
* Dynamic data attributes for custom styling based on the current error state
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Broadcast from "@livepeer/react/broadcast";
export default () => (
);
```
## Props
The component accepts all props suitable for a div element, in addition to the
following specific props:
### `forceMount`
A boolean value that, when set to true, ensures the component is always mounted.
This is particularly useful for managing animations with external animation
libraries.
### `matcher`
A prop intended to define the circumstances under which the `LoadingIndicator`
should be visible. It can be a direct boolean comparison with the loading state
or a function that provides custom logic for visibility determination.
## Data Attributes
### `data-livepeer-loading-indicator`
Serves to identify the component's role.
### `data-loading`
Displays the current loading state, `"true"` when media is loading and `"false"`
when it's not.
### `data-visible`
Indicates the visibility status of the indicator, with `"true"` meaning it's
currently visible and `"false"` denoting it's not.
This is often used for dynamically applying enter/exit CSS animations.
# Picture in Picture
Source: https://docs.livepeer.org/v1/sdks/react/broadcast/PictureInPicture
The `PictureInPictureTrigger` component toggles the picture-in-picture mode.
## Features
* Automatic conditional rendering based on browser API availability,
customizable with the `matcher` pattern
* Supports both the [w3c](https://w3c.github.io/picture-in-picture/) standard
(which most modern browsers support), as well as the
[older Safari/iOS spec](https://developer.apple.com/documentation/webkitjs/adding_picture_in_picture_to_your_safari_media_controls)
(see the browsers which support Picture-in-Picture on
[caniuse](https://caniuse.com/picture-in-picture))
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Broadcast from "@livepeer/react/broadcast";
export default () => (
);
```
## Props
The component accepts all props suitable for a button element.
## Data Attributes
### `data-livepeer-controls-picture-in-picture-trigger`
Serves to identify the component's role.
### `data-picture-in-picture`
Indicates the current picture-in-picture state, `"true"` when the feature is
active and `"false"` otherwise.
### `data-visible`
Reflects the visibility status of the trigger, with `"true"` meaning it's
currently visible (i.e., picture-in-picture is supported and the media is not in
fullscreen mode) and `"false"` denoting it's not visible.
This is often used for dynamically applying enter/exit CSS animations.
# Portal
Source: https://docs.livepeer.org/v1/sdks/react/broadcast/Portal
The `Portal` component allows projection of content into different parts of the DOM.
The `Portal` component is a simple wrapper over
[@radix-ui/react-portal](https://www.radix-ui.com/primitives/docs/utilities/portal#portal).
It inherits all of the documentation for the component.
## Features
* Provides an easy way to portal controls out of the Root components
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Broadcast from "@livepeer/react/broadcast";
export default () => (
{/* Place portalled elements here, which can still
consume the React Context from the Root, but are
appended to the document */}
);
```
## Props
### `children`
React nodes that are to be rendered inside the portal.
### `container`
An optional prop specifying a container element where the portal's children
should be rendered. If not provided, the children are appended to the body of
the document by default.
# Root
Source: https://docs.livepeer.org/v1/sdks/react/broadcast/Root
The `Broadcast.Root` component is the React Context wrapper for Broadcast.
This is a comprehensive example of how the Broadcast elements can fit together
to build an advanced in-browser streaming experience. This does not only show
the Root Broadcast, but how the Root can be used to provide a state store to
all of its children.
## Features
* Pure React Context provider to pass the broadcast and media state store to all
components
* Automatic SDP negotiation with a
[WebRTC WHIP](https://www.ietf.org/archive/id/draft-ietf-wish-whip-01.html)
endpoint
The Broadcast component utilizes WebRTC for streaming and consistently employs
STUN/TURN servers for the WebRTC connection. This setup facilitates
broadcasting despite corporate firewalls or port restrictions. The component
adheres to WHIP/WHEP standards for ingest/egress SDP negotiation, making it
compatible with any WHIP/WHEP ingest endpoint.
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Broadcast from "@livepeer/react/broadcast";
export default () => (
{/* All child components which use the state store. */}
);
```
## Usage
The `Player.Root` component is a React Context wrapper which passes the player
state store down to all of the child components. It is responsible for creating
the [Zustand](https://github.com/pmndrs/zustand) state store which is consumed
by the children, and listens for media/browser events and keeps state in sync.
The Player automatically handles different source types, such as WebRTC, MP4, and HLS.
These are seamlessly integrated so that playback has low latency under all
network conditions.
It is compatible with WebRTC WHEP endpoints, HLS (and low latency HLS), or
typical media file playable by an HTML5 video element (MP4, WebM).
## Props
### `ingestUrl`
Configures the WHIP WebRTC ingest URL for the `Broadcast` component. You can
create the `ingestUrl` by passing
[`getIngest`](/sdks/react/broadcast/get-ingest) a string (interpreted as a
Livepeer Studio stream key or URL), Livepeer Studio stream data, or Cloudflare
stream data. `Broadcast` is compatible with all WHIP playback endpoints.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{...}
```
### `aspectRatio`
Specifies the aspect ratio of the content. Recommended for an optimal
broadcasting experience to minimize
[Cumulative Layout Shift](https://web.dev/cls/). The default value is `16 / 9`.
Set to `null` to disable the aspect ratio container (see `Container`).
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{...}
```
### `forceEnabled`
Determines whether the WebRTC stream should start immediately after the user
allows access to their video/audio input. The default is `false`, which previews
the video first, then streams media to the server upon activation.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{...}
```
### `audio`
Controls whether audio is enabled initially for the broadcast. The default is
`true`. Set to `false` to start the broadcast without requesting an audio track.
This can be an object that adheres to the structure of
[`MediaTrackConstraints`](https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints),
which will constrain the audio track used in the broadcast.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{...}
```
### `video`
Controls whether video is enabled initially for the broadcast. The default is
`true`. Set to `false` to start the broadcast without requesting a video track.
This can be an object that adheres to the structure of
[`MediaTrackConstraints`](https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints),
which will constrain the video track used in the broadcast. This is usually used
to limit the resolution of the video and improve bandwidth usage.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{...}
```
### `hotkeys`
Enables keyboard hotkeys for controlling the broadcast. Enabled by default
(`true`). It's recommended to follow ARIA guidelines by keeping this enabled
unless you're implementing custom hotkeys or there's a conflict with existing
ones.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{...}
```
### `creatorId`
Sets the creator ID for the broadcast, useful for metrics and viewership API
integration.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{...}
```
### `onError`
An optional callback for handling broadcasting errors. It's called with `null`
when the previous error is resolved. The callback receives the parameter:
```ts theme={"theme":{"light":"github-light","dark":"dark-plus"}}
type PlaybackError = {
type: "offline" | "access-control" | "fallback" | "permissions" | "unknown";
message: string;
};
```
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
console.log(error)}>{...}
```
### `timeout`
Sets the timeout duration for playback before switching to the next source,
including SDP negotiation for WebRTC, waiting for WebRTC to play, and server
responses. The default is 10000 milliseconds.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{...}
```
### `storage`
Configures the storage option for saving persistent states like volume and video
quality. The default is `localStorage` in the browser. Set to `null` to disable
storage.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{...}
```
# Screenshare
Source: https://docs.livepeer.org/v1/sdks/react/broadcast/Screenshare
The `ScreenshareTrigger` and `ScreenshareIndicator` components provide gateways with controls for managing the screenshare state.
## Features
* Automatic conditional rendering based on
[`getDisplayMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia)
status and browser API availability, customizable with the `matcher` pattern
* Handles all common browser APIs, and old WebKit APIs (see
[caniuse](https://caniuse.com/mdn-api_mediadevices_getdisplaymedia))
* Compatible with CSS animations for dynamic enter/exit animations
The `getDisplayMedia` API is only available in secure contexts (HTTPS).
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Broadcast from "@livepeer/react/broadcast";
export default () => (
);
```
## Props
### `ScreenshareTrigger`
Accepts all props for a typical button HTML element.
### `ScreenshareIndicator`
#### `forceMount`
A boolean that, when true, keeps the component mounted at all times, useful for
controlling animations with external libraries.
#### `matcher`
A prop to define the condition under which the `ScreenshareIndicator` should be
visible. It can be a boolean directly matching the screenshare state or a
function providing custom logic to determine visibility.
## Data Attributes
### `ScreenshareTrigger`
#### `data-livepeer-controls-screenshare-trigger`
Serves to identify the component's role within the broadcast interface.
#### `data-active`
Indicates the current screenshare state, `"true"` when screensharing is active
and `"false"` when it is not.
#### `data-visible`
Reflects the visibility status of the trigger, with `"true"` meaning it's
currently visible (i.e., screensharing is supported) and `"false"` denoting it's
not visible.
### `ScreenshareIndicator`
#### `data-livepeer-controls-screenshare-indicator`
Identifies the component's role as a visual indicator of the screenshare state
within the broadcast interface.
#### `data-active`
Shows the current screenshare state, `"true"` when screensharing is active and
`"false"` when it is not.
#### `data-visible`
Reflects the visibility status of the indicator, with `"true"` meaning it's
currently visible based on the `matcher` or screenshare state and `"false"`
denoting it's not visible.
This is often used for dynamically applying enter/exit CSS animations.
# Source
Source: https://docs.livepeer.org/v1/sdks/react/broadcast/Source
The `SourceSelect` component provides gateways with a dropdown interface to choose between different media source devices like cameras and microphones.
All of the `SourceSelect` components extend from
[`@radix-ui/react-select`](https://www.radix-ui.com/primitives/docs/components/select),
and inherits all of the documentation for those components.
## Features
* Synchronizes state with the user media and the broadcast
* Adheres to [WAI-ARIA](https://w3c.github.io/aria/) design patterns
* Persists to `localStorage` by default (with storage overrides customizable in
`Root`)
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Broadcast from "@livepeer/react/broadcast";
export default () => (
);
```
## Props
### `SourceSelect`
Takes all props of the
[Radix Select Root](https://www.radix-ui.com/primitives/docs/components/select)
component.
#### `forceMount`
A boolean that, when set to true, ensures the component is always mounted. If
this is not specified, it will only be shown when sources are detected.
#### `type`
A string indicating the type of media devices to list in the dropdown, either
`"audioinput"` for microphones or `"videoinput"` for cameras.
#### `children`
A function that takes the available media devices as input and returns the React
nodes (options) to be rendered inside the dropdown. This enables dynamic
population of the dropdown based on the available devices. ™
The device ID must be used for the `SelectItem` value.
## Data Attributes
### `data-livepeer-source-select`
Serves to identify the component's role within the broadcast interface.
### `data-type`
Indicates the type of media source device the dropdown is currently displaying,
either `"audioinput"` for microphones or `"videoinput"` for cameras.
### `data-visible`
Reflects the visibility status of the dropdown, with `"true"` meaning it's
currently visible (i.e., device support is available) and `"false"` denoting
it's not visible.
# Status
Source: https://docs.livepeer.org/v1/sdks/react/broadcast/Status
The `StatusIndicator` component provides visual cues for the broadcast status.
## Features
* Synchronizes broadcast status with a visual indicator
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Broadcast from "@livepeer/react/broadcast";
export default () => (
);
```
## Props
### `forceMount`
A boolean that, when true, ensures the component is always mounted. This is
particularly useful for managing animations with external animation libraries.
### `matcher`
A prop required to define the conditions under which the `StatusIndicator`
should be visible. It can be a specific `BroadcastStatus` value or a function
that provides custom logic for visibility determination based on the broadcast
status.
The status can be of the type: `"live" | "pending" | "idle"`
## Data Attributes
### `data-livepeer-controls-status-indicator`
Serves to identify the component's role within the broadcast interface.
### `data-status`
Shows the current broadcast status as a string.
The status can be of the type: `"live" | "pending" | "idle"`
### `data-visible`
Reflects the visibility status of the indicator, with `"true"` meaning it's
currently visible based on the `matcher` or broadcast status and `"false"`
denoting it's not visible.
# Video
Source: https://docs.livepeer.org/v1/sdks/react/broadcast/Video
The `Video` component is a container for previewing broadcast video content.
As you can see in the above example, the component will request permissions
for video/audio input - so it prompts the user for access to their microphone
and camera **upon component mount**.
The `getUserMedia` browser API used to get the video/audio is only available in
secure contexts (HTTPS).
#### Features
* Synchronizes state with the HTML5 video element
* Keyboard hotkeys (`B` to toggle whether the broadcast is enabled, `L` to
toggle audio, `V` to toggle video, `D` to broadcast display media, `C` for
next video source, `M` for next audio source)
* Adheres to [WAI-ARIA](https://w3c.github.io/aria/) design patterns
* Handles all common browser APIs, and old WebKit/Firefox APIs (see
[caniuse](https://caniuse.com/mdn-api_mediadevices_getusermedia))
The Broadcast above will work with only keyboard shortcuts, without any custom
controls.
### Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Broadcast from "@livepeer/react/broadcast";
export default () => (
);
```
## Props
The component accepts most props suitable for a HTML5 `video` tag, except for
`src` and `poster` which are managed internally or provided explicitly through
props.
## Data Attributes
### `data-livepeer-video`
Serves to identify the component's role within the Broadcast.
### `data-enabled`
Indicates the enabled state of the broadcast, `"true"` when broadcasting is
enabled and `"false"` when it is not.
# getIngest
Source: https://docs.livepeer.org/v1/sdks/react/broadcast/get-ingest
`getIngest` is a utility function for converting various types of ingest information into a standardized WHIP URL format suitable for broadcasting.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Broadcast from "@livepeer/react/broadcast";
import { getIngest } from "@livepeer/react";
// Usage with a stream key
const streamKey = "your-stream-key-here";
const whipUrl = getIngest(streamKey, {
baseUrl: "https://playback.livepeer.studio/webrtc",
});
// Usage with Livepeer stream data
const livepeerStreamData = {
id: "stream-id",
streamKey: "your-stream-key-here",
// Other unused Livepeer stream data...
};
// This is either a string or null, depending on whether
// the input was parsed successfully
const whipUrlFromLivepeer = getIngest(livepeerStreamData);
export default () => (
{/* All child components. */}
);
```
### Functionality
`getIngest` simplifies the process of preparing ingest sources for broadcasting
by standardizing them into WHIP URLs.
#### Input Types
The function supports a variety of input types to accommodate different
broadcasting setups:
* **String**: Directly returns the string if it's a valid URL. Constructs a WHIP
URL using a base URL for stream keys.
* **LivepeerStream**: Uses the `streamKey` from Livepeer stream data to generate
a WHIP URL.
* **CloudflareStreamData**: Extracts the URL from Cloudflare stream data
objects.
Optional parameters (`opts`) include:
* **baseUrl**: The base URL for constructing WHIP URLs. Essential when the input
is a stream key.
#### Output Format
The function outputs a WHIP URL string suitable for use in broadcasting setups,
or `null` if the input can't be processed into a valid WHIP URL.
# useBroadcastContext
Source: https://docs.livepeer.org/v1/sdks/react/broadcast/useBroadcastContext
The `useBroadcastContext` hook lets you build custom components which interact directly with the Broadcast state store.
The `useStore` hook is from
[`zustand`](https://github.com/pmndrs/zustand?tab=readme-ov-file#using-zustand-without-react),
and inherits all of the documentation for Zustand stores.
## Features
* Flexible interaction with the broadcast state store
* Based on Zustand's `useStore` hooks
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Broadcast from "@livepeer/react/broadcast";
import { useBroadcastContext, useStore } from "@livepeer/react/broadcast";
export default () => (
{/** The `useBroadcastContext` hook can be used in any component,
as long as it's inside the Broadcast.Root React Context provider */}
);
function CustomComponent({
style,
__scopeBroadcast,
}: Broadcast.BroadcastScopedProps<{}>) {
const context = useBroadcastContext("CustomComponent", __scopeBroadcast);
// use selectors with the Zustand store, to make sure your component doesn't render
// on every store state change
const { status } = useStore(context.store, ({ status }) => ({
status,
}));
return status;
}
```
## State
The `useBroadcastContext` hook returns a Zustand store, which contains the
`BroadcastState`.
### `aria`
The ARIA text for the controls given the current state.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
type BroadcastAriaText = {
audioTrigger: string;
start: string;
screenshareTrigger: string;
videoTrigger: string;
};
```
### `audio`
Indicates whether the broadcast's audio track is turned on.
### `enabled`
Specifies whether the broadcast is currently active or in "preview" mode.
### `hydrated`
Reflects whether the broadcast store is hydrated, indicating if initial data has
been loaded into the state.
### `mediaDevices`
A list of the current media devices (based on
[MediaDeviceInfo](https://developer.mozilla.org/en-US/docs/Web/API/MediaDeviceInfo)),
which changes based on permissions or when a user starts sharing their display.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
type MediaDeviceInfoExtended = Omit & {
/**
* This is a convenience field added to MediaDeviceInfo to help easily add a device picker.
*
* For security reasons, the label field will blank unless an active media stream exists
* or the user has granted persistent permission for media device access. The set of device labels
* could otherwise be used as part of a fingerprinting mechanism to identify a user.
*
* When the label field is not blank, these are the same value. Otherwise, the value is a friendly default.
*/
friendlyName: string;
/**
* For security reasons, the label field is blank unless an active media stream exists
* or the user has granted persistent permission for media device access. The set of device labels
* could otherwise be used as part of a fingerprinting mechanism to identify a user.
*
* We override it here to be null when it is blank, for easier developer usage.
*/
label: string | null;
};
mediaDevices: MediaDeviceInfoExtended[] | null;
```
### `mediaStream`
The [MediaStream](https://developer.mozilla.org/en-US/docs/Web/API/MediaStream)
for the current broadcast, containing the audio and video tracks.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
mediaStream: MediaStream | null;
```
### `mounted`
Whether the broadcast component is currently mounted in the DOM.
### `peerConnection`
The
[RTCPeerConnection](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection)
object for the broadcast, managing the connection between the local and remote
peers.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
peerConnection: RTCPeerConnection | null;
```
### `status`
The current status of the broadcast, which can be "live", "pending", or "idle".
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
status: "live" | "pending" | "idle";
```
### `ingestUrl`
The WHIP ingest URL used for the broadcast.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
ingestUrl: string | null;
```
### `video`
Indicates if the broadcast's video track is turned on.
### `mediaDeviceIds`
The IDs of the currently selected media devices.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
mediaDeviceIds: MediaDeviceIds;
```
### `__initialProps`
The initial properties passed into the broadcast component. This is an internal
object used by Broadcast.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
__initialProps: InitialBroadcastProps;
```
### `__device`
Information about the broadcast device's capabilities and support. This is an
internal object used by Broadcast, but can be used for detecting device
capabilities.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
type BroadcastDeviceInformation = {
version: string;
/** If the environment supports mediaDevices */
isMediaDevicesSupported: boolean;
/** If the environment supports RTCPeerConnection */
isRTCPeerConnectionSupported: boolean;
/** If the environment supports sharing display media */
isDisplayMediaSupported: boolean;
};
__device: BroadcastDeviceInformation;
```
### `__controls`
The current state of broadcast controls. This is an internal object used by
Broadcast.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
__controls: BroadcastControlsState;
```
### `__controlsFunctions`
An object containing functions to manipulate the broadcast's state, such as
toggling audio/video, updating the media stream, and setting the peer
connection.
These functions are internal - please refer to the UI Kit source code before
interacting with these functions.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
__controlsFunctions: {
requestDeviceListInfo: () => void;
requestForceRenegotiate: () => void;
requestMediaDeviceId: (deviceId: AudioDeviceId, type: keyof MediaDeviceIds) => void;
rotateAudioSource: () => void;
rotateVideoSource: () => void;
setIngestUrl: (ingestUrl: string) => void;
setInitialState: (ids: MediaDeviceIds, audio: boolean, video: boolean) => void;
setPeerConnection: (peerConnection: RTCPeerConnection) => void;
setStatus: (status: BroadcastStatus) => void;
setMediaDeviceIds: (mediaDevices: Partial) => void;
toggleAudio: () => void;
toggleDisplayMedia: () => void;
toggleEnabled: () => void;
toggleVideo: () => void;
updateDeviceList: (mediaDevices: MediaDeviceInfo[]) => void;
updateMediaStream: (mediaStream: MediaStream) => void;
};
```
# Getting Started
Source: https://docs.livepeer.org/v1/sdks/react/getting-started
Get started building with Livepeer React
Livepeer React is a set of prebuilt and customizable UI primitives for building
live or on-demand video experiences.
## Installation
Install Livepeer React using your favorite package manager.
```
npm i @livepeer/react
```
## Build with the primitives
You can use `Player` primitives to build a media playback experience, and
`Broadcast` primitives to build an in-browser broadcasting experience.
Below, we create a simple player and broadcast experience with minimal controls.
The player only includes a play/pause button, and the broadcast has a start/stop
streaming button.
## Integrate with Studio
Now that we've started using the primitives, we need something to play or
broadcast! We can integrate with the Livepeer Studio API to start playing media.
The below example shows the use of the `livepeer` JS SDK, but any other
language's SDK can be used to fetch the playback info or stream object.
```ts theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// this is a server function, which uses the API key
// on the backend
import { Livepeer } from "livepeer"
import { getSrc } from "@livepeer/react/external";
const livepeer = new Livepeer({
apiKey: "YOUR_API_KEY"
})
export async function getSourceForPlaybackId(playbackId: string) {
const response = await livepeer.playback.get(playbackId);
// the return value can be passed directly to the Player as `src`
return getSrc(response.playbackInfo);
}
```
```ts theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// this is a server function, which uses the API key
// on the backend
import { Livepeer } from "livepeer"
import { getIngest } from "@livepeer/react/external";
const livepeer = new Livepeer({
apiKey: "YOUR_API_KEY"
})
export async function getIngestUrlForStreamId(streamId: string) {
const stream = await livepeer.stream.get(streamId);
// the return value can be passed directly to the Broadcast as `ingestUrl`
return getIngest(stream.stream);
}
```
Want to learn more? Continue reading the documentation for more details.
# Broadcast
Source: https://docs.livepeer.org/v1/sdks/react/migration/3.x/Broadcast
The Broadcast component provides an easy way to livestream video or audio.
The `Broadcast` component provides an easy way to livestream video or audio,
including camera and screen sources.
It automatically handles WebRTC connection and allows extremely low latency
livestreaming.
## Usage
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Broadcast } from '@livepeer/react';
```
The following example assumes a stream was created via `useCreateStream`, and
the `streamKey` was passed to the Broadcast component.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Broadcast } from '@livepeer/react';
function BroadcastComponent() {
return (
);
};
```
React Native is not supported yet.
## Configuration
### streamKey
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function BroadcastComponent() {
return ;
}
```
The `streamKey` passed to the `Broadcast` component is used to connect to the
WebRTC ingest URL.
### title
The `title` for the content. This is highly recommended, since it is used for
[accessibility labels](https://web.dev/semantics-aria/) in the Broadcast. If you
do not want to show the title visually, see [`showTitle`](#showtitle).
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function BroadcastComponent() {
return ;
}
```
### showTitle
Enables/disables the title component.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function BroadcastComponent() {
return (
);
}
```
### displayMediaOptions
The display media stream options to use when requesting screen share. This is
usually a set of audio and video
[`MediaTrackConstraints`](https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints)
which are passed to the browser to limit the sources available to the user.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function BroadcastComponent() {
return (
);
}
```
### aspectRatio
Sets the aspect ratio for the content. Highly recommended for a great
broadcasting experience (for more information, see
[Cumulative Layout Shift](https://web.dev/cls/)). Defaults to `16to9`.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function BroadcastComponent() {
return (
);
}
```
### controls
Configures the timeout for autohiding controls, default volume, and (only on
web) if keyboard hotkeys for controlling the broadcast are enabled.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function BroadcastComponent() {
return (
);
}
```
### muted
Sets the video to muted when the broadcast started.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function BroadcastComponent() {
return ;
}
```
### objectFit
Sets the video's
[object fit](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit)
property. Defaults to `contain`. `cover` is usually used when there is a
guarantee that the `aspectRatio` matches the content displayed in the Broadcast.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function BroadcastComponent() {
return (
);
}
```
### showPipButton
Shows the Picture-in-Picture button to the left of the fullscreen button.
Defaults to `false`. See [children](#children) for an example on how to use the
underlying ``.
We support both the [w3c](https://w3c.github.io/picture-in-picture/) standard
(which most modern browsers support), as well as the [older Safari/iOS
spec](https://developer.apple.com/documentation/webkitjs/adding_picture_in_picture_to_your_safari_media_controls).
See the browsers which support Picture-in-Picture on
[caniuse](https://caniuse.com/picture-in-picture).
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Player } from "@livepeer/react";
function BroadcastComponent() {
return (
);
}
```
### theme
Sets the Player-specific theme overrides. It is recommended to use
[`LivepeerConfig`](/sdks/react/migration/3.x/LivepeerConfig) for any global app
styles, and the `theme` prop to override those styles on a per-Broadcast basis.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function BroadcastComponent() {
return (
);
}
```
### children
Overrides the custom controls for the Player. See the
[`Broadcast` default controls](https://github.com/livepeer/react/blob/main/packages/react/src/components/media/Broadcast.tsx)
for more details on how the `ControlsContainer` component is used.
This can be used alongside `renderChildrenOutsideContainer` to render the
children outside of the aspect ratio container. This is used for custom
controls, so children of the Player can use `useMediaController` without any
parent elements.
### mediaElementRef
Sets the React
[callback `ref`](https://reactjs.org/docs/refs-and-the-dom.html#callback-refs)
passed to the underlying media element. Useful when integrating with third party
tools, or when access to the underlying video element is needed (usually it
isn't!). Simple refs are not supported - only callback refs (which will be
called when the underlying media element is set/updated on initial render).
### onPlaybackStatusUpdate
Callback called when the Broadcast store status updates. **This should be used
with `playbackStatusSelector` to limit state updates.** This allows developers
to use the underlying state of the Broadcast component in their UI.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function BroadcastComponent() {
return (
console.log(muted)}
playbackStatusSelector={(state) => state.muted}
/>
);
}
```
## Technical Details
### WebRTC Broadcasting
The Broadcast component uses WebRTC for broadcasting. This always uses STUN/TURN
servers for the WebRTC connection, to allow the broadcast to circumvent
corporate firewalls and other port blocks. We use the WHIP/WHEP standards for
ingest/egress SDP negotiation, so this means that the Broadcast component can be
used with *any* WHIP/WHEP ingest endpoint - not only the providers we have.
# LivepeerConfig
Source: https://docs.livepeer.org/v1/sdks/react/migration/3.x/LivepeerConfig
The LivepeerConfig component manages configuration for all hooks using React Context.
The `LivepeerConfig` component manages configuration for all hooks using
[React Context](https://reactjs.org/docs/context.html).
## Usage
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { LivepeerConfig } from '@livepeer/react';
```
The `LivepeerConfig` should wrap all of your pages, so every page can use hooks provided by Livepeer React.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const client = createReactClient({
provider: studioProvider({ apiKey: 'yourStudioApiKey' }),
});
function App() {
return (
);
}
```
If you are using an SSR framework (like Next.js), see [SSR](#ssr) for specific instructions on how to configure
the `head` of the document, to ensure hydration happens correctly.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { LivepeerConfig } from '@livepeer/react-native';
```
The `LivepeerConfig` should wrap all of your screens, so every screen can use hooks provided by Livepeer React.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const client = createReactClient({
provider: studioProvider({ apiKey: 'yourStudioApiKey' }),
});
function App() {
return (
);
}
```
## Configuration
### client
A livepeer [`Client`](/sdks/react/migration/3.x/client) instance that consists
of configuration options. Required to connect to a provider.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const client = createReactClient({
provider: studioProvider({ apiKey: "yourStudioApiKey" }),
});
function App() {
return (
);
}
```
### theme
Sets the global theme overrides. It is recommended to use this for any global
app styles. This is optional and every value has a default. See the source code
for more information.
```tsx {5-16,20} theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const client = createReactClient({
provider: studioProvider({ apiKey: "yourStudioApiKey" }),
});
const theme: ThemeConfig = {
colors: {
accent: "rgb(0, 145, 255)",
containerBorderColor: "rgba(0, 145, 255, 0.9)",
},
fonts: {
display: "Inter",
},
radii: {
slider: "4px",
},
};
function App() {
return (
);
}
```
## SSR
The following section only applies to web-based use-cases - React Native has
no concept of SSR.
You can get access to the CSS string by using the `getCssText` function. This
function is made available by the createStitches function. This will give you
all the CSS you need to server-side render it.
For a better hydration strategy, we highly recommend adding an `id="stitches"`
to your style tag.
Here's an example of SSR with Next.js:
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import NextDocument, { Html, Head, Main, NextScript } from "next/document";
import { getCssText } from "@livepeer/react";
export default class Document extends NextDocument {
render() {
return (
);
}
}
```
See the [Stitches](https://stitches.dev/docs/server-side-rendering)
documentation for further information.
# Player
Source: https://docs.livepeer.org/v1/sdks/react/migration/3.x/Player
The Player component provides an easy way to display video or audio.
The `Player` component provides an easy way to display video or audio.
It automatically handles different source types from a Livepeer provider, such
as WebRTC, MP4, and HLS. These are seamlessly integrated so that playback has
low latency under all network conditions.
## Usage
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Player } from '@livepeer/react';
```
The following example assumes a stream or asset was created via `useCreateAsset`
or `useCreateStream`, and the `playbackId` was passed to the viewer.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Player } from '@livepeer/react';
import Image from 'next/image';
import blenderPoster from '../../../public/images/blender-poster.png';
const PosterImage = () => {
return (
);
};
function PlayerComponent() {
return (
}
showPipButton
objectFit="cover"
priority
/>
);
};
```
Here we also introduce a custom `PosterImage` React component, which is
described in more detail below in [`poster`](#poster) configuration.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Player } from '@livepeer/react-native';
```
The following example assumes a stream or asset was created via `useCreateAsset`
or `useCreateStream`, and the `playbackId` was passed to the viewer.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Player } from '@livepeer/react-native';
import blenderPoster from './assets/images/blender-poster.png';
function PlayerComponent() {
return (
);
};
```
## Compatibility
| Browser | Version |
| ------------------ | ------- |
| Chrome | 102+ |
| Chrome for Android | 105+ |
| iOS Safari | 12.2+ |
| Edge | 103+ |
| Safari | 13.1+ |
| Firefox | 103+ |
| Opera | 89+ |
| Samsung Internet | 17+ |
| UC Browser | 13.4+ |
| Firefox Android | 104+ |
| Opera Mini | all |
We aim to support
[\~93%](https://browsersl.ist/#q=last+2+versions%2C%3E+0.2%25%2Cnot+dead) of
browsers tracked on [caniuse](https://caniuse.com/). We use
[browserslist](https://browsersl.ist/) to track compatibility and
[core-js](https://github.com/zloirock/core-js) for polyfills.
| Framework | Version |
| ------------ | ------- |
| React Native | 0.64.0+ |
| Expo | 43+ |
| React | 17+ |
We aim to support the latest versions of React Native and Expo. If you are
using an older version of Expo or React Native, we highly recommend upgrading
to ensure compatibility.
## Configuration
### playbackId or src
A `playbackId` for an
[asset](https://github.com/livepeer/react/blob/main/packages/core/src/types/provider.ts)
or
[Stream](https://github.com/livepeer/react/blob/main/packages/core/src/types/provider.ts),
or `src`, a media source URL. One of these is required.
#### playbackId
If a playback ID is provided, the playback URL corresponding to the playback
ID will be automatically fetched.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
The `playbackId` passed to the `Player` can be either a short playback ID which
is created on asset/stream creation, or, for an asset, an IPFS CID. If the
provided IPFS CID or IPFS/Arweave URL has not been uploaded yet, it can be
auto-uploaded and played back - see [`autoUrlUpload`](#autourlupload) for more
details.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// only after the asset has been persisted to IPFS
// equivalent to the above example
function PlayerComponent() {
return (
);
}
```
#### src
Using an arbitrary `src` that is not from a provider will not be transcoded
(unless [`autoUrlUpload`](#autourlupload) is used), and will take up
significant network bandwidth. It's highly recommended to upload media to a
provider, and serve content to viewers with a `playbackId`.
The Player also supports an arbitrary `src` URL which can correspond to any
common video or audio which most browsers support. See
[caniuse video format](https://caniuse.com/?search=video%20format) for more
details on browser support.
Metrics reporting **will not work** with an arbitrary `src` (e.g. not a Studio
playback URL).
If the `src` is an IPFS/Arweave URL, it can be auto-uploaded and played back -
see [`autoUrlUpload`](#autourlupload) for more details.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const src =
"https://ipfs.livepeer.studio/ipfs/QmURv3J5BGsz23GaCUm7oXncm2M9SCj8RQDuFPGzAFSJw8";
function PlayerComponent() {
return ;
}
```
### jwt or accessKey
This section defines ways to play back a video which has a playback policy
applied to it. Your application can prevent playback unless the user meets
application-specific requirements (this can be done either with JWTs or
webhooks, and solves use-cases like restricting viewership to users who own an
NFT, have created an account on your platform, are part of a multisig, etc).
#### jwt
The JSON Web Token (JWT) used to access media gated by a `jwt` playback policy.
Alternatively, `accessKey` can be used for a `webhook` playback policy. See the
[Access Control example](/developers/guides/access-control-jwt) for more
details.
Access control is now supported for both streams and assets!
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
#### accessKey
The access key used to access media behind a `webhook` playback policy.
Alternatively, `onAccessKeyRequest` can be used to return this access key in a
callback. See the
[Access Control example](/developers/guides/access-control-webhooks) for more
details.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
#### onAccessKeyRequest
A callback which returns the access key used to gate access to media. Similar to
`accessKey` above, this is used to gate content based on a `webhook` playback
policy. This is used instead of the `accessKey` prop, and can be asynchronous
and accepts any Promise or simple callback which returns a string. See the
[Access Control example](/developers/guides/access-control-webhooks) for more
details.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
{
return "access-key";
}}
/>
);
}
```
### priority
When true, the media will be considered high priority and preload. Lazy loading
is automatically disabled for media using `priority`. You should use the
priority property on any media detected as the
[Largest Contentful Paint (LCP)](https://web.dev/lcp/) element. It may be
appropriate to have multiple, as different content may be the LCP element for
different viewport sizes.
Should only be used when the media is visible above the fold. Defaults to false.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
### lowLatency
When enabled, the Player will play back **live streams** with low-latency
WebRTC. Defaults to `true`. If this does not succeed in playing back (commonly
due to a slow network or connectivity issues), the Player will automatically
fall back to HLS playback. Also, if the stream contains B-frames (bidirectional
frames, which are common for users streaming with OBS or other streaming apps),
the Player will automatically switch to HLS, so that out-of-order frames are not
displayed.
OBS users should be instructed to use the Livepeer stream profile, or to
manually turn off B-frames in their stream. See our [Stream from
OBS](/developers/guides/stream-via-obs) docs for more information.
This only applies to video elements which are playing back livestreams - assets
will play back with MP4 or HLS.
You may also specify `"force"`, which forces WebRTC and disables fallback to
HLS. This is not a recommended default unless your application requires low
latency (and should not play if low latency is not available), due to the
possible connectivity issues which WebRTC can face, which HLS is not subject to.
We are planning on adding similar functionality to the React Native `Player` -
please reach out on Discord if you are interested.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
### clipLength
The clip length enables the "live clipping" feature - the value is in seconds,
and controls the length of the clip that is created when the clip button is
clicked by a viewer. This can be one of 90, 60, 45, 30, 15, or 10 seconds.
This allows for dynamic viewing experiences, along with the `onClipStarted`,
`onClipCreated`, and `onClipError` callbacks for clips.
You can use the `onClipStarted`, `onClipCreated`, and `onClipError` callbacks
to control UI outside of the Player, to show toasts or other loading
indicators, as well as track the status of the Asset which is created and
processed. See `useAsset` for how to poll the status of the asset.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
{
console.log("Clip API request is pending...");
}}
onClipCreated={(asset: Asset) => {
// poll the status of the asset for the
// download URL or playback ID
console.log(asset.id);
}}
onClipError={(error: Error) => {
console.error(error.message);
}}
/>
);
}
```
### playRecording
When allowed, the Player will include recording URLs in playback. This is the
HLS URL that allows users to watch the entire recording of a stream, without
requiring the user to play from the latest playhead (as is usually required in
stream playback). This can be used to create historical clipping experiences for
streams - users can watch a version of the stream that constantly appended with
the latest segments.
Keep in mind that latency for the latest segments will be higher when this
option is enabled, and is not recommended for low latency applications.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
### title
The `title` for the content. This is highly recommended, since it is used for
[accessibility labels](https://web.dev/semantics-aria/) in the Player. If you do
not want to show the title visually, see [`showTitle`](#showtitle).
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
### showTitle
Enables/disables the title component.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
### aspectRatio
Sets the aspect ratio for the content. Highly recommended for a great viewing
experience (for more information, see
[Cumulative Layout Shift](https://web.dev/cls/)). Defaults to `16to9`.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
### loop
Sets whether the content will loop when finished. Defaults to `false`.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
### poster
Sets the poster image. This can be either a string for an image URL, or a React
component.
The `poster` can be a simple image URL, and it will be rendered with a regular
`img` HTML tag.
It is recommended to use an optimized React image component for this (see
below), as opposed to passing a simple URL.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
If the poster is a React component, it will be rendered with similar CSS
attributes to the `img` above. In the below example, we show the use of
[Next.js Image](https://nextjs.org/docs/basic-features/image-optimization) to
render an optimized image, which will automatically handle slow network
conditions/different device sizes.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Player } from "@livepeer/react";
import Image from "next/image";
import blenderPoster from "./images/blender-poster.png";
const PosterImage = () => {
return (
);
};
function PlayerComponent() {
return (
}
/>
);
}
```
Sets the poster image. This can be either a remote URL or a local file resource.
It is recommended to use a local file resource, as opposed to passing a remote
URL. Since this image is used during a loading state, it will ensure a smooth
experience for users.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import posterImage from "./images/blender-poster.png";
function PlayerComponent() {
return (
);
}
```
### showLoadingSpinner
Shows/hides the loading spinner for the media content. Defaults to `true`.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
### hlsConfig
Sets the underlying HLS.js config used for playback. See the
[HLS.js docs](https://github.com/video-dev/hls.js/blob/8d75e45992a7139e7cf9b11a056c8474e9ef4546/docs/API.md)
for more details on the possible values.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
### webrtcConfig
Sets the underlying WebRTC config used for
[WHEP SDP negotiation](https://datatracker.ietf.org/doc/draft-murillo-whep/).
The possible config options are `constant` and `sdpTimeout`.
A `constant=true` boolean indicates that audio will not be distorted if the
playhead falls behind the livestream. This is usually used for music
applications, where audio quality and consistency is more important than
latency.
The `sdpTimeout` config sets the amount of time in milliseconds that the Player
will wait for a response from SDP negotiation before falling back to HLS.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
### controls
Configures the timeout for autohiding controls, default volume, and (only on
web) if keyboard hotkeys for controlling video are enabled.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
### autoPlay and muted
Sets the video to autoplay when the content comes into focus on the webpage. If
`autoPlay` is specified, `muted` will be forced to be `true`. This is
[enforced in many modern browsers](https://developer.chrome.com/blog/autoplay/).
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
### objectFit
Sets the video's
[object fit](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit)
property. Defaults to `contain`. `cover` is usually used when there is a
guarantee that the `aspectRatio` matches the content displayed in the Player.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
### showPipButton
Shows the Picture-in-Picture button to the left of the fullscreen button.
Defaults to `false`. See [children](#children) for an example on how to use the
underlying ``.
We support both the [w3c](https://w3c.github.io/picture-in-picture/) standard
(which most modern browsers support), as well as the [older Safari/iOS
spec](https://developer.apple.com/documentation/webkitjs/adding_picture_in_picture_to_your_safari_media_controls).
See the browsers which support Picture-in-Picture on
[caniuse](https://caniuse.com/picture-in-picture).
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Player } from "@livepeer/react";
function PlayerComponent() {
return (
);
}
```
Picture-in-Picture is not supported in React Native, due to lack of support in
`expo-av`.
### viewerId
Allows a wallet identifier to be passed to the backend which allows for querying
views by an identifier. This should be an wallet's public address.
We are planning on adding further features to the viewer ID, such as "verified
views" with a provable signature claim attached to these view counts. Reach
out to us on [Discord](https://discord.gg/livepeer) if you're interested!
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
### autoUrlUpload
Enables automatic upload and playback from decentralized storage providers.
Currently supports IPFS CIDs and IPFS/Arweave URLs. Defaults to `true`.
For IPFS HTTP gateway URLs, the player currently only supports “path style”
URLs and does not support “subdomain style” URLs. The player will support both
styles of URLs in a future update.
If `fallback` is specified, while the URL upload is being processed in the
background, the video will start non-transcoded playback immediately (defaulting
to `w3s.link` for IPFS and `arweave.net` for Arweave). Once this finishes, the
Player will switch to playing from the transcoded version from the Livepeer
provider. To show/hide the indicator of current upload progress, see
[`showUploadingIndicator`](#showuploadingindicator).
It is highly recommended for the best playback experience to upload from an
Arweave/IPFS URL using `useCreateAsset` (with the format `ipfs://` or
`ar://`) before presenting the content to the user - the first view with
automatic URL upload can take a few minutes, then it will be permanently cached
and play back quickly.
An IPFS [v0 or v1 CID](https://docs.ipfs.tech/concepts/content-addressing/) or
IPFS/Arweave URL (including directories) can be passed as the `src` or
`playbackID` to the Player, and it will automatically detect if it is a
dStorage identifier and attempt to play from a cached version. If the API does
not have a cached version with the corresponding ID, the Player will upload
the content using IPFS/Arweave, and then start playing the transcoded content
back. This may take a few minutes. If `fallback` is specified, it will attempt
to play back instantly from the provided gateway or default gateway.
For best performance, use a custom gateway URL, and ideally, use the same
gateway and pinning service, to avoid timeout errors.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
### showUploadingIndicator
Shows/hides the uploading indication for `autoUrlUpload`. Defaults to `true` -
only used with `autoUrlUpload`.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
### theme
Sets the Player-specific theme overrides. It is recommended to use
[`LivepeerConfig`](/sdks/react/migration/3.x/LivepeerConfig) for any global app
styles, and the `theme` prop to override those styles on a per-Player basis.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
### children
Overrides the custom controls for the Player. See the
[`Player` default controls](https://github.com/livepeer/react/blob/main/packages/react/src/components/media/Player.tsx)
for more details on how the `ControlsContainer` component is used.
This can be used alongside `renderChildrenOutsideContainer` to render the
children outside of the aspect ratio container. This is used for custom
controls, so children of the Player can use `useMediaController` without any
parent elements.
Overrides the custom controls for the Player. See the
[React Native `Player` default controls](https://github.com/livepeer/react/blob/main/packages/react-native/src/components/media/Player.tsx)
for more details on how the `ControlsContainer` component is used.
This can be used alongside `renderChildrenOutsideContainer` to render the
children outside of the aspect ratio container. This is used for custom
controls, so children of the Player can use `useMediaController` without any
parent elements.
### streamOfflineErrorComponent
Sets the error component that is shown when playback fails due to the stream
being offline. When this component is shown, the Player will retry playback in
the background. This will override the
[`OfflineStreamError` component](https://github.com/livepeer/react/blob/main/packages/react/src/components/media/controls/PlaybackDisplayError.tsx).
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
Stream is offline. Playback will start automatically once the stream
has started.
}
/>
);
}
```
### accessControlErrorComponent
Sets the error component that is shown when playback fails due to an access
control error. This will override the
[`PrivateStreamError` component](https://github.com/livepeer/react/blob/main/packages/react/src/components/media/controls/PlaybackDisplayError.tsx).
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
It looks like you don't have permission to view this content.
}
/>
);
}
```
### playbackFailedErrorComponent
Sets the error component that is shown when playback fails for a generic reason
(usually this is an intermittent network issue). When this component is shown,
the Player will be retrying playback in the background, with linear backoff.
This will override the
[`GenericError` component](https://github.com/livepeer/react/blob/main/packages/react/src/components/media/controls/PlaybackDisplayError.tsx).
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
Playback failed! Please wait while we retry in the background.
}
/>
);
}
```
### mediaElementRef
Sets the React
[callback `ref`](https://reactjs.org/docs/refs-and-the-dom.html#callback-refs)
passed to the underlying media element. Useful when integrating with third party
tools, or when access to the underlying video element is needed (usually it
isn't!). Simple refs are not supported - only callback refs (which will be
called when the underlying media element is set/updated on initial render).
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useCallback } from "react";
function PlayerComponent() {
const mediaElementRef = useCallback((ref: HTMLMediaElement) => {
console.log(ref.duration);
}, []);
return (
);
}
```
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useCallback } from "react";
function PlayerComponent() {
return (
{
await ref?.setVolumeAsync(0.5);
}}
/>
);
}
```
### onPlaybackStatusUpdate
Callback called when the Player store status updates. **This must be used with
`playbackStatusSelector` to limit state updates.** This allows developers to use
the underlying state of the Player component in their UI.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
console.log(muted)}
playbackStatusSelector={(state) => state.muted}
/>
);
}
```
## Hooks
### usePlayerList
`usePlayerList` is currently only available for React Native, since there are
List primitives which provide a standard API to hook into. We are working on a
React version.
The `usePlayerList` hook makes it easy to preload and display videos in a
[`FlatList`](https://reactnative.dev/docs/flatlist)-compatible list, by using
[`viewabilityConfigCallbackPairs`](https://reactnative.dev/docs/flatlist#viewabilityconfigcallbackpairs)
to trigger preloading on upcoming videos, and automatically playing/pausing
media when it is shown/hidden from the list.
See our
[Expo sample app](https://github.com/livepeer/react/tree/main/examples/expo) for
a real-world example.
#### Usage
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const videos = [
{
title: "Fountain",
playbackId: "6119i9hncfr7gopr",
},
{
title: "Happy Dog",
playbackId: "8cf0gfaqtuajakyf",
},
];
function SomeComponent() {
const { listProps } = usePlayerList({
data: videos,
itemVisibleMinimumViewTime: 100,
itemVisiblePercentThreshold: 60,
itemPreload: 2,
});
return (
(
)}
/>
);
}
```
#### Return Value
The return value extends the `data` array which is passed into the hook, to add
Player-specific props to it. The `viewabilityConfigCallbackPairs` prop is also
returned, which must be passed into the `FlatList`-compatible list to maintain
the correct preloading/playing states for the Player(s).
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
data: (
TInputArray & {
playerProps: {
_isCurrentlyShown: boolean;
priority: boolean;
};
}
)[];
viewabilityConfigCallbackPairs: ViewabilityConfigCallbackPairs;
}
```
#### Configuration
##### data
The data used in the list - required. This is extended to add Player-specific
props, which are passed into the Player using `item.playerProps`.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { listProps } = usePlayerList({
data: videos,
});
return (
(
)}
/>
);
}
```
##### itemPreload
The number of items to preload ahead of the currently-viewable Player. For
instance, if `itemPreload` is set to 8 and there are 30 items in the Player
list, when the user is currently viewing the 5th item, the 6th-14th Players will
actively preload in the background. Defaults to 3.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { listProps } = usePlayerList({
data: videos,
itemPreload: 8,
});
}
```
##### itemVisibleMinimumViewTime
The minimum amount of time in milliseconds that an item must be viewable before
it is considered "shown". This will also be the delay between when the item
becomes visible and when the autoPlay logic is triggered. Defaults to 100 ms,
use `null` to unset. See
[FlatList's `viewabilityConfig`](https://reactnative.dev/docs/flatlist#viewabilityconfig)
for more details.
```tsx {4} theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { listProps } = usePlayerList({
data: videos,
itemVisibleMinimumViewTime: 300,
});
}
```
##### itemVisiblePercentThreshold
The percent of the item that must be visible for the item to count as
"viewable", from 0-100. Defaults to 60%, use `null` to unset. See
[FlatList's `viewabilityConfig`](https://reactnative.dev/docs/flatlist#viewabilityconfig)
for more details.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { listProps } = usePlayerList({
data: videos,
itemVisiblePercentThreshold: 35,
});
}
```
##### itemVisibleViewAreaCoveragePercentThreshold
The percent of the viewport that must be covered for a partially occluded item
to count as "viewable", 0-100. No default value. See
[FlatList's `viewabilityConfig`](https://reactnative.dev/docs/flatlist#viewabilityconfig)
for more details.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { listProps } = usePlayerList({
data: videos,
itemVisiblePercentThreshold: null, // the default item percent can be unset, if needed
itemVisibleViewAreaCoveragePercentThreshold: 75,
});
}
```
##### itemVisibleWaitForInteraction
Indicates that the item is not considered viewable until the user scrolls or
`recordInteraction` is called after render. Defaults to false. See
[FlatList's `viewabilityConfig`](https://reactnative.dev/docs/flatlist#viewabilityconfig)
for more details.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { listProps } = usePlayerList({
data: videos,
itemVisibleWaitForInteraction: true,
});
}
```
## SSR
The following section only applies to web-based use-cases - React Native has
no concept of SSR.
### Next.js
The Player also comes with a
[Tanstack Query](https://tanstack.com/query/v4/docs/guides/ssr) prefetch query,
`prefetchPlayer`, which makes it easy to prefetch the data used internally for
the Player during server-side rendering.
First, you add a
[`getStaticProps`](https://nextjs.org/docs/basic-features/data-fetching/get-static-props)
function to the page which you want to prefetch data on. The props should match
the Player props to ensure that the correct data is prefetched.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { prefetchPlayer, studioProvider } from "@livepeer/react";
export const getStaticProps = async () => {
const dehydratedState = await prefetchPlayer(
{ playbackId },
{ provider: studioProvider({ apiKey: "yourStudioApiKey" }) }
);
return {
props: {
dehydratedState,
},
revalidate: 600,
};
};
```
We need to update the `_app.tsx` to pass the `dehydratedState` in `pageProps` to
the LivepeerConfig. We also move the `livepeerClient` into a useMemo hook so
that a new client is created on each request.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import {
LivepeerConfig,
createReactClient,
studioProvider,
} from "@livepeer/react";
import type { AppProps } from "next/app";
import { useMemo } from "react";
function App({ Component, pageProps }: AppProps<{ dehydratedState: string }>) {
// we create a new livepeer client on each request so data is
// not shared between users
const livepeerClient = useMemo(
() =>
createReactClient({
provider: studioProvider({
apiKey: process.env.NEXT_PUBLIC_STUDIO_API_KEY,
}),
}),
[]
);
return (
);
}
```
That's it! You now have data prefetching on the server, which is passed to the
browser and used to hydrate the initial query client.
### Other Frameworks
The process is very similar for other frameworks, with the exception that there
is a `clearClient` boolean which should be used to ensure that the client cache
is not reused across users.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { prefetchPlayer, studioProvider } from "@livepeer/react";
export const handleRequest = async (req, res) => {
const dehydratedState = await prefetchPlayer(
{
playbackId,
clearClient: true,
},
{ provider: studioProvider({ apiKey: "yourStudioApiKey" }) }
);
// sanitize the custom SSR generated data
// https://medium.com/node-security/the-most-common-xss-vulnerability-in-react-js-applications-2bdffbcc1fa0
res.send(`
${html}
`);
};
```
## Technical Details
The Player is opinionated about the ways it handles playback of media,
specifically regarding HLS reconnect and playback URL choices.
### HLS Reconnect
The Player will perform a linear backoff strategy when it encounters any
network/response errors. The reconnect will initially wait one second, and add
one second every retry. This ensures that if there are any intermittent
network/API errors, they are resolved as quickly as possible. Most open source
players do not do this automatically, which results in a poor playback
experience for the user.
### MP4 Playback URLs
When videos are uploaded which are shorter than two minutes, the Studio provider
will automatically generate MP4 renditions alongside the usual HLS playback URL.
This allows for rapid playback/caching at the CDN layer to enable your
application to load video instantly.
The MP4 renditions will be prioritized over HLS and are chosen with the
following algorithm: the device screen width is multiplied by a static
multiplier (currently set to `x2.5`). This value is then compared to the
rendition widths, and the renditions are prioritized based on the distance
between these values. This results in a choice of a rendition which is close to
the screen size without visual quality issues. For instance, a device with a
1280 pixel width would compute `1280px * 2.5 = 3200px`, and then sort the MP4
renditions by which are closest to this value.
# useAsset
Source: https://docs.livepeer.org/v1/sdks/react/migration/3.x/asset/useAsset
React Hook for retrieving an asset.
Hook for retrieving an
[asset](https://github.com/livepeer/react/blob/main/packages/core/src/types/provider.ts)
based on a unique identifier.
## Usage
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useAsset } from '@livepeer/react';
```
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useAsset } from '@livepeer/react-native';
```
The following examples assume an asset was created via `useCreateAsset` or
directly via a provider's API/dashboard. If a falsy asset ID is provided, the
query will be skipped.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function Component() {
const { data: asset } = useAsset(asset?.id);
}
```
## Return Value
The return value is partially based on
[Tanstack Query](https://tanstack.com/query/v4/docs/reference/useQuery), with
some return types aggregated for simplicity.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
data?: Asset,
error?: Error,
status: 'idle' | 'loading' | 'success' | 'error',
isError: boolean,
isFetched: boolean,
isFetching: boolean,
isIdle: boolean,
isLoading: boolean,
isRefetching: boolean,
isSuccess: boolean,
refetch: (options: RefetchOptions) => Promise,
}
```
## Configuration
### assetId
Asset identifier. Can also be a string passed as the only parameter.
```tsx {3} theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { data: asset } = useAsset({
assetId,
});
}
```
### UseQueryOptions
The `useAsset` hook also supports any
[Tanstack Query](https://tanstack.com/query/v4/docs/reference/useQuery)
`useQuery` options, such as `refetchInterval` or `enabled`. These override any
configs passed by default by the internal hook.
```tsx {4} theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { data: asset } = useAsset({
assetId,
refetchInterval: (asset) => (!asset?.playbackUrl ? 5000 : false),
});
}
```
## SSR
The following section only applies to web-based use-cases - React Native has
no concept of SSR.
### Next.js
The `useAsset` hook also comes with a
[Tanstack Query](https://tanstack.com/query/v4/docs/guides/ssr) prefetch query,
`prefetchAsset`, which makes it easy to prefetch data for server-side rendering.
First, you add a
[`getStaticProps`](https://nextjs.org/docs/basic-features/data-fetching/get-static-props)
function to the page which you want to prefetch data on. The props should match
the `useAsset` hook to ensure that the correct data is prefetched.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// pages/demo.tsx
import { prefetchAsset, studioProvider } from "@livepeer/react";
export const getStaticProps = async () => {
const dehydratedState = await prefetchAsset(
{ assetId },
{ provider: studioProvider({ apiKey: "yourStudioApiKey" }) }
);
return {
props: {
dehydratedState,
},
revalidate: 600,
};
};
```
We need to update the `_app.tsx` to pass the `dehydratedState` in `pageProps` to
the LivepeerConfig. We also move the `livepeerClient` into a useMemo hook so
that a new client is created on each request.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// pages/_app.tsx
import {
LivepeerConfig,
createReactClient,
studioProvider,
} from "@livepeer/react";
import type { AppProps } from "next/app";
import { useMemo } from "react";
function App({ Component, pageProps }: AppProps<{ dehydratedState: string }>) {
// we create a new livepeer client on each request so data is
// not shared between users
const livepeerClient = useMemo(
() =>
createReactClient({
provider: studioProvider({
apiKey: process.env.NEXT_PUBLIC_STUDIO_API_KEY,
}),
}),
[]
);
return (
);
}
```
That's it! You now have data prefetching on the server, which is passed to the
browser and used to hydrate the initial query client.
### Other Frameworks
The process is very similar for other frameworks, with the exception that there
is a `clearClient` boolean which should be used to ensure that the client cache
is not reused across users.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { prefetchAsset, studioProvider } from "@livepeer/react";
export const handleRequest = async (req, res) => {
const dehydratedState = await prefetchAsset(
{
assetId,
clearClient: true,
},
{ provider: studioProvider({ apiKey: "yourStudioApiKey" }) }
);
// sanitize the custom SSR generated data
// https://medium.com/node-security/the-most-common-xss-vulnerability-in-react-js-applications-2bdffbcc1fa0
res.send(`
${html}
`);
};
```
# useAssetMetrics
Source: https://docs.livepeer.org/v1/sdks/react/migration/3.x/asset/useAssetMetrics
React Hook for retrieving metrics for an asset.
Hook for retrieving metrics for an Asset.
## Usage
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useAssetMetrics } from '@livepeer/react';
```
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useAssetMetrics } from '@livepeer/react-native';
```
Metrics are currently only available if a user has the ID associated with an
asset. This should only be the user(s) with write access to the asset -
viewers are not able to use this hook.
The following examples assume an ID has been created for an asset, and the
[`Player`](/sdks/react/Player) is used for playback (with its built-in metrics
reporting).
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { data: metrics } = useAssetMetrics({ assetId });
}
```
If a falsy asset ID is provided, the query will be skipped.
## Return Value
The return value is partially based on
[Tanstack Query](https://tanstack.com/query/v4/docs/reference/useQuery), with
some return types aggregated for simplicity.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
data?: ViewsMetrics,
error?: Error,
status: 'idle' | 'loading' | 'success' | 'error',
isError: boolean,
isFetched: boolean,
isFetching: boolean,
isIdle: boolean,
isLoading: boolean,
isRefetching: boolean,
isSuccess: boolean,
refetch: (options: RefetchOptions) => Promise,
}
```
## Configuration
### assetId
Asset identifier.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { data: metrics } = useAssetMetrics({
assetId,
});
}
```
### UseQueryOptions
The `useAssetMetrics` hook also supports any
[Tanstack Query](https://tanstack.com/query/v4/docs/reference/useQuery)
`useQuery` options, such as `refetchInterval` or `enabled`. These override any
configs passed by default by the internal hook.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { data: metrics } = useAssetMetrics({
assetId,
refetchInterval: 30000,
});
}
```
## SSR
The following section only applies to web-based use-cases - React Native has
no concept of SSR.
### Next.js
The `useAssetMetrics` hook also comes with a
[Tanstack Query](https://tanstack.com/query/v4/docs/guides/ssr) prefetch query,
`prefetchAssetMetrics`, which makes it easy to prefetch data for server-side
rendering.
First, you add a
[`getStaticProps`](https://nextjs.org/docs/basic-features/data-fetching/get-static-props)
function to the page which you want to prefetch data on. The props should match
the `useAsset` hook to ensure that the correct data is prefetched.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// pages/demo.tsx
import { prefetchAssetMetrics, studioProvider } from "@livepeer/react";
export const getStaticProps = async () => {
const dehydratedState = await prefetchAssetMetrics(
{ assetId },
{ provider: studioProvider({ apiKey: "yourStudioApiKey" }) }
);
return {
props: {
dehydratedState,
},
revalidate: 600,
};
};
```
We need to update the `_app.tsx` to pass the `dehydratedState` in `pageProps` to
the LivepeerConfig. We also move the `livepeerClient` into a useMemo hook so
that a new client is created on each request.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// pages/_app.tsx
import {
LivepeerConfig,
createReactClient,
studioProvider,
} from "@livepeer/react";
import type { AppProps } from "next/app";
import { useMemo } from "react";
function App({ Component, pageProps }: AppProps<{ dehydratedState: string }>) {
// we create a new livepeer client on each request so data is
// not shared between users
const livepeerClient = useMemo(
() =>
createReactClient({
provider: studioProvider({
apiKey: process.env.NEXT_PUBLIC_STUDIO_API_KEY,
}),
}),
[]
);
return (
);
}
```
That's it! You now have data prefetching on the server, which is passed to the
browser and used to hydrate the initial query client.
### Other Frameworks
The process is very similar for other frameworks, with the exception that there
is a `clearClient` boolean which should be used to ensure that the client cache
is not reused across users.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { prefetchAssetMetrics, studioProvider } from "@livepeer/react";
export const handleRequest = async (req, res) => {
const dehydratedState = await prefetchAssetMetrics(
{
assetId,
clearClient: true,
},
{ provider: studioProvider({ apiKey: "yourStudioApiKey" }) }
);
// sanitize the custom SSR generated data
// https://medium.com/node-security/the-most-common-xss-vulnerability-in-react-js-applications-2bdffbcc1fa0
res.send(`
${html}
`);
};
```
# useCreateAsset
Source: https://docs.livepeer.org/v1/sdks/react/migration/3.x/asset/useCreateAsset
React Hook for creating a new asset.
useCreateAsset is a React Hook for creating a new asset. It returns a `mutate`
function that can be called to create an asset. Multiple assets can be created
at once by passing in an array of `sources`.
## Usage
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useCreateAsset } from '@livepeer/react';
```
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useCreateAsset } from '@livepeer/react-native';
```
The asset ID should only be passed to users who are allowed to modify the
asset. **Ensure viewers are only provided with the `playbackId`,** which is a
limited identifier that provides only the ability to stream media using the
[`Player`](/sdks/react/Player).
The following example shows how an asset can be created with the `mutate`
function. The variables are passed into the `useCreateAsset` hook, and
`createAsset` return type is defined when the variables are truthy.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const [video, setVideo] = useState(undefined);
const {
mutate: createAsset,
data: assets,
status,
progress,
error,
} = useCreateAsset(
// we use a `const` assertion here to provide better Typescript types
// for the returned data
video
? {
sources: [
{
name: video.name,
file: video,
storage: {
ipfs: true,
metadata: {
name: "interesting video",
description: "a great description of the video",
},
},
},
] as const,
}
: null
);
return (
);
}
```
## Mutation
## Return Value
The return value is partially based on
[Tanstack Query](https://tanstack.com/query/v4/docs/reference/useMutation), with
some return types aggregated for simplicity.
The value `progress` is an array of progress values which contains the upload
progress from [tus](https://github.com/tus/tus-js-client), as well as the
processing progress of the asset from the provider. These values are polled
consistently until the asset succeeds or fails to be processed by the provider.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
data?: Asset[],
progress?: CreateAssetProgress,
error?: Error,
isError: boolean,
isIdle: boolean,
isLoading: boolean,
isSuccess: boolean,
status: 'idle' | 'loading' | 'success' | 'error',
mutate: () => void,
mutateAsync: () => Promise,
variables?: CreateAssetArgs
}
```
## Configuration
### sources
The `sources` used for the asset creation can be an array of either a URL or a
local File/ReadStream/object with a `uri` string. *It is highly recommended to
use
[const assertions](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-4.html#const-assertions)
to infer types properly from the `sources` parameter - please see below for an
example.*
```tsx " theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useCreateAsset } from "@livepeer/react";
function SomeComponent() {
const { mutate: createAsset, status } = useCreateAsset({
sources: [
{
name: video.name,
file: video,
creatorId: "0xabcd000000000000000000000000000000001234",
storage: {
ipfs: true,
metadata: {
name: "interesting video",
description: "a great description of the video",
},
},
},
] as const,
});
}
```
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useCreateAsset } from "@livepeer/react";
function SomeComponent() {
// get the URI from a file picker
// then pass the URI into the source
const { mutate: createAsset, status } = useCreateAsset({
sources: [
{
name: video.name,
file: { uri },
creatorId: "0xabcd000000000000000000000000000000001234",
storage: {
ipfs: true,
metadata: {
name: "interesting video",
description: "a great description of the video",
},
},
},
] as const,
});
}
```
The `useCreateAsset` hook uses [tus](https://github.com/tus/tus-js-client) for
resumable uploads and checks for existing uploads by default, before starting
a new upload. **It also automatically polls the livepeer provider's API to
update `status` until the import job is complete.**
The `sources` type can be either a URL or a File/ReadStream:
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
type CreateAssetSourceUrl = {
/** Name for the new asset */
name: string;
/** External URL to be imported */
url: string;
/** The storage configs for the new asset (e.g. IPFS) */
storage?: Storage;
/**
* Sets the playback policy for the asset created.
*/
playbackPolicy?: PlaybackPolicy;
/**
* Sets the creator ID for the asset that is created.
* This should be an wallet's public address.
*/
creatorId?: CreateAssetCreatorId;
};
/** React Native file type */
type NativeFile = File & {
uri: string;
};
type CreateAssetSourceFile = {
/** Name for the new asset */
name: string;
/** Content to be uploaded or streamed */
file: File | ReadStream | NativeFile;
/** The storage configs for the new asset (e.g. IPFS) */
storage?: Storage;
/**
* Sets the playback policy for the asset created.
*/
playbackPolicy?: PlaybackPolicy;
/**
* Sets the creator ID for the asset that is created.
* This should be an wallet's public address.
*/
creatorId?: CreateAssetCreatorId;
};
/** Source(s) to upload - can be a file or URL source */
type Sources = CreateAssetSourceFile[] | CreateAssetSourceUrl[];
```
We are planning on adding further features to the creator ID such as provable
claims. Reach out to us on [Discord](https://discord.gg/livepeer) if you're
interested!
If `CreateAssetSourceFile` is passed in the array, the `useCreateAsset` hook
uses [tus](https://github.com/tus/tus-js-client) for resumable uploads and
checks for existing uploads by default, before starting a new upload.
If `CreateAssetSourceUrl` is passed in the array, the hook will make a request
to the background to start an import. This can also be an IPFS URL
(`ipfs://`) or Arweave URL (`ar://`). **Either a URL or file must be
provided.**
#### storage
The `storage` configs can be applied on asset creation. See `useUpdateAsset` for
more details on these configs. If the `storage` parameter is omitted, the asset
will not be stored in decentralized storage.
If you would like to use Arweave as storage, we recommend you upload to
Arweave first and then import the video.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
type Storage = {
/**
* If the asset should be stored on IPFS.
*/
ipfs?: boolean;
/**
* Metadata exported to the storage provider. This will be deep merged with the default
* metadata from the livepeer provider. This should ideally be EIP-721/EIP-1155 compatible.
*
* @see {@link https://eips.ethereum.org/EIPS/eip-721}
*/
metadata?: Partial & {
[k: string]: unknown;
};
/**
* The metadata template to use. `player` will embed the Livepeer Player's IPFS CID while `file`
* will reference only the immutable media files.
*/
metadataTemplate?: "player" | "file";
};
```
The metadata can be overridden when the Asset and its metadata are exported to
IPFS - we provide some helper types for metadata best practices based on ERC-721
and ERC-1155:
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
type Metadata = {
/** Name of the Asset */
name?: string;
/** Description of the Asset */
description?: string;
/** Image URL for the Asset */
image?: string;
/** Properties of the Asset */
properties?: {
[k: string]: unknown;
};
/**
* Background color for the Asset (OpenSea Standard)
*
* @see {@link https://docs.opensea.io/docs/metadata-standards}
*/
background_color?: string;
/**
* Attributes for the Asset (OpenSea Standard)
*
* @see {@link https://docs.opensea.io/docs/metadata-standards}
*/
attributes?: {
[k: string]: unknown;
};
};
```
### noWait
The `noWait` config option skips the polling mechanism which waits for the Asset
upload to succeed or fail. It will immediately return after the file upload is
complete, or in the case of a URL upload, it will return after the URL is
`POST`ed to the backend.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useCreateAsset } from "@livepeer/react";
function SomeComponent() {
const { mutate: createAsset } = useCreateAsset({
sources: [{ name: video.name, file: video }] as const,
noWait,
});
}
```
### mutationConfig
The `mutationConfig` parameter allows for any
[Tanstack Query](https://tanstack.com/query/v4/docs/reference/useMutation)
`useMutation` options, such as `cacheTime` or `retry`. These override any
configs passed by default by the internal hook.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useCreateAsset } from "@livepeer/react";
function SomeComponent() {
const { mutate: createAsset } = useCreateAsset({
sources: [{ name: video.name, file: video }] as const,
mutationConfig: { retry: 5 },
});
}
```
# useUpdateAsset
Source: https://docs.livepeer.org/v1/sdks/react/migration/3.x/asset/useUpdateAsset
React Hook for updating an asset.
Hook for updating an existing
[Asset](https://github.com/livepeer/react/blob/main/packages/core/src/types/provider.ts).
## Usage
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useUpdateAsset } from '@livepeer/react';
```
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useUpdateAsset } from '@livepeer/react-native';
```
The following example shows how an asset can be updated.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const assetId = "7ce29561-91ae-42cf-b9c0-6e46dbc1cc2d";
function SomeComponent() {
const { data: asset } = useAsset({
assetId,
refetchInterval: 10000,
});
const {
mutate: updateAsset,
status,
error,
} = useUpdateAsset({
assetId,
storage: { ipfs: true },
});
return (
{asset && (
<>
Asset Name: {asset?.name}
IPFS CID: {asset?.storage?.ipfs?.cid ?? "None"}
>
)}
{error &&
{error.message}
}
);
}
```
## Return Value
The return value is partially based on
[Tanstack Query](https://tanstack.com/query/v4/docs/reference/useMutation), with
some return types aggregated for simplicity.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
data?: Asset,
error?: Error,
isError: boolean,
isIdle: boolean,
isLoading: boolean,
isSuccess: boolean,
status: 'idle' | 'loading' | 'success' | 'error',
mutate: () => void,
mutateAsync: () => Promise,
variables?: UpdateAssetArgs
}
```
## Configuration
### assetId
The asset ID to update - required.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useUpdateAsset } from "@livepeer/react";
function SomeComponent() {
const { mutate: updateAsset } = useUpdateAsset({
assetId,
name: "New Name",
});
}
```
### name
The updated name for the asset.
### storage
The storage configs to use for the asset. This is preferably EIP-721 or EIP-1155
compatible metadata configs.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
type Storage = {
/**
* If the asset should be stored on IPFS.
*/
ipfs?: boolean;
/**
* Metadata exported to the storage provider. This will be deep merged with the default
* metadata from the livepeer provider. This should ideally be EIP-721/EIP-1155 compatible.
*
* @see {@link https://eips.ethereum.org/EIPS/eip-721}
*/
metadata?: Partial & {
[k: string]: unknown;
};
/**
* The metadata template to use. `player` will embed the Livepeer Player's IPFS CID while `file`
* will reference only the immutable media files.
*/
metadataTemplate?: "player" | "file";
};
```
The metadata can be overridden when the Asset and its metadata are exported to
IPFS - we provide some helper types for metadata best practices based on ERC-721
and ERC-1155:
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
type Metadata = {
/** Name of the Asset */
name?: string;
/** Description of the Asset */
description?: string;
/** Image URL for the Asset */
image?: string;
/** Properties of the Asset */
properties?: {
[k: string]: unknown;
};
/**
* Background color for the Asset (OpenSea Standard)
*
* @see {@link https://docs.opensea.io/docs/metadata-standards}
*/
background_color?: string;
/**
* Attributes for the Asset (OpenSea Standard)
*
* @see {@link https://docs.opensea.io/docs/metadata-standards}
*/
attributes?: {
[k: string]: unknown;
};
};
```
### mutationConfig
The `mutationConfig` parameter allows for any
[Tanstack Query](https://tanstack.com/query/v4/docs/reference/useMutation)
`useMutation` options, such as `cacheTime` or `retry`. These override any
configs passed by default by the internal hook.
```tsx {7} theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useUpdateAsset } from "@livepeer/react";
function SomeComponent() {
const { mutate: updateAsset } = useUpdateAsset({
assetId,
name: "New Name",
mutationConfig: { retry: 3 },
});
}
```
# Client
Source: https://docs.livepeer.org/v1/sdks/react/migration/3.x/client
The livepeer Client is a framework agnostic client that manages wallet connection state and configuration, such as: auto-connection, connectors, and ethers providers.
The livepeer `Client` is a framework agnostic client that manages state and
connection to a Livepeer provider. The `createReactClient` function wraps the
`Client` with a React-specific caching layer for faster queries.
## Usage
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { createReactClient } from '@livepeer/react';
```
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { createReactClient } from '@livepeer/react-native';
```
The client can be created using `createReactClient`.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const client = createReactClient({
provider: studioProvider({ apiKey: "yourStudioApiKey" }),
});
```
## Configuration
### provider
Livepeer provider interface for connecting to the network.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const client = createReactClient({
provider: studioProvider({ apiKey: "yourStudioApiKey" }),
});
```
### storage (optional)
The default strategy to persist and cache data. Used for both state management
and query caching. Defaults to `window.localStorage`.
To disable the use of localStorage, we provide a convenient "no-op" storage
option:
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import {
createReactClient,
studioProvider,
noopStorage,
createStorage,
} from "@livepeer/react";
const client = createReactClient({
provider: studioProvider({ apiKey: 'yourStudioApiKey' }),
storage: createStorage({
storage: noopStorage,
}),
});
```
The default strategy to persist and cache data. Used for both state management
and query caching. Defaults to no storage.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import AsyncStorage from '@react-native-async-storage/async-storage';
const client = createReactClient({
provider: studioProvider({ apiKey: 'yourStudioApiKey' }),
storage: createStorage({ storage: AsyncStorage }),
});
```
### queryClient (optional)
The react-query
[QueryClient](https://tanstack.com/query/v4/docs/reference/QueryClient) used to
cache/deduplicate queries. Defaults to caching for 24 hours and no retries.
```ts theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const client = createReactClient({
provider: studioProvider({ apiKey: "yourStudioApiKey" }),
queryClient: new QueryClient({
defaultOptions: {
queries: {
cacheTime: 1_000 * 60 * 60, // 1 hour
retry: 100,
},
},
}),
});
```
# Application Binary Interface
Source: https://docs.livepeer.org/v1/sdks/react/migration/3.x/constants/abis
All Livepeer ABIs available via import.
All Livepeer ABIs are available via import.
## Protocol
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import {
BondingManagerABI,
ControllerABI,
LivepeerTokenABI,
LivepeerTokenFaucetABI,
MerkleSnapshotABI,
MinterABI,
PollABI,
PollCreatorABI,
RoundsManagerABI,
ServiceRegistryABI,
TicketBrokerABI,
} from '@livepeer/react';
```
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import {
BondingManagerABI,
ControllerABI,
LivepeerTokenABI,
LivepeerTokenFaucetABI,
MerkleSnapshotABI,
MinterABI,
PollABI,
PollCreatorABI,
RoundsManagerABI,
ServiceRegistryABI,
TicketBrokerABI,
} from '@livepeer/react-native';
```
## Bridging
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import {
ArbRetryableTxABI,
InboxABI,
L1BondingManagerABI,
L1MigratorABI,
L2LPTGatewayABI,
L2MigratorABI,
NodeInterfaceABI,
} from '@livepeer/react';
```
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import {
ArbRetryableTxABI,
InboxABI,
L1BondingManagerABI,
L1MigratorABI,
L2LPTGatewayABI,
L2MigratorABI,
NodeInterfaceABI,
} from '@livepeer/react-native';
```
# Contract Addresses
Source: https://docs.livepeer.org/v1/sdks/react/migration/3.x/constants/contract-addresses
All contract addresses for the Livepeer protocol.
**This page documents a deprecated SDK version.** For current contract addresses, see:
**[Livepeer Contract Addresses](/v2/about/resources/livepeer-contract-addresses)**
All contract addresses for the Livepeer protocol.
## Addresses
The addresses for the protocol contracts are provided in a simple import with
types.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import {
arbitrumOneAddress,
arbitrumRinkebyAddress,
mainnetAddress,
rinkebyAddress,
} from '@livepeer/react';
```
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import {
arbitrumOneAddress,
arbitrumRinkebyAddress,
mainnetAddress,
rinkebyAddress,
} from '@livepeer/react-native';
```
These addresses will be expanded upon in a future version of Livepeer React to
include more in-depth contract interaction.
## Chain IDs
There are exports for the chain IDs the Livepeer protocol is currently deployed
on. This includes both Arbitrum One/mainnet and testnet chains.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import {
allChainId, mainnetChainId, testnetChainId
} from '@livepeer/react';
```
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import {
allChainId, mainnetChainId, testnetChainId
} from '@livepeer/react-native';
```
# Getting Started
Source: https://docs.livepeer.org/v1/sdks/react/migration/3.x/getting-started
Get started building with Livepeer UI Kit!
These docs are written for a React or React Native developer building on
`@livepeer/react` or `@livepeer/react-native`.
## Installation
Install Livepeer React using your favorite package manager.
```
npm i @livepeer/react
```
React Native also requires some peer dependencies (used in the `Player`
component). We rely on `expo` for pod installation/linking. You must ensure that
the
[correct version of `react-native-svg`](https://github.com/software-mansion/react-native-svg#supported-react-native-versions)
is installed.
If you're installing this in a
[bare React Native app](https://docs.expo.dev/introduction/managed-vs-bare/#bare-workflow),
you should also follow the
[extra `expo-av` installation instructions](https://github.com/expo/expo/tree/sdk-47/packages/expo-av).
```bash React Native theme={"theme":{"light":"github-light","dark":"dark-plus"}}
expo install @livepeer/react-native expo-av react-native-svg
```
## Create a livepeer client
First, create a livepeer `Client` instance using
[`createReactClient`](/sdks/react/migration/3.x/client), and pass a provider to
it.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { createReactClient, studioProvider } from '@livepeer/react';
const client = createReactClient({
provider: studioProvider({ apiKey: 'yourStudioApiKey' }),
});
```
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { createReactClient, studioProvider } from '@livepeer/react-native';
const client = createReactClient({
provider: studioProvider({ apiKey: 'yourStudioApiKey' }),
});
```
Note: If you choose to use Studio as a provider, you will need to configure an
API key for the `studioProvider` which is
[CORS-protected API key](/sdks/react/migration/3.x/providers/studio#apikey).
[Read more about client configuration](/sdks/react/migration/3.x/client)
## Wrap app with `LivepeerConfig`
Next, wrap the app with the
[`LivepeerConfig`](/sdks/react/migration/3.x/LivepeerConfig) component, passing
the `client` to it.
This is added to `_app.js` for Next.js or `App.js` with Create React App, so that the
`LivepeerConfig` React Context is available across every component.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import {
LivepeerConfig,
createReactClient,
studioProvider,
} from '@livepeer/react';
const client = createReactClient({
provider: studioProvider({ apiKey: 'yourStudioApiKey' }),
});
function App() {
return (
);
}
```
This is added to `App.js`, so that the `LivepeerConfig` React Context is available across every component.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import {
LivepeerConfig,
createReactClient,
studioProvider,
} from '@livepeer/react-native';
const client = createReactClient({
provider: studioProvider({ apiKey: 'yourStudioApiKey' }),
});
function App() {
return (
);
}
```
## Enjoy!
Use hooks! Every component inside the `LivepeerConfig` is now set up to use the
livepeer hooks.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useAsset } from '@livepeer/react';
function SomeComponent() {
const asset = useAsset({ assetId: 'd8e8b87d-6774-4083-a2d7-4e85872d18cd' });
return
;
}
```
Want to learn more? Continue reading the documentation for more details.
# usePlaybackInfo
Source: https://docs.livepeer.org/v1/sdks/react/migration/3.x/playback/usePlaybackInfo
React Hook for retrieving playback details for a playback ID.
Hook for retrieving playback information related to a playback ID. Used
internally in the [`Player`](/sdks/react/Player) to fetch the playback URL for a
playback ID.
## Usage
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { usePlaybackInfo } from '@livepeer/react';
```
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { usePlaybackInfo } from '@livepeer/react-native';
```
The following examples assume a playback ID has been created for an asset or
stream.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { data: playbackInfo } = usePlaybackInfo(playbackId);
}
```
If a falsy playback ID is provided, the query will be skipped.
## Return Value
The return value is partially based on
[Tanstack Query](https://tanstack.com/query/v4/docs/reference/useQuery), with
some return types aggregated for simplicity.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
data?: PlaybackInfo,
error?: Error,
status: 'idle' | 'loading' | 'success' | 'error',
isError: boolean,
isFetched: boolean,
isFetching: boolean,
isIdle: boolean,
isLoading: boolean,
isRefetching: boolean,
isSuccess: boolean,
refetch: (options: RefetchOptions) => Promise,
}
```
## Configuration
### playbackId
Playback identifier. Can also be a string passed as the only parameter.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { data: playbackInfo } = usePlaybackInfo({
playbackId,
});
}
```
### UseQueryOptions
The `usePlaybackInfo` hook also supports any
[Tanstack Query](https://tanstack.com/query/v4/docs/reference/useQuery)
`useQuery` options, such as `refetchInterval` or `enabled`. These override any
configs passed by default by the internal hook.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { data: playbackInfo } = usePlaybackInfo({
playbackId,
refetchInterval: 30000,
});
}
```
## SSR
The following section only applies to web-based use-cases - React Native has
no concept of SSR.
### Next.js
The `usePlaybackInfo` hook also comes with a
[Tanstack Query](https://tanstack.com/query/v4/docs/guides/ssr) prefetch query,
`prefetchPlaybackInfo`, which makes it easy to prefetch data for server-side
rendering.
First, you add a
[`getStaticProps`](https://nextjs.org/docs/basic-features/data-fetching/get-static-props)
function to the page which you want to prefetch data on. The props should match
the `usePlaybackInfo` hook to ensure that the correct data is prefetched.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// pages/demo.tsx
import { prefetchPlaybackInfo, studioProvider } from "@livepeer/react";
export const getStaticProps = async () => {
const dehydratedState = await prefetchPlaybackInfo(
{ playbackId },
{ provider: studioProvider({ apiKey: "yourStudioApiKey" }) }
);
return {
props: {
dehydratedState,
},
revalidate: 600,
};
};
```
We need to update the `_app.tsx` to pass the `dehydratedState` in `pageProps` to
the LivepeerConfig. We also move the `livepeerClient` into a useMemo hook so
that a new client is created on each request.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// pages/_app.tsx
import {
LivepeerConfig,
createReactClient,
studioProvider,
} from "@livepeer/react";
import type { AppProps } from "next/app";
import { useMemo } from "react";
function App({ Component, pageProps }: AppProps<{ dehydratedState: string }>) {
// we create a new livepeer client on each request so data is
// not shared between users
const livepeerClient = useMemo(
() =>
createReactClient({
provider: studioProvider({
apiKey: process.env.NEXT_PUBLIC_STUDIO_API_KEY,
}),
}),
[]
);
return (
);
}
```
That's it! You now have data prefetching on the server, which is passed to the
browser and used to hydrate the initial query client.
### Other Frameworks
The process is very similar for other frameworks, with the exception that there
is a `clearClient` boolean which should be used to ensure that the client cache
is not reused across users.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { prefetchPlaybackInfo, studioProvider } from "@livepeer/react";
export const handleRequest = async (req, res) => {
const dehydratedState = await prefetchPlaybackInfo(
{
playbackId,
clearClient: true,
},
{ provider: studioProvider({ apiKey: "yourStudioApiKey" }) }
);
// sanitize the custom SSR generated data
// https://medium.com/node-security/the-most-common-xss-vulnerability-in-react-js-applications-2bdffbcc1fa0
res.send(`
${html}
`);
};
```
# useCreateStream
Source: https://docs.livepeer.org/v1/sdks/react/migration/3.x/stream/useCreateStream
React Hook for creating a new stream.
Hook for creating a new
[Stream](https://github.com/livepeer/react/blob/main/packages/core/src/types/provider.ts).
## Usage
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useCreateStream } from '@livepeer/react';
```
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useCreateStream } from '@livepeer/react-native';
```
The stream ID should only be passed to users who are allowed to modify the
stream. **Ensure viewers are only provided with the `playbackId`,** which is a
limited identifier that provides only the ability to stream media using the
[`Player`](/sdks/react/Player).
The following example shows how a stream can be created.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const streamName = `New Stream`;
function SomeComponent() {
const {
mutate: createStream,
data: stream,
status,
} = useCreateStream({ name: streamName });
return (
{stream &&
Stream Key: {stream.streamKey}
}
);
}
```
## Return Value
The return value is partially based on
[Tanstack Query](https://tanstack.com/query/v4/docs/reference/useMutation), with
some return types aggregated for simplicity.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
data?: Stream,
error?: Error,
isError: boolean,
isIdle: boolean,
isLoading: boolean,
isSuccess: boolean,
status: 'idle' | 'loading' | 'success' | 'error',
mutate: () => void,
mutateAsync: () => Promise,
variables?: CreateStreamArgs
}
```
## Configuration
### name
The name for the new stream. Required to create a stream.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { mutate: createStream } = useCreateStream({
name: "My new stream",
});
}
```
### profiles
Transcoding profiles to use for the stream for ABR playback. When this is not
defined, the `defaultTranscodingProfiles` are used (720p, 480p, and 360p).
### record
Whether to create recordings of the stream sessions. Defaults to `false`.
### multistream
The configuration for multistreaming (AKA "restream" or "simulcast") - allows
configuration of targets where this stream should be simultaneously streamed to.
### playbackPolicy
Configuration for stream playback access-control policy. Defaults to `public`.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
type PlaybackPolicy = {
/**
* The type of playback policy to apply. `jwt` requires a signed JWT for
* playback. `webhook` requires that a webhook is configured and passed during the
* creation of the asset. `public` indicates no
* access control will be applied (anyone with the `playbackId` can
* view without a JWT or webhook).
*/
type: "webhook" | "jwt" | "public";
};
type WebhookPlaybackPolicy = PlaybackPolicy & {
type: "webhook";
/** The ID of the webhook which has already been created. */
webhookId: string;
/** The context which is passed to the webhook when it is called on playback. */
webhookContext: TContext;
};
```
### mutationConfig
The `mutationConfig` parameter allows for any
[Tanstack Query](https://tanstack.com/query/v4/docs/reference/useMutation)
`useMutation` options, such as `cacheTime` or `retry`. These override any
configs passed by default by the internal hook.
```tsx {4} theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { mutate: createStream } = useCreateStream({
name: "My new stream",
mutationConfig: { retry: 3 },
});
}
```
# useStream
Source: https://docs.livepeer.org/v1/sdks/react/migration/3.x/stream/useStream
React Hook for retrieving a stream.
Hook for retrieving a
[Stream](https://github.com/livepeer/react/blob/main/packages/core/src/types/provider.ts)
based on a unique identifier.
## Usage
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useStream } from '@livepeer/react';
```
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useStream } from '@livepeer/react-native';
```
The following examples assume a stream was created via `useCreateStream` or
directly via a provider's API/dashboard. If a falsy stream ID is provided, the
query will be skipped.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { data: stream } = useStream(stream?.id);
}
```
## Return Value
The return value is partially based on
[Tanstack Query](https://tanstack.com/query/v4/docs/reference/useQuery), with
some return types aggregated for simplicity.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
data?: Stream,
error?: Error,
status: 'idle' | 'loading' | 'success' | 'error',
isError: boolean,
isFetched: boolean,
isFetching: boolean,
isIdle: boolean,
isLoading: boolean,
isRefetching: boolean,
isSuccess: boolean,
refetch: (options: RefetchOptions) => Promise,
}
```
## Configuration
### streamId
Stream identifier. Can also be a string passed as the only parameter.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { data: stream } = useStream({
streamId,
});
}
```
### UseQueryOptions
The `useStream` hook also supports any
[Tanstack Query](https://tanstack.com/query/v4/docs/reference/useQuery)
`useQuery` options, such as `refetchInterval` or `enabled`. These override any
configs passed by default by the internal hook.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { data: stream } = useStream({
streamId,
refetchInterval: (stream) => (!stream?.isActive ? 5000 : false),
});
}
```
## SSR
The following section only applies to web-based use-cases - React Native has
no concept of SSR.
### Next.js
The `useStream` hook also comes with a
[Tanstack Query](https://tanstack.com/query/v4/docs/guides/ssr) prefetch query,
`prefetchStream`, which makes it easy to prefetch data for server-side
rendering.
First, you add a
[`getStaticProps`](https://nextjs.org/docs/basic-features/data-fetching/get-static-props)
function to the page which you want to prefetch data on. The props should match
the `useStream` hook to ensure that the correct data is prefetched.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// pages/demo.tsx
import { prefetchStream, studioProvider } from "@livepeer/react";
export const getStaticProps = async () => {
const dehydratedState = await prefetchStream(
{ streamId },
{ provider: studioProvider({ apiKey: "yourStudioApiKey" }) }
);
return {
props: {
dehydratedState,
},
revalidate: 600,
};
};
```
We need to update the `_app.tsx` to pass the `dehydratedState` in `pageProps` to
the LivepeerConfig. We also move the `livepeerClient` into a useMemo hook so
that a new client is created on each request.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// pages/_app.tsx
import {
LivepeerConfig,
createReactClient,
studioProvider,
} from "@livepeer/react";
import type { AppProps } from "next/app";
import { useMemo } from "react";
function App({ Component, pageProps }: AppProps<{ dehydratedState: string }>) {
// we create a new livepeer client on each request so data is
// not shared between users
const livepeerClient = useMemo(
() =>
createReactClient({
provider: studioProvider({
apiKey: process.env.NEXT_PUBLIC_STUDIO_API_KEY,
}),
}),
[]
);
return (
);
}
```
That's it! You now have data prefetching on the server, which is passed to the
browser and used to hydrate the initial query client.
### Other Frameworks
The process is very similar for other frameworks, with the exception that there
is a `clearClient` boolean which should be used to ensure that the client cache
is not reused across users.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { prefetchStream, studioProvider } from "@livepeer/react";
export const handleRequest = async (req, res) => {
const dehydratedState = await prefetchStream(
{
streamId,
clearClient: true,
},
{ provider: studioProvider({ apiKey: "yourStudioApiKey" }) }
);
// sanitize the custom SSR generated data
// https://medium.com/node-security/the-most-common-xss-vulnerability-in-react-js-applications-2bdffbcc1fa0
res.send(`
${html}
`);
};
```
# useStreamSession
Source: https://docs.livepeer.org/v1/sdks/react/migration/3.x/stream/useStreamSession
React Hook for retrieving a stream session.
Hook for retrieving a
[Stream Session](https://github.com/livepeer/react/blob/main/packages/core/src/types/provider.ts)
based on a unique identifier.
## Usage
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useStreamSession } from '@livepeer/react';
```
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useStreamSession } from '@livepeer/react-native';
```
The following examples assume a stream session was created via streaming to an
existing Stream. If a falsy stream session ID is provided, the query will be
skipped.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { data: streamSession } = useStreamSession(streamSession?.id);
}
```
## Return Value
The return value is partially based on
[Tanstack Query](https://tanstack.com/query/v4/docs/reference/useQuery), with
some return types aggregated for simplicity.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
data?: StreamSession,
error?: Error,
status: 'idle' | 'loading' | 'success' | 'error',
isError: boolean,
isFetched: boolean,
isFetching: boolean,
isIdle: boolean,
isLoading: boolean,
isRefetching: boolean,
isSuccess: boolean,
refetch: (options: RefetchOptions) => Promise,
}
```
## Configuration
### streamSessionId
Stream session identifier. Can also be a string passed as the only parameter.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { data: streamSession } = useStreamSession({
streamSessionId,
});
}
```
### UseQueryOptions
The `useStreamSession` hook also supports any
[Tanstack Query](https://tanstack.com/query/v4/docs/reference/useQuery)
`useQuery` options, such as `refetchInterval` or `enabled`. These override any
configs passed by default by the internal hook.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { data: streamSession } = useStreamSession({
streamSessionId,
refetchInterval: (streamSession) =>
streamSession?.recordingStatus !== "ready" ? 5000 : false,
});
}
```
## SSR
The following section only applies to web-based use-cases - React Native has
no concept of SSR.
### Next.js
The `useStreamSession` hook also comes with a
[Tanstack Query](https://tanstack.com/query/v4/docs/guides/ssr) prefetch query,
`prefetchStreamSession`, which makes it easy to prefetch data for server-side
rendering.
First, you add a
[`getStaticProps`](https://nextjs.org/docs/basic-features/data-fetching/get-static-props)
function to the page which you want to prefetch data on. The props should match
the `useStreamSession` hook to ensure that the correct data is prefetched.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// pages/demo.tsx
import { prefetchStreamSession, studioProvider } from "@livepeer/react";
export const getStaticProps = async () => {
const dehydratedState = await prefetchStreamSession(
{ streamSessionId },
{ provider: studioProvider({ apiKey: "yourStudioApiKey" }) }
);
return {
props: {
dehydratedState,
},
revalidate: 600,
};
};
```
We need to update the `_app.tsx` to pass the `dehydratedState` in `pageProps` to
the LivepeerConfig. We also move the `livepeerClient` into a useMemo hook so
that a new client is created on each request.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// pages/_app.tsx
import {
LivepeerConfig,
createReactClient,
studioProvider,
} from "@livepeer/react";
import type { AppProps } from "next/app";
import { useMemo } from "react";
function App({ Component, pageProps }: AppProps<{ dehydratedState: string }>) {
// we create a new livepeer client on each request so data is
// not shared between users
const livepeerClient = useMemo(
() =>
createReactClient({
provider: studioProvider({
apiKey: process.env.NEXT_PUBLIC_STUDIO_API_KEY,
}),
}),
[]
);
return (
);
}
```
That's it! You now have data prefetching on the server, which is passed to the
browser and used to hydrate the initial query client.
### Other Frameworks
The process is very similar for other frameworks, with the exception that there
is a `clearClient` boolean which should be used to ensure that the client cache
is not reused across users.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { prefetchStreamSession, studioProvider } from "@livepeer/react";
export const handleRequest = async (req, res) => {
const dehydratedState = await prefetchStreamSession(
{
streamSessionId,
clearClient: true,
},
{ provider: studioProvider({ apiKey: "yourStudioApiKey" }) }
);
// sanitize the custom SSR generated data
// https://medium.com/node-security/the-most-common-xss-vulnerability-in-react-js-applications-2bdffbcc1fa0
res.send(`
${html}
`);
};
```
# useStreamSessions
Source: https://docs.livepeer.org/v1/sdks/react/migration/3.x/stream/useStreamSessions
React Hook for retrieving the stream sessions associated with a stream ID.
Hook for retrieving
[Stream Sessions](https://github.com/livepeer/react/blob/main/packages/core/src/types/provider.ts)
based on the parent stream's unique identifier.
## Usage
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useStreamSessions } from '@livepeer/react';
```
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useStreamSessions } from '@livepeer/react-native';
```
The following examples assume a Stream was created via via `useCreateStream` or
directly via a provider's API/dashboard. If a falsy stream ID is provided, the
query will be skipped.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { data: streamSessions } = useStreamSessions(stream?.id);
}
```
## Return Value
The return value is partially based on
[Tanstack Query](https://tanstack.com/query/v4/docs/reference/useQuery), with
some return types aggregated for simplicity.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
data?: StreamSession[],
error?: Error,
status: 'idle' | 'loading' | 'success' | 'error',
isError: boolean,
isFetched: boolean,
isFetching: boolean,
isIdle: boolean,
isLoading: boolean,
isRefetching: boolean,
isSuccess: boolean,
refetch: (options: RefetchOptions) => Promise,
}
```
## Configuration
### streamId
The stream identifier for the parent stream. Can also be a string passed as the
only parameter.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { data: streamSessions } = useStreamSessions({
streamId,
});
}
```
### UseQueryOptions
The `useStreamSessions` hook also supports any
[Tanstack Query](https://tanstack.com/query/v4/docs/reference/useQuery)
`useQuery` options, such as `refetchInterval` or `enabled`. These override any
configs passed by default by the internal hook.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { data: streamSessions } = useStreamSessions({
streamId,
refetchInterval: (streamSessions) =>
(streamSessions?.length ?? 0) === 0 ? 5000 : false,
});
}
```
## SSR
The following section only applies to web-based use-cases - React Native has
no concept of SSR.
### Next.js
The `useStreamSessions` hook also comes with a
[Tanstack Query](https://tanstack.com/query/v4/docs/guides/ssr) prefetch query,
`prefetchStreamSessions`, which makes it easy to prefetch data for server-side
rendering.
First, you add a
[`getStaticProps`](https://nextjs.org/docs/basic-features/data-fetching/get-static-props)
function to the page which you want to prefetch data on. The props should match
the `useStreamSessions` hook to ensure that the correct data is prefetched.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// pages/demo.tsx
import { prefetchStreamSessions, studioProvider } from "@livepeer/react";
export const getStaticProps = async () => {
const dehydratedState = await prefetchStreamSessions(
{ streamId },
{ provider: studioProvider({ apiKey: "yourStudioApiKey" }) }
);
return {
props: {
dehydratedState,
},
revalidate: 600,
};
};
```
We need to update the `_app.tsx` to pass the `dehydratedState` in `pageProps` to
the LivepeerConfig. We also move the `livepeerClient` into a useMemo hook so
that a new client is created on each request.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// pages/_app.tsx
import {
LivepeerConfig,
createReactClient,
studioProvider,
} from "@livepeer/react";
import type { AppProps } from "next/app";
import { useMemo } from "react";
function App({ Component, pageProps }: AppProps<{ dehydratedState: string }>) {
// we create a new livepeer client on each request so data is
// not shared between users
const livepeerClient = useMemo(
() =>
createReactClient({
provider: studioProvider({
apiKey: process.env.NEXT_PUBLIC_STUDIO_API_KEY,
}),
}),
[]
);
return (
);
}
```
That's it! You now have data prefetching on the server, which is passed to the
browser and used to hydrate the initial query client.
### Other Frameworks
The process is very similar for other frameworks, with the exception that there
is a `clearClient` boolean which should be used to ensure that the client cache
is not reused across users.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { prefetchStreamSessions, studioProvider } from "@livepeer/react";
export const handleRequest = async (req, res) => {
const dehydratedState = await prefetchStreamSessions(
{
streamId,
clearClient: true,
},
{ provider: studioProvider({ apiKey: "yourStudioApiKey" }) }
);
// sanitize the custom SSR generated data
// https://medium.com/node-security/the-most-common-xss-vulnerability-in-react-js-applications-2bdffbcc1fa0
res.send(`
${html}
`);
};
```
# useUpdateStream
Source: https://docs.livepeer.org/v1/sdks/react/migration/3.x/stream/useUpdateStream
React Hook for updating an stream.
Hook for updating an existing
[Stream](https://github.com/livepeer/react/blob/main/packages/core/src/types/livepeer.ts).
## Usage
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useUpdateStream } from '@livepeer/react';
```
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useUpdateStream } from '@livepeer/react-native';
```
The following example shows how an stream can be updated to enable recording and
require a JWT for playback
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const streamId = "abcff74a-bb19-45af-8e63-b961efa1899e";
function SomeComponent() {
const { data: stream } = useStream({
streamId,
refetchInterval: 10000,
});
const {
mutate: updateStream,
status,
error,
} = useUpdateStream({
streamId,
record: true,
playbackPolicy: {
type: "jwt",
},
});
return (
{stream && (
<>
Stream Name: {stream?.name}
Recording?: {String(Boolean(stream.record))}
>
)}
{error &&
{error.message}
}
);
}
```
## Return Value
The return value is partially based on
[Tanstack Query](https://tanstack.com/query/v4/docs/reference/useMutation), with
some return types aggregated for simplicity.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
data?: Stream,
error?: Error,
isError: boolean,
isIdle: boolean,
isLoading: boolean,
isSuccess: boolean,
status: 'idle' | 'loading' | 'success' | 'error',
mutate: () => void,
mutateAsync: () => Promise,
variables?: UpdateStreamArgs
}
```
## Configuration
### streamId
The stream ID to update - required.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { mutate: createStream } = useUpdateStream({
streamId,
record: true,
});
}
```
### suspend
Whether to immediately block ingest and playback of the stream.
### record
Whether to create recordings of the stream sessions. Defaults to `false`.
### multistream
The configuration for multistreaming (AKA "restream" or "simulcast") - allows
configuration of targets where this stream should be simultaneously streamed to.
The multistream targets can be either a full `MultistreamTarget` like on create,
or a `MultistreamTargetRef`. The `Ref` object comes directly from the existing
`Stream` object, in case multistream has already been configured for the given
stream. It contains a vanity ID instead of the full `Spec` since the ingest URL
contains user secrets like the stream key.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
type MultistreamTarget = {
/**
* Name of transcoding profile that should be sent. Use "source" for pushing
* source stream data
*/
profile: string;
/**
* If true, the stream audio will be muted and only silent video will be
* pushed to the target.
*/
videoOnly?: boolean;
/**
* Unique ID of this multistream target. Used to dedup targets on update.
*/
id?: string;
/**
* Inline spec for the multistream target object. Underlying target resource
* will be automatically created.
*/
spec?: {
/** Name for the multistream target. Defaults to the URL hostname */
name?: string;
/** Livepeer-compatible multistream target URL (RTMP(s) or SRT) */
url: string;
};
};
```
### playbackPolicy
Configuration for stream playback access-control policy. Defaults to `public`.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
type PlaybackPolicy = {
/**
* The type of playback policy to apply. `jwt` requires a signed JWT for
* playback. `webhook` requires that a webhook is configured and passed during the
* creation of the asset. `public` indicates no
* access control will be applied (anyone with the `playbackId` can
* view without a JWT or webhook).
*/
type: "webhook" | "jwt" | "public";
};
type WebhookPlaybackPolicy = PlaybackPolicy & {
type: "webhook";
/** The ID of the webhook which has already been created. */
webhookId: string;
/** The context which is passed to the webhook when it is called on playback. */
webhookContext: TContext;
};
```
### mutationConfig
The `mutationConfig` parameter allows for any
[Tanstack Query](https://tanstack.com/query/v4/docs/reference/useMutation)
`useMutation` options, such as `cacheTime` or `retry`. These override any
configs passed by default by the internal hook.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { mutate: updateStream } = useUpdateStream({
streamId,
record: true,
mutationConfig: { retry: 3 },
});
}
```
# Migration Guide for 4+
Source: https://docs.livepeer.org/v1/sdks/react/migration/migration-4.x
Migration guide for the 4.0.0 release of Livepeer React.
Livepeer React `v4.0.0+` was a complete rewrite of the library to support
video primitives.
## Introduction
This migration guide is designed to assist you in transitioning from the
previous version of the `@livepeer/react` library to the new major release. This
update is a significant overhaul aimed at addressing several key issues with the
previous releases.
## Before you start
### Major changes
* The library has been rewritten to offer unstyled, composable `` and
`` primitives based on
[Radix UI](https://www.radix-ui.com/primitives/docs/overview/introduction).
* The components are now highly composable, moving away from the monolithic
design of the previous versions.
* All components support the
[`asChild`](https://www.radix-ui.com/primitives/docs/guides/composition)
pattern, where the component will instead clone the part's child and passing
it the props and behavior required to make it functional.
* For instance: `{...}` will
not render a DOM element, and instead copy all of it's properties to the
child component, which will behave as a fullscreen trigger.
* The components are more aligned with web standards, allowing direct prop
passing to elements (notably the `Video` component).
* Automatic data fetching and CORS API key usage within components have been
removed to enhance security and reduce developer confusion.
* We highly recommend moving away from CORS API keys and making API requests
from your backend. *We plan to deprecate CORS API keys in the future.*
* The React Native package has been deprecated. The package was not
well-maintained and we have focused on web components for Livepeer React.
## Migration steps
### Primitives
Replace your usage of the single `` and `` components
with the new composable primitives. These include:
#### Player
* ``
* ``
* ``
* ``
* ``
* ``
* ...and more.
Check out our [complete example](/sdks/react/Player) for how these can be
composed to build a video player, modeled after the 3.x versions of the Player.
#### Broadcast
* ``
* ``
* ``
* ``
* ``
* ``
* ...and more.
Check out the [complete example](/sdks/react/Broadcast) for how these can be
composed to build a complete in-browser broadcast experience.
### Data fetching
1. All data fetching logic from the Livepeer Studio API has been removed from
the Player and Broadcast components.
* This includes all of the `useCreateAsset`, `useStream`, etc.
2. You will now need to use the [`livepeer`](/sdks/javascript) JS SDK (or
[another SDK](/sdks/introduction), depending on your applications's API
language) for data fetching and interaction.
* You must now make API requests in your backend to fetch playback info for a
playback ID.
* Use [`getSrc`](/sdks/react/player/get-src) utility function with the Player
or [`getIngest`](/sdks/react/broadcast/get-ingest) utility function with
Broadcast to parse the JSON responses from the API.
### Unstyled by default
1. The components are now unstyled by default. You will need to apply your own
styles.
2. Refer to the documentation for example styles that mimic the previous
versions, which you can customize as needed.
### Recommendations
1. Embrace the flexibility of **Composable components**. Use the `asChild`
pattern for more control over the rendering of components.
2. Use **automatic poster images** by passing the
[playback info](/api-reference/playback/get) response to `getSrc`.
3. There are no changes required to **resume progress on fallback**, which
resumes playback from where it was interrupted when an error occurs, and the
player falls back to another playback protocol.
4. Use `useMediaContext` for building custom components. See the implementation
of the primitives as an example of how to implement them.
### Callouts
1. Note the discontinuation of `autoUrlUpload` and direct IPFS playback. See
below for recommendations for how to migrate from this.
2. The new build system includes `use client` and `use server` directives in the
output. This means that you can directly import the client components into a
RSC and you don't need to wrap them. If you don't use React Server
Components, this doesn't affect you.
### React Native
The React Native package has been deprecated. Consider seeking alternative
solutions or consulting the team for future support plans.
### Replacing `autoUrlUpload`
To replace the usage of `autoUrlUpload`, use the following pseudocode as a guide
for how the logic used to work on the frontend.
```tsx /api/playback theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Livepeer } from "livepeer";
import { parseCid, parseArweaveTxId } from "@livepeer/core/utils";
const livepeer = new Livepeer({
apiKey: process.env.STUDIO_API_KEY ?? "",
});
const possibleIpfsCid =
"https://cloudflare-ipfs.com/ipfs/bafybeie2hgozfameyzawq6kkzc3tuf67g4kkufm4hoefxczpfe2fen2riu";
// if the source contains a CID or Arweave TX ID, these utility functions will parse out the
// ID and be non-null
const decentralizedSource =
parseCid(possibleIpfsCid) ?? parseArweaveTxId(possibleIpfsCid);
if (decentralizedSource?.id) {
// we check if the CID/Arweave ID already exists in the playback info endpoint
const response = await livepeer.playback.get(decentralizedSource.id);
if (!response.playbackInfo) {
// the CID/Arweave ID doesn't exist, so we import it by the URL
await livepeer.asset.createViaURL({
// this is the IPFS CID, or Arweave transaction ID
name: decentralizedSource.id,
// the formatted IPFS CID or Arweave tx ID as a URL:
// ipfs://{CID} or ar://{CID}
url: decentralizedSource.url,
});
// ...continue to poll the created asset and use the decentralized identifier
// to get the playback info, and pass to `getSrc` to use with
const imported = await livepeer.playback.get(decentralizedSource.id);
const source = getSrc(imported.playbackInfo);
return source;
}
}
```
# Clip
Source: https://docs.livepeer.org/v1/sdks/react/player/Clip
The `ClipTrigger` component enables users to create clips from live Player content.
The `ClipTrigger` is designed to be used as a child of the `Player` component.
It interacts with the playback state to provide a user-friendly interface for creating media
clips, **based on the Unix timestamp from the current playback position**.
*Clipping is currently supported only for livestreams*.
## Features
* Automatically handles determining the current playback head in Unix time
* Compatible with the [create clip API](/api-reference/stream/create-clip)
* Keyboard hotkeys and adheres to [WAI-ARIA](https://w3c.github.io/aria/) design
patterns
* Conditional rendering if it is supported by the current media and is enabled
`ClipTrigger` will automatically handle determining the Unix timestamp for the
current playback position. The playback position is *not* the same as the
server livestream head, due to natural latency from server ingest to playback.
This is why Unix timestamps are required, and relative timestamps cannot be
used.
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
export default () => (
);
```
## Usage
`ClipTrigger` is a button that users can interact with to initiate the clip
creation process. It's displayed only if clipping functionality is enabled (by
passing a valid `clipLength` to the Root component).
**It should be wrapped in a LiveIndicator, since the "last n seconds" clipping
functionality is only supported on livestreams.**
## Props
The component accepts all props suitable for a button element, along with
specific props:
### `forceMount`
A boolean that, when set to true, ensures the component is always mounted. This
is particularly useful for controlling animations with external animation
libraries.
### `onClip`
A function that gets called when a clip is requested. It receives an object
containing the `playbackId`, `startTime`, and `endTime`, which can be used to
handle the clip creation process.
## Data Attributes
The `ClipTrigger` component assigns data attributes to its underlying element to
reflect the current state and user interaction capabilities.
### `data-livepeer-controls-clip-button`
Serves to identify the component's role.
### `data-visible`
Indicates the visibility status of the trigger, with `"true"` meaning it's
currently visible (i.e., clip functionality is enabled) and `"false"` denoting
it's not visible, useful for CSS-based animations.
# Container
Source: https://docs.livepeer.org/v1/sdks/react/player/Container
The `Container` component is the container element for the Player. It wraps all other elements and acts as an aspect ratio container by default.
The `Container` component acts as the container div element for the Player,
using either
[@radix-ui/react-aspect-ratio](https://www.radix-ui.com/primitives/docs/components/aspect-ratio)
or a standard div element. It selectively renders one of these based on the
presence of an `aspectRatio` prop. We show above how to disable the aspect
ratio element.
## Features
* Provides an aspect ratio container to reduce
[Cumulative Layout Shift](https://web.dev/cls/)
* Dynamic data attributes for custom styling based on the current media state
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
export default () => (
{/* Place child elements here, like Video and Controls */}
{/* Or place other controls outside of here, to not be bound by the aspect ratio Container */}
);
```
## Data Attributes
These attributes are dynamically updated based on the current state.
### `data-livepeer-aspect-ratio` or `data-livepeer-wrapper`
Indicates the container type. It's present if the container is an aspect ratio
container (with `data-livepeer-aspect-ratio`) or a regular div (with
`data-livepeer-wrapper`).
When `aspectRatio` is set to `null` on the Root component, then it will be a
regular div wrapper with `position: relative`.
### `data-fullscreen`
Reflects whether the content is in fullscreen mode.
* `"true"`: The content is in fullscreen mode.
* `"false"`: The content is not in fullscreen mode.
### `data-playing`
Indicates if the content is currently playing.
* `"true"`: The content is playing.
* `"false"`: The content is not playing.
### `data-can-play`
Shows if the content can be played.
* `"true"`: The content can be played.
* `"false"`: The content cannot be played due to some restrictions or lack of
data.
### `data-playback-rate`
Displays the current playback rate.
* `"normal"`: The playback is at normal speed.
* `"fast"`: The playback is at a speed faster than normal.
* `"slow"`: The playback is at a speed slower than normal.
* `"constant"`: The playback rate is constant (neither fast nor slow).
### `data-error`
Indicates if there is an error in the content.
* `"true"`: There is an error in the content.
* `"false"`: There are no errors in the content.
### `data-loading`
Shows if the content is loading.
* `"true"`: The content is loading.
* `"false"`: The content is not loading.
### `data-live`
Indicates if the content is live.
* `"true"`: The content is live.
* `"false"`: The content is not live.
### `data-has-played`
Reflects if the content has been played.
* `"true"`: The content has been played at least once.
* `"false"`: The content has not been played yet.
### `data-controls-hidden`
Shows if the controls are hidden.
* `"true"`: The controls are hidden.
* `"false"`: The controls are visible.
### `data-picture-in-picture`
Indicates if the picture-in-picture mode is active.
* `"true"`: The picture-in-picture mode is active.
* `"false"`: The picture-in-picture mode is not active.
### `data-video-quality`
Displays the current video quality, directly reflecting the `videoQuality` value
from the state. It can be a string indicating the quality level (e.g., `"720p"`,
`"1080p"`).
# Controls
Source: https://docs.livepeer.org/v1/sdks/react/player/Controls
The `Controls` component provides an interactive container for all other media control elements such as `Play`, `Fullscreen`, etc.
`Controls` serves as the interactive layer for media control actions, dynamically displayed based on the media state, loading state, or presence of an error. It is designed to automatically show upon user interaction with the Container element and hides based on the `Root` component's `autohide` property.
By default, controls are shown during hover or interaction, mimicking the
behavior of standard media players.
## Features
* Automatic conditional rendering based on user interactions
* Click/touch to pause/play media
* Compatible with CSS animations for dynamic enter/exit animations
The visibility of `Controls` is managed automatically, relying on the
`autohide` property of the `Root` component to determine how long after a user
interaction to wait before hiding.
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
export default () => (
{/* Place interactive control elements here, like play/pause buttons, progress bars, etc. */}
);
```
## Props
### `forceMount`
Ensures the component is always in the DOM, useful for animation controls.
### `autoHide`
Defines the auto-hide delay in milliseconds after user interaction. Default is
3000ms. Set to 0 to disable auto-hide.
## Data Attributes
### `data-livepeer-controls`
Identifies the control component within the Player.
### `data-visible`
Indicates if the controls are visible (`"true"`) or not (`"false"`), useful for
CSS-based animations.
# Error
Source: https://docs.livepeer.org/v1/sdks/react/player/Error
The `ErrorIndicator` component is a visual representation of error states in media playback based on error types.
The `Error` component can be shown for all error types, or a subset of them.
It is usually recommended to be more granular in the error types, since some
errors are more "fatal" and some cannot be recovered from.
## Features
* Conditional rendering based on the error state, customizable with the
`matcher` pattern
* Dynamic data attributes for custom styling based on the current error state
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
export default () => (
);
```
## Props
The component accepts all props suitable for a div element, in addition to the
following specific props:
### `forceMount`
A boolean to force the component's presence in the DOM, useful for controlling
animations with external libraries.
### `matcher`
A prop to define the condition under which the `ErrorIndicator` should be
visible. It can be a string indicating a broad category of errors (like `"all"`
or `"not-permissions"`) or a more specific error type. Alternatively, it can be
a function for custom logic, receiving the PlaybackError type and returning a
boolean for whether it should be shown.
## Data Attributes
### `data-livepeer-error-indicator`
Always present to indicate the component's role.
### `data-error-state`
Indicates whether there is an error (`"true"` or `"false"`).
### `data-error-type`
Specifies the type of the current error or `"none"` if no error is present.
Could be one of:
`"offline" | "access-control" | "fallback" | "permissions" | "unknown" | "none"`
### `data-visible`
Reflects whether the indicator is currently visible (`"true"` or `"false"`).
This is often used for dynamically applying enter/exit CSS animations.
# Fullscreen
Source: https://docs.livepeer.org/v1/sdks/react/player/Fullscreen
The `FullscreenIndicator` and `FullscreenTrigger` components provide visual cues and interactive elements for fullscreen functionality.
## Features
* Automatic conditional rendering based on fullscreen status and browser API
availability, customizable with the `matcher` pattern
* Handles all browser APIs back to IE11, with special handling for iOS
* Compatible with CSS animations for dynamic enter/exit animations
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
export default () => (
);
```
## Props
### `FullscreenIndicator`
#### `forceMount`
A boolean that, when true, keeps the component mounted at all times, useful for
controlling animations with external libraries.
#### `matcher`
A prop to define the condition under which the `FullscreenIndicator` should be
visible. It can be a boolean directly matching the fullscreen state or a
function providing custom logic to determine visibility.
### `FullscreenIndicator`
#### `forceMount`
A boolean that, when true, keeps the component mounted at all times, useful for
controlling animations with external libraries.
#### `matcher`
A prop to define the condition under which the `FullscreenIndicator` should be
visible. It can be a boolean directly matching the fullscreen state or a
function providing custom logic to determine visibility.
## Data Attributes
### `FullscreenIndicator`
#### `data-livepeer-controls-fullscreen-indicator`
Indicates the component's role.
#### `data-fullscreen`
Shows the current fullscreen state (`"true"` or `"false"`).
#### `data-visible`
Reflects whether the indicator is currently visible (`"true"` or `"false"`).
This is often used for dynamically applying enter/exit CSS animations.
### `FullscreenTrigger`
#### `data-livepeer-controls-fullscreen-trigger`
Indicates the component's role.
#### `data-fullscreen-state`
Shows the current fullscreen state (`"true"` or `"false"`).
# Live
Source: https://docs.livepeer.org/v1/sdks/react/player/Live
The `LiveIndicator` component visually signals the live status of media playback.
`LiveIndicator` is designed to provide a clear, visual cue of the live status
of the media playback.
## Features
* Conditional rendering based on live playback status, customizable with the
`matcher` pattern
* Adheres to [WAI-ARIA](https://w3c.github.io/aria/) design patterns
* Compatible with CSS animations for dynamic enter/exit animations
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
export default () => (
);
```
## Props
### `forceMount`
Keeps the component always mounted, aiding in managing animations.
### `matcher`
Determines when the `LiveIndicator` is shown, accepting a boolean or a function
for customized visibility logic.
## Data Attributes
### `data-livepeer-live-indicator`
Designates the live indicator component within the Player.
### `data-live`
Denotes the live status (`"true"` for live, `"false"` for not live).
### `data-visible`
Signifies if the indicator is visible (`"true"`) or hidden (`"false"`), useful
for CSS-based animations.
# Loading
Source: https://docs.livepeer.org/v1/sdks/react/player/Loading
The `LoadingIndicator` component is a visual indicator of the loading state of the media.
The `Loading` component can be composed with any other elements. Typically it
is combined with Poster
## Features
* Conditional rendering based on the error state, customizable with the
`matcher` pattern
* Dynamic data attributes for custom styling based on the current error state
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
export default () => (
);
```
## Props
The component accepts all props suitable for a div element, in addition to the
following specific props:
### `forceMount`
A boolean value that, when set to true, ensures the component is always mounted.
This is particularly useful for managing animations with external animation
libraries.
### `matcher`
A prop intended to define the circumstances under which the `LoadingIndicator`
should be visible. It can be a direct boolean comparison with the loading state
or a function that provides custom logic for visibility determination.
## Data Attributes
### `data-livepeer-loading-indicator`
Serves to identify the component's role.
### `data-loading`
Displays the current loading state, `"true"` when media is loading and `"false"`
when it's not.
### `data-visible`
Indicates the visibility status of the indicator, with `"true"` meaning it's
currently visible and `"false"` denoting it's not.
This is often used for dynamically applying enter/exit CSS animations.
# Picture in Picture
Source: https://docs.livepeer.org/v1/sdks/react/player/PictureInPicture
The `PictureInPictureTrigger` component toggles the picture-in-picture mode.
## Features
* Automatic conditional rendering based on browser API availability,
customizable with the `matcher` pattern
* Supports both the [w3c](https://w3c.github.io/picture-in-picture/) standard
(which most modern browsers support), as well as the
[older Safari/iOS spec](https://developer.apple.com/documentation/webkitjs/adding_picture_in_picture_to_your_safari_media_controls)
(see the browsers which support Picture-in-Picture on
[caniuse](https://caniuse.com/picture-in-picture))
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
export default () => (
);
```
## Props
The component accepts all props suitable for a button element.
## Data Attributes
### `data-livepeer-controls-picture-in-picture-trigger`
Serves to identify the component's role.
### `data-picture-in-picture`
Indicates the current picture-in-picture state, `"true"` when the feature is
active and `"false"` otherwise.
### `data-visible`
Reflects the visibility status of the trigger, with `"true"` meaning it's
currently visible (i.e., picture-in-picture is supported and the media is not in
fullscreen mode) and `"false"` denoting it's not visible.
This is often used for dynamically applying enter/exit CSS animations.
# Play
Source: https://docs.livepeer.org/v1/sdks/react/player/Play
The `PlayPauseTrigger` component enables users to toggle playback and the `PlayingIndicator` provides a visual cue for the current playback state.
`PlayPauseTrigger` and `PlayingIndicator` integrate together to form the
typical play/pause interaction for media players. They do not have to be used
together and can combine with other components.
## Features
* Controls the playback state and conditionally renders based on playing status,
customizable with the `matcher` pattern
* Keyboard hotkeys and adheres to [WAI-ARIA](https://w3c.github.io/aria/) design
patterns
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
export default () => (
);
```
## Props
### `PlayPauseTrigger`
Accepts all props for a typical button element.
### `PlayingIndicator`
#### `forceMount`
Ensures the component is always mounted, beneficial for animation consistency.
#### `matcher`
Defines the condition under which the `PlayingIndicator` displays, using a
boolean or a custom function for tailored visibility logic.
## Data Attributes
### PlayPauseTrigger
#### `data-livepeer-play-pause-trigger`
Identifies the play/pause button within the Player.
#### `data-playing`
Shows the playback status (`"true"` for playing, `"false"` for paused).
#### `data-visible`
Signifies if the indicator is visible (`"true"`) or hidden (`"false"`), useful
for CSS-based animations and visibility adjustments.
### PlayingIndicator
#### `data-livepeer-playing-indicator`
Marks the playing status indicator component.
#### `data-playing`
Shows the playback status (`"true"` for playing, `"false"` for paused).
#### `data-visible`
Signifies if the indicator is visible (`"true"`) or hidden (`"false"`), useful
for CSS-based animations.
# Portal
Source: https://docs.livepeer.org/v1/sdks/react/player/Portal
The `Portal` component allows projection of content into different parts of the DOM.
The `Portal` component is a simple wrapper over
[@radix-ui/react-portal](https://www.radix-ui.com/primitives/docs/utilities/portal#portal).
It inherits all of the documentation for the component.
## Features
* Provides an easy way to portal controls out of the Root components
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
export default () => (
{/* Place portalled elements here, which can still
consume the React Context from the Root, but are
appended to the document */}
);
```
## Props
### `children`
React nodes that are to be rendered inside the portal.
### `container`
An optional prop specifying a container element where the portal's children
should be rendered. If not provided, the children are appended to the body of
the document by default.
# Poster
Source: https://docs.livepeer.org/v1/sdks/react/player/Poster
The `Poster` component displays a visual placeholder for media content prior to playback.
When used with Livepeer's playback info API, `getSrc` will automatically parse
any available thumbnail images in the JSON response and pass them to `Poster`.
The example above assumes that the playback info has a "Thumbnail (JPEG)"
source.
## Features
* Displays a preview image as a placeholder while media is loading
* Conditionally renders based on the availability of a thumbnail image
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
export default () => (
);
```
## Props
`Poster` accepts all typical HTML `img` props.
It is usually used alongside a `Player.Video` with poster set to `null`, so
that the default poster URL is not parsed and set on the HTML5 video element.
It can be composed with custom img renderers, like Next.js Image, with the
`asChild` prop, so you can customize the image loading to go through your
optimization pipeline.
### `forceMount`
Ensures consistent presence in the DOM, aiding in the smooth application of
animations.
### `src`
Specifies the URL for the poster image, allowing for a customized preview. If
not set, the component attempts to retrieve a poster from the media's context.
## Data Attributes
### `data-livepeer-poster`
Identifies the poster component within the Player.
### `data-visible`
Signifies if the poster is visible (`"true"`) or hidden (`"false"`), useful for
CSS-based animations.
# Playback Speed
Source: https://docs.livepeer.org/v1/sdks/react/player/RateSelect
The `RateSelect` and `RateSelectItem` components provide an interface for users to adjust the playback speed of the media.
All of the `RateSelect` components extend from
[`@radix-ui/react-select`](https://www.radix-ui.com/primitives/docs/components/select),
and inherits all of the documentation for those components.
## Features
* Composes a dropdown menu for selecting any playback speed, and handles syncing
with the underlying media element
* Keyboard navigation (with Radix) and adheres to
[WAI-ARIA](https://w3c.github.io/aria/) design patterns
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
export default () => (
);
```
## Props
### `RateSelect`
Takes all props of the
[Radix Select Root](https://www.radix-ui.com/primitives/docs/components/select)
component.
### `RateSelectItem`
Takes all props of the
[Radix Select Item](https://www.radix-ui.com/primitives/docs/components/select)
component.
#### `value`
Required - denote the playback speed value as a number.
## Data Attributes
### `RateSelect`
#### `data-livepeer-rate-select`
Identifies the rate select component within the Player.
#### `data-rate`
Indicates the selected playback speed value.
### `RateSelectItem`
#### `data-livepeer-rate-select-item`
Identifies the rate select item within the Player.
# Root
Source: https://docs.livepeer.org/v1/sdks/react/player/Root
The `Player.Root` component is the React Context wrapper for the Player.
This is a comprehensive example of how the Player elements can fit together to
build an advanced video player. This does not only show the Root Player, but
how the Root can be used to provide a state store to all of its children.
## Features
* Pure React Context provider to pass the media store state to all components
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
export default () => (
{/* All child components which use the state store. */}
);
```
## Compatibility
The compatibility table below applies to the Player broadly, since the Root
component is only a React context.
| Browser | Version |
| ------------------ | ------- |
| Chrome | 102+ |
| Chrome for Android | 105+ |
| iOS Safari | 12.2+ |
| Edge | 103+ |
| Safari | 13.1+ |
| Firefox | 103+ |
| Opera | 89+ |
| Samsung Internet | 17+ |
| UC Browser | 13.4+ |
| Firefox Android | 104+ |
| Opera Mini | all |
We aim to support
[\~93%](https://browsersl.ist/#q=last+2+versions%2C%3E+0.2%25%2Cnot+dead) of
browsers tracked on [caniuse](https://caniuse.com/). We use
[browserslist](https://browsersl.ist/) to track compatibility.
## Usage
The `Player.Root` component is a React Context wrapper which passes the player
state store down to all of the child components. It is responsible for creating
the [Zustand](https://github.com/pmndrs/zustand) state store which is consumed
by the children, and listens for media/browser events and keeps state in sync.
The Player automatically handles different source types, such as WebRTC, MP4, and HLS.
These are seamlessly integrated so that playback has low latency under all
network conditions.
It is compatible with WebRTC WHEP endpoints, HLS (and low latency HLS), or
typical media file playable by an HTML5 video element (MP4, WebM).
## Props
### `src`
Defines the source for the Player. It accepts `Src[]`, which can be derived from
various sources like Livepeer playback info, Cloudflare stream data, Mux URLs,
or simple strings.
See `getSrc` for docs on how to easily generate this parameter.
### `autoPlay` and `volume`
Sets the video to autoplay when the content comes into focus on the webpage. If
`autoPlay` is specified, `volume` is highly recommended to be set to 0.
Autoplay will not work
[in many modern browsers](https://developer.chrome.com/blog/autoplay/) without
setting mute to 0.
### `aspectRatio`
Specifies the aspect ratio of the content. Recommended for an optimal
broadcasting experience to minimize
[Cumulative Layout Shift](https://web.dev/cls/). The default value is `16 / 9`.
Set to `null` to disable the aspect ratio container (see `Container`).
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{...}
```
### `hotkeys`
Enables keyboard hotkeys for controlling the player. Enabled by default
(`true`). It's recommended to follow ARIA guidelines by keeping this enabled
unless you're implementing custom hotkeys or there's a conflict with existing
ones.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{...}
```
### `viewerId`
Sets the viewer ID for the broadcast, useful for metrics and viewership API
integration.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{...}
```
### `onError`
An optional callback for handling broadcasting errors. It's called with `null`
when the previous error is resolved. The callback receives the parameter:
```ts theme={"theme":{"light":"github-light","dark":"dark-plus"}}
type PlaybackError = {
type: "offline" | "access-control" | "fallback" | "permissions" | "unknown";
message: string;
};
```
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
console.log(error)}>{...}
```
### `jwt` or `accessKey`
These define ways to play back a video which has a playback policy applied to
it. Your application can prevent playback unless the user meets
application-specific requirements. This can be done either with JWTs or
webhooks.
Defines the JSON Web Token (JWT) or access key used to access media gated by a
`jwt` or `webhook` playback policy respectively. It's crucial for implementing
application-specific access control like restricting viewership based on certain
criteria (e.g., having an activated account, etc.).
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{...}{...}
```
### `lowLatency`
Enables low-latency playback for live streams via WebRTC by default. If set to
`"force"`, it forces WebRTC playback and disables fallback to HLS. This is ideal
for applications requiring low latency and can tolerate possible connectivity
issues inherent to WebRTC.
Defaults to `true`. If this does not succeed in playing back (commonly due to a
slow network or connectivity issues), the Player will automatically fall back to
HLS playback. Also, if the stream contains B-frames (bidirectional frames, which
are common for users streaming with OBS or other streaming apps), the Player
will automatically switch to HLS, so that out-of-order frames are not displayed.
OBS users should be instructed to use the Livepeer stream profile, or to
manually turn off B-frames in their stream. See our [Stream from
OBS](/developers/guides/stream-via-obs) docs for more information.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{...}
```
### `timeout`
Sets the timeout duration for playback before switching to the next source,
including SDP negotiation for WebRTC, waiting for WebRTC to play, and server
responses. The default is 10000 milliseconds.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{...}
```
### `storage`
Configures the storage option for saving persistent states like volume and video
quality. The default is `localStorage` in the browser. Set to `null` to disable
storage.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{...}
```
# Seek
Source: https://docs.livepeer.org/v1/sdks/react/player/Seek
The `Seek` and `SeekBuffer` components provide visual elements for seeking through media and displaying buffer status.
All of the `Seek` components extend from
[`@radix-ui/react-slider`](https://www.radix-ui.com/primitives/docs/components/slider),
and inherits all of the documentation for those components.
## Features
* Composes a slider for the current progress and buffer, and handles syncing
with the underlying media element
* Keyboard navigation (with Radix) and adheres to
[WAI-ARIA](https://w3c.github.io/aria/) design patterns
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
export default () => (
);
```
## Props
### `Seek`
The component accepts all props for a
[Radix Slider](https://www.radix-ui.com/primitives/docs/components/slider)
element.
#### `forceMount`
A boolean that, when set to true, ensures the component is always mounted. This
is particularly useful for managing animations with external animation
libraries.
### `SeekBuffer`
The component accepts all props for a
[Radix Track](https://www.radix-ui.com/primitives/docs/components/slider)
element.
It is usually not used as the Slider Track (since the seekable media isn't
constrained by the amount buffered), but can be used for it, depending on the
use-case.
## Data Attributes
Both components assign several data attributes to their underlying elements to
reflect the current state, user interactions, and visibility conditions.
### `Seek`
#### `data-livepeer-controls-seek`
Serves to identify the component's role within the Player.
#### `data-duration`
Indicates the total duration of the media.
#### `data-progress`
Shows the current progress as a percentage of the total duration.
#### `data-live`
Indicates if the current media is live, `"true"` for live and `"false"` for
non-live media.
#### `data-buffered`
Shows the portion of the media that has been buffered.
#### `data-visible`
Reflects the visibility status of the slider, with `"true"` meaning it's
currently visible (i.e., the media is not live) and `"false"` denoting it's not
visible.
This is often used for dynamically applying enter/exit CSS animations.
### `SeekBuffer`
##### `data-livepeer-controls-seek-buffer`
Identifies the component's role within the Seek slider.
##### `data-buffered`
Shows the portion of the media that has been buffered.
# Time
Source: https://docs.livepeer.org/v1/sdks/react/player/Time
The `Time` component provides a display of the current time, total duration, and progress of the media.
## Features
* Automatic display of friendly time from state store
* Handles live and static assets (e.g. no fixed duration vs fixed duration)
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
export default () => (
);
```
## Props
The component accepts all props suitable for a span element, except for
`children`, since the formatted time will be rendered as the only child.
## Data Attributes
### `data-livepeer-controls-time`
Serves to identify the component's role in the playback interface.
### `data-duration`
Displays the total duration of the media.
### `data-progress`
Indicates the current progress of the media playback, usually represented as a
percentage or time elapsed.
### `data-live`
Shows the live state of the media, `"true"` for live streams and `"false"` for
pre-recorded content.
# Video
Source: https://docs.livepeer.org/v1/sdks/react/player/Video
The `Video` component renders the actual video content and manages various aspects of media playback.
#### Features
* Synchronizes state with the HTML5 video element
* Keyboard hotkeys (`←`/`→` to seek, `K` to pause, `M` to toggle mute, `F`
fullscreen, `I` picture-in-picture)
* Adheres to [WAI-ARIA](https://w3c.github.io/aria/) design patterns
### Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
export default () => (
);
```
## Props
The component accepts most props suitable for a HTML5 `video` tag, except for
`src`, `poster`, `autoPlay`, and `preload`, which are managed internally or
provided explicitly through props.
### `poster`
Optional. Controls the poster source. By default, it uses the thumbnail from the
`Root` src input. Set to `null` to disable the default poster image from the
`Root` src.
### `hlsConfig`
Optional. Controls the HLS.js config. By default, it adds JWT or Access Token
headers to HLS segment requests.
## Data Attributes
### `data-livepeer-video`
Serves to identify the component's role within the Player.
### `data-livepeer-source-type`
Indicates the type of the current source, such as "none" when there's no source,
or other types based on the media being played.
This can be of the type: `"audio" | "video" | "hls" | "webrtc" | "none"`
# Video Quality
Source: https://docs.livepeer.org/v1/sdks/react/player/VideoQualitySelect
The `VideoQualitySelect` and `VideoQualitySelectItem` components allow viewers to select the desired video quality during media playback.
All of the `VideoQualitySelect` components extend from
[`@radix-ui/react-select`](https://www.radix-ui.com/primitives/docs/components/select),
and inherits all of the documentation for those components.
## Features
* Synchronizes state with the HTML5 video element
* Adheres to [WAI-ARIA](https://w3c.github.io/aria/) design patterns
* Persists to `localStorage` by default (with storage overrides customizable in
`Root`)
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
export default () => (
);
```
## Props
### `VideoQualitySelect`
Takes all props of the
[Radix Select Root](https://www.radix-ui.com/primitives/docs/components/select)
component.
### `VideoQualitySelectItem`
Takes all props of the
[Radix Select Item](https://www.radix-ui.com/primitives/docs/components/select)
component.
#### `value`
The `VideoQuality` enum value representing the video quality that the item
corresponds to. This must be provided to ensure correct selection behavior.
This can be of the type:
`"auto" | "1080p" | "720p" | "480p" | "360p" | "240p" | "144p"`
## Data Attributes
### `VideoQualitySelect`
#### `data-livepeer-quality-select`
Serves to identify the component's role within the Player.
#### `data-video-quality`
Indicates the current video quality selection, matching the value of the
selected `VideoQualitySelectItem`.
This can be of the type:
`"auto" | "1080p" | "720p" | "480p" | "360p" | "240p" | "144p"`
### `VideoQualitySelectItem`
#### `data-livepeer-quality-select-item`
Serves to identify the component's role within the Player.
# Volume
Source: https://docs.livepeer.org/v1/sdks/react/player/Volume
The `Volume`, `VolumeIndicator`, and `MuteTrigger` components provide interactive controls for the volume level.
All of the `Volume` components extend from
[`@radix-ui/react-slider`](https://www.radix-ui.com/primitives/docs/components/slider),
and inherits all of the documentation for those components.
## Features
* Conditional rendering based on volume status, customizable with the `matcher`
pattern
* Keyboard shortcuts and adheres to [WAI-ARIA](https://w3c.github.io/aria/)
design patterns
* Compatible with CSS animations for dynamic enter/exit animations
* Persists to `localStorage` by default (with storage overrides customizable in
`Root`)
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
export default () => (
);
```
## Props
### MuteTrigger
Accepts all props for a typical button element.
### VolumeIndicator
#### `forceMount`
A boolean that, when set to true, ensures the component is always mounted. This
is particularly useful for managing animations with external animation
libraries.
#### `matcher`
A prop intended to define the circumstances under which the `VolumeIndicator`
should be visible. It can be a boolean matching the mute state or a function
that provides custom logic for visibility determination based on the volume
level.
### Volume
#### `forceMount`
Keeps the component always mounted, aiding in managing animations.
## Data Attributes
### MuteTrigger
#### `data-livepeer-mute-trigger`
Identifies the mute toggle component within the media player setup.
#### `data-muted`
Shows whether the audio is currently muted (`"true"`) or active (`"false"`),
assisting in the visual representation and scripting based on the mute state.
### VolumeIndicator
#### `data-livepeer-controls-volume-indicator`
Identifies the component's role within the Player.
#### `data-livepeer-muted`
Indicates the mute state, `"true"` if muted and `"false"` otherwise.
#### `data-livepeer-volume`
Shows the current volume as a percentage, e.g., `"50"` for 50% volume.
#### `data-visible`
Indicates the visibility status of the indicator, with `"true"` meaning it's
currently visible based on the `matcher` or mute state and `"false"` denoting
it's not visible.
This is often used for dynamically applying enter/exit CSS animations.
### Volume
#### `data-livepeer-controls-volume`
Serves to identify the component's role within the Player.
#### `data-livepeer-muted`
Indicates the mute state, `"true"` if muted and `"false"` otherwise.
#### `data-livepeer-volume`
Shows the current volume as a percentage, e.g., `"50"` for 50% volume.
#### `data-visible`
Reflects the visibility status of the slider, with `"true"` meaning it's
currently visible (i.e., volume change is supported) and `"false"` denoting it's
not visible.
# getSrc
Source: https://docs.livepeer.org/v1/sdks/react/player/get-src
`getSrc` is a utility function for parsing various types of playback information and converting them into a standardized format suitable for the Player.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { getSrc } from "@livepeer/react/external";
import * as Player from "@livepeer/react/player";
// An example response from the livepeer playback info API endpoint
const vodSource = {
type: "vod",
meta: {
playbackPolicy: null,
source: [
{
hrn: "HLS (TS)",
type: "html5/application/vnd.apple.mpegurl",
url: "https://lp-playback.com/hls/f5eese9wwl88k4g8/index.m3u8",
},
],
},
};
// This is either an array of `Src` or null,
// and can be passed into the Player.Root `src`
const src = getSrc(vodSource);
export default () => (
{/* All child components. */}
);
```
#### Features
* Supports inputs like Livepeer playback info, Cloudflare stream data, Mux URLs,
arrays of strings, and single strings
* Transforms into `Src[]` which contains essential playback information, along
with supportive metadata like thumbnails and VTT files.
### Functionality
#### Input Types
The function can process the following input types:
* `LivepeerPlaybackInfo`: Extracts the 'source' array from its 'meta' property
from the playback info endpoint.
* `LivepeerSource` or `LivepeerSource[]`: Uses the source object(s) directly.
* `CloudflareStreamData`: Retrieves the stream data from a Cloudflare stream
data object.
* `string[]`: Assumes each string as a URL and creates an array of Source
objects.
* `string`: Assumes the string is a URL and creates a single Source object.
#### Output Format
The output is an array of `Src` objects or `null` if the input is invalid or
empty.
# useMediaContext
Source: https://docs.livepeer.org/v1/sdks/react/player/useMediaContext
The `useMediaContext` hook lets you build custom components which interact directly with the media state store.
The `useStore` hook is from
[`zustand`](https://github.com/pmndrs/zustand?tab=readme-ov-file#using-zustand-without-react),
and inherits all of the documentation for Zustand stores.
## Features
* Flexible interaction with the player state store
* Based on Zustand's `useStore` hooks
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
import { useMediaContext, useStore } from "@livepeer/react/player";
export default () => (
{/** The `useMediaContext` hook can be used in any component,
as long as it's inside the Player.Root React Context provider */}
);
function CustomComponent({ __scopeMedia }: MediaScopedProps) {
const context = useMediaContext("CustomComponent", __scopeMedia);
const { currentSource } = useStore(context.store, ({ currentSource }) => ({
currentSource,
}));
return currentSource?.type ?? null;
}
```
## State
The `useMediaContext` hook returns a Zustand store, which contains the
`PlayerState`.
### `aria`
The ARIA text for the current state, providing accessible descriptions for media
control actions.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
type AriaText = {
progress: string;
pictureInPicture: string;
fullscreen: string;
playPause: string;
clip: string | null;
time: string;
};
aria: AriaText;
```
### `buffered`
Current buffered end time for the media in seconds.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
buffered: number;
```
### `bufferedPercent`
Current buffered percent of the media, from 0 to 1.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
bufferedPercent: number;
```
### `canPlay`
Indicates if the media has loaded sufficiently and can be played.
### `currentSource`
The current source that is playing.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
type Src =
| AudioSrc
| HlsSrc
| VideoSrc
| Base64Src
| WebRTCSrc
| ImageSrc
| VideoTextTrackSrc;
currentSource: Src | null;
```
### `currentUrl`
The final playback URL for the media that is playing, after any redirects.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
currentUrl: string | null;
```
### `duration`
Current total duration of the media in seconds.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
duration: number;
```
### `error`
If the media has experienced an error, this property provides details.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
type PlaybackError = {
type: "offline" | "access-control" | "fallback" | "permissions" | "unknown";
message: string;
};
error: PlaybackError | null;
```
### `errorCount`
The number of consecutive errors that have occurred during the media playback,
without resolution.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
errorCount: number;
```
### `stalled`
Indicates if the media playback is currently stalled.
### `fullscreen`
Indicates if the media is being played in fullscreen mode.
### `hasPlayed`
Indicates if the media has been played yet.
### `hidden`
Indicates if all controls are currently hidden.
### `live`
Indicates if the content is live media.
### `loading`
Indicates if the media is currently loading.
### `mounted`
Indicates if the video element is mounted on the DOM. This is used for
initialization logic.
### `playbackRate`
The current playback rate for the media. Defaults to 1. `constant` means playing
WebRTC playback at a constant pace and not speeding up.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
type PlaybackRate = number | "constant";
playbackRate: PlaybackRate;
```
### `pictureInPicture`
Indicates if the media is in picture in picture mode.
### `poster`
The poster image URL for the media. Any thumbnails are automatically parsed from
the input `Src[]`.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
poster: string | null;
```
### `progress`
Current progress of the media in seconds.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
progress: number;
```
### `playing`
Indicates if the media is currently trying to play or paused.
### `sortedSources`
The sorted sources that were passed into the Player. These are the playback
sources which will be tried, in order (e.g. WebRTC with a fallback to HLS).
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
sortedSources: Src[] | string | null;
```
### `volume`
Current volume of the media. 0 if it is muted.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
volume: number;
```
### `waiting`
Indicates if the media is currently waiting for data.
### `videoQuality`
The quality of the video playback.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
type VideoQuality =
| "1080p"
| "720p"
| "480p"
| "360p"
| "240p"
| "144p"
| "auto";
videoQuality: VideoQuality;
```
### `ended`
Indicates if the media playback has ended.
### `__controlsFunctions`
An object containing functions to manipulate the media's state, such as toggling
play/pause, seeking, and changing volume.
These functions are internal - please refer to the UI Kit source code before
interacting with these functions.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
__controlsFunctions: {
setHidden: (hidden: boolean) => void;
onCanPlay: () => void;
onDurationChange: (duration: number) => void;
onEnded: () => void;
onError: (error: Error | null) => void;
onFinalUrl: (url: string | null) => void;
onLoading: () => void;
onPause: () => void;
onPlay: () => void;
onProgress: (time: number) => void;
onStalled: () => void;
onWaiting: () => void;
requestClip: () => void;
requestMeasure: () => void;
requestSeek: (time: number) => void;
requestSeekBack: (difference?: number) => void;
requestSeekDiff: (difference: number) => void;
requestSeekForward: (difference?: number) => void;
requestToggleFullscreen: () => void;
requestToggleMute: () => void;
requestTogglePictureInPicture: () => void;
requestVolume: (volume: number) => void;
setAutohide: (autohide: number) => void;
setFullscreen: (fullscreen: boolean) => void;
setHlsConfig: (hlsConfig: any) => void;
setLive: (live: boolean) => void;
setMounted: () => void;
setPictureInPicture: (pictureInPicture: boolean) => void;
setPlaybackRate: (rate: number | string) => void;
setPoster: (poster: string | null) => void;
setVideoQuality: (videoQuality: VideoQuality) => void;
setSize: (size: Partial) => void;
setVolume: (volume: number) => void;
setWebsocketMetadata: (metadata: Metadata) => void;
togglePlay: (force?: boolean) => void;
updateBuffered: (buffered: number) => void;
updateLastInteraction: () => void;
updatePlaybackOffsetMs: (offset: number) => void;
};
```
### `__device`
Information about the device's capabilities and support for media features. This
is an internal object used by Player/Broadcast, but can be used for detecting
device capabilities.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
type DeviceInformation = {
version: string;
isMobile: boolean;
isIos: boolean;
isAndroid: boolean;
userAgent: string;
screenWidth: number | null;
/** If the media supports changing the volume */
isVolumeChangeSupported: boolean;
/** If the media supports PiP */
isPictureInPictureSupported: boolean;
/** If the media supports fullscreen */
isFullscreenSupported: boolean;
/** If the media supports HLS playback */
isHlsSupported: boolean;
/** If the media supports WebRTC */
isWebRTCSupported: boolean;
};
__device: DeviceInformation;
```
### `__controls`
Represents the state of various media control actions, such as play/pause and
fullscreen changes. This is an internal object used by Player/Broadcast.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
__controls: ControlsState;
```
### `__initialProps`
The initial properties passed into the media component. This is an internal
object used by Player/Broadcast.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
__initialProps: InitialProps;
```
### `__metadata`
Metadata related to the media, such as buffer window and frame rate. This is an
internal object used by Player/Broadcast.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
type Metadata = {
bframes?: number;
bufferWindow?: number;
};
__metadata: Metadata | null;
```
# Audio To Text
Source: https://docs.livepeer.org/v1/ai/api-reference/audio-to-text
post /audio-to-text
Transcribe audio files to text.
The default Gateway used in this guide is the public
[Livepeer.cloud](https://www.livepeer.cloud/) Gateway. It is free to use but
not intended for production-ready applications. For production-ready
applications, consider using the [Livepeer Studio](https://livepeer.studio/)
Gateway, which requires an API token. Alternatively, you can set up your own
Gateway node or partner with one via the `ai-video` channel on
[Discord](https://discord.gg/livepeer).
Please note that the exact parameters, default values, and responses may vary
between models. For more information on model-specific parameters, please
refer to the respective model documentation available in the [audio-to-text
pipeline](/ai/pipelines/audio-to-text). Not all parameters might be available
for a given model.
# Image To Image
Source: https://docs.livepeer.org/v1/ai/api-reference/image-to-image
post /image-to-image
Apply image transformations to a provided image.
The default Gateway used in this guide is the public
[Livepeer.cloud](https://www.livepeer.cloud/) Gateway. It is free to use but
not intended for production-ready applications. For production-ready
applications, consider using the [Livepeer Studio](https://livepeer.studio/)
Gateway, which requires an API token. Alternatively, you can set up your own
Gateway node or partner with one via the `ai-video` channel on
[Discord](https://discord.gg/livepeer).
Please note that the exact parameters, default values, and responses may vary
between models. For more information on model-specific parameters, please
refer to the respective model documentation available in the [image-to-image
pipeline](/ai/pipelines/image-to-image). Not all parameters might be available
for a given model.
# Image To Text
Source: https://docs.livepeer.org/v1/ai/api-reference/image-to-text
post /image-to-text
Transform image files to text.
The default Gateway used in this guide is the public
[Livepeer.cloud](https://www.livepeer.cloud/) Gateway. It is free to use but
not intended for production-ready applications. For production-ready
applications, consider using the [Livepeer Studio](https://livepeer.studio/)
Gateway, which requires an API token. Alternatively, you can set up your own
Gateway node or partner with one via the `ai-video` channel on
[Discord](https://discord.gg/livepeer).
Please note that the exact parameters, default values, and responses may vary
between models. For more information on model-specific parameters, please
refer to the respective model documentation available in the [image-to-text
pipeline](/ai/pipelines/image-to-text). Not all parameters might be available
for a given model.
# Image To Video
Source: https://docs.livepeer.org/v1/ai/api-reference/image-to-video
post /image-to-video
Generate a video from a provided image.
The default Gateway used in this guide is the public
[Livepeer.cloud](https://www.livepeer.cloud/) Gateway. It is free to use but
not intended for production-ready applications. For production-ready
applications, consider using the [Livepeer Studio](https://livepeer.studio/)
Gateway, which requires an API token. Alternatively, you can set up your own
Gateway node or partner with one via the `ai-video` channel on
[Discord](https://discord.gg/livepeer).
Please note that the exact parameters, default values, and responses may vary
between models. For more information on model-specific parameters, please
refer to the respective model documentation available in the [image-to-video
pipeline](/ai/pipelines/image-to-video). Not all parameters might be available
for a given model.
# LLM
Source: https://docs.livepeer.org/v1/ai/api-reference/llm
post /llm
Generate text using a language model.
The LLM pipeline is OpenAI API-compatible but does **not** implement all
features of the OpenAI API.
The default Gateway used in this guide is the public
[Livepeer.cloud](https://www.livepeer.cloud/) Gateway. It is free to use but
not intended for production-ready applications. For production-ready
applications, consider using the [Livepeer Studio](https://livepeer.studio/)
Gateway, which requires an API token. Alternatively, you can set up your own
Gateway node or partner with one via the `ai-video` channel on
[Discord](https://discord.gg/livepeer).
### Streaming Responses
Ensure your client supports SSE and processes each `data:` line as it arrives.
By default, the `/llm` endpoint returns a single JSON response in the OpenAI
[chat/completions](https://platform.openai.com/docs/api-reference/chat/object)
format, as shown in the sidebar.
To receive responses token-by-token, set `"stream": true` in the request body.
The server will then use **Server-Sent Events (SSE)** to stream output in real
time.
Each streamed chunk will look like:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
data: {
"choices": [
{
"delta": {
"content": "...token...",
"role": "assistant"
},
"finish_reason": null
}
]
}
```
The final chunk will have empty content and `"finish_reason": "stop"`:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
data: {
"choices": [
{
"delta": {
"content": "",
"role": "assistant"
},
"finish_reason": "stop"
}
]
}
```
# Introduction
Source: https://docs.livepeer.org/v1/ai/api-reference/overview
Learn more about Livepeer's AI API.
Welcome to the Livepeer AI API reference docs! Here you'll find all the
endpoints exposed on the standard Livepeer AI API, learn how to use them and
what they return.
The Livepeer API is organized around REST, has predictable resource-oriented
URLs, accepts JSON request bodies, returns JSON-encoded responses, and uses
standard HTTP response codes, authentication, and verbs.
There are multiple gateway providers active in the ecosystem that can be used to
interact with the Livepeer AI network. For more details, visit the
[AI Gateways](/ai/builders/gateways) page.
# Segment Anything 2
Source: https://docs.livepeer.org/v1/ai/api-reference/segment-anything-2
post /segment-anything-2
Segment objects in an image.
The default Gateway used in this guide is the public
[Livepeer.cloud](https://www.livepeer.cloud/) Gateway. It is free to use but
not intended for production-ready applications. For production-ready
applications, consider using the [Livepeer Studio](https://livepeer.studio/)
Gateway, which requires an API token. Alternatively, you can set up your own
Gateway node or partner with one via the `ai-video` channel on
[Discord](https://discord.gg/livepeer).
Please note that the exact parameters, default values, and responses may vary
between models. For more information on model-specific parameters, please
refer to the respective model documentation available in the
[segment-anything-2 pipeline](/ai/pipelines/segment-anything-2). Not all
parameters might be available for a given model.
# Text To Image
Source: https://docs.livepeer.org/v1/ai/api-reference/text-to-image
post /text-to-image
Generate images from text prompts.
The default Gateway used in this guide is the public
[Livepeer.cloud](https://www.livepeer.cloud/) Gateway. It is free to use but
not intended for production-ready applications. For production-ready
applications, consider using the [Livepeer Studio](https://livepeer.studio/)
Gateway, which requires an API token. Alternatively, you can set up your own
Gateway node or partner with one via the `ai-video` channel on
[Discord](https://discord.gg/livepeer).
Please note that the exact parameters, default values, and responses may vary
between models. For more information on model-specific parameters, please
refer to the respective model documentation available in the [text
pipeline](/ai/pipelines/text-to-image). Not all parameters might be available
for a given model.
# Text To Speech
Source: https://docs.livepeer.org/v1/ai/api-reference/text-to-speech
post /text-to-speech
Generate a text-to-speech audio file based on the provided text input and speaker description.
The default Gateway used in this guide is the public
[Livepeer.cloud](https://www.livepeer.cloud/) Gateway. It is free to use but
not intended for production-ready applications. For production-ready
applications, consider using the [Livepeer Studio](https://livepeer.studio/)
Gateway, which requires an API token. Alternatively, you can set up your own
Gateway node or partner with one via the `ai-video` channel on
[Discord](https://discord.gg/livepeer).
Please note that the exact parameters, default values, and responses may vary
between models. For more information on model-specific parameters, please
refer to the respective model documentation available in the [text-to-speech
pipeline](/ai/pipelines/text-to-speech). Not all parameters might be available
for a given model.
# Upscale
Source: https://docs.livepeer.org/v1/ai/api-reference/upscale
post /upscale
Upscale an image by increasing its resolution.
The default Gateway used in this guide is the public
[Livepeer.cloud](https://www.livepeer.cloud/) Gateway. It is free to use but
not intended for production-ready applications. For production-ready
applications, consider using the [Livepeer Studio](https://livepeer.studio/)
Gateway, which requires an API token. Alternatively, you can set up your own
Gateway node or partner with one via the `ai-video` channel on
[Discord](https://discord.gg/livepeer).
Please note that the exact parameters, default values, and responses may vary
between models. For more information on model-specific parameters, please
refer to the respective model documentation available in the [upscaling
pipeline](/ai/pipelines/upscale). Not all parameters might be available for a
given model.
# Delete an asset
Source: https://docs.livepeer.org/v1/api-reference/asset/delete
DELETE /asset/{assetId}
# Retrieve an asset
Source: https://docs.livepeer.org/v1/api-reference/asset/get
GET /asset/{assetId}
# Retrieve assets
Source: https://docs.livepeer.org/v1/api-reference/asset/get-all
GET /asset
# Overview
Source: https://docs.livepeer.org/v1/api-reference/asset/overview
The Assets API is used to create, retrieve, update, delete assets object from pipeline.
### Asset object
This is a unique identifier for the asset.
Type of the asset. This can be either 'video' or 'audio'.
Used to form playback URL and storage folder.
Whether to generate MP4s for the asset.
Attach Livepeer Studio C2PA Attestation in the output mp4 video.
URL for HLS playback.
URL to manually download the asset if desired.
Reference to the playback-policy schema.
Source of the asset, which can be URL, recording, directUpload, or clip.
Reference to the creator-id schema.
Information about the storage of the asset, particularly on IPFS.
Status of the asset, including its phase, update time, and any error message.
Name of the asset. This is not necessarily the filename, can be a custom name
or title.
Timestamp (in milliseconds) at which asset was created.
Size of the asset in bytes.
Hash of the asset.
Video metadata including format, duration, bitrate, and tracks information.
```json Response theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"id": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"type": "video",
"playbackId": "eaw4nk06ts2d0mzb",
"staticMp4": "boolean",
"c2pa": "boolean",
"playbackUrl": "https://livepeercdn.com/asset/ea03f37e-f861-4cdd-b495-0e60b6d753ad/index.m3u8",
"downloadUrl": "https://livepeercdn.com/asset/eaw4nk06ts2d0mzb/video",
"playbackPolicy": {
"type": "public",
"webhookId": "3e02c844-d364-4d48-b401-24b2773b5d6c",
"webhookContext": {
"foo": "bar"
}
},
"source": {
"type": "url",
"url": "https://example.com/video.mp4",
"gatewayUrl": "https://example.com/video.mp4"
},
"creatorId": "object",
"storage": {
"ipfs": {
"spec": {
"nftMetadataTemplate": "file",
"nftMetadata": {
"name": "My NFT",
"description": "My NFT description"
}
}
}
},
"status": {
"phase": "ready",
"updatedAt": 1587667174725,
"progress": 100
},
"name": "filename.mp4",
"createdAt": 1587667174725,
"size": 84934509,
"hash": [
{
"hash": "9b560b28b85378a5004117539196ab24e21bbd75b0e9eb1a8bc7c5fd80dc5b57",
"algorithm": "sha256"
}
],
"videoSpec": {
"format": "mp4",
"duration": 23.8328,
"bitrate": 1000000,
"tracks": [
{
"type": "video",
"codec": "h264",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"width": 1920,
"height": 1080,
"pixelFormat": "yuv420p",
"fps": 30
},
{
"type": "audio",
"codec": "aac",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"channels": 2,
"sampleRate": 44100,
"bitDepth": 16
}
]
}
}
```
# Update an asset
Source: https://docs.livepeer.org/v1/api-reference/asset/update
PATCH /asset/{assetId}
# Upload an asset
Source: https://docs.livepeer.org/v1/api-reference/asset/upload
POST /asset/request-upload
To upload an asset, your first need to request for a direct upload URL
and only then actually upload the contents of the asset.
\
\
Once you created a upload link, you have 2 options, resumable or direct
upload. For a more reliable experience, you should use resumable uploads
which will work better for users with unreliable or slow network
connections. If you want a simpler implementation though, you should
just use a direct upload.
## Direct Upload
For a direct upload, make a PUT request to the URL received in the url
field of the response above, with the raw video file as the request
body. response above:
## Resumable Upload
Livepeer supports resumable uploads via Tus. This section provides a
simple example of how to use tus-js-client to upload a video file.
\
\
From the previous section, we generated a URL to upload a video file to
Livepeer on POST /api/asset/request-upload. You should use the
tusEndpoint field of the response to upload the video file and track the
progress:
```
# This assumes there is an `input` element of `type="file"` with id
`fileInput` in the HTML
const input = document.getElementById('fileInput');
const file = input.files[0];
const upload = new tus.Upload(file, {
endpoint: tusEndpoint, // URL from `tusEndpoint` field in the
`/request-upload` response
metadata: {
filename,
filetype: 'video/mp4',
},
uploadSize: file.size,
onError(err) {
console.error('Error uploading file:', err);
},
onProgress(bytesUploaded, bytesTotal) {
const percentage = ((bytesUploaded / bytesTotal) * 100).toFixed(2);
console.log('Uploaded ' + percentage + '%');
},
onSuccess() {
console.log('Upload finished:', upload.url);
},
});
const previousUploads = await upload.findPreviousUploads();
if (previousUploads.length > 0) {
upload.resumeFromPreviousUpload(previousUploads[0]);
}
upload.start();
```
> Note: If you are using tus from node.js, you need to add a custom URL
storage to enable resuming from previous uploads. On the browser, this
is enabled by default using local storage. In node.js, add urlStorage:
new tus.FileUrlStorage("path/to/tmp/file"), to the UploadFile object
definition above.
# Upload asset via URL
Source: https://docs.livepeer.org/v1/api-reference/asset/upload-via-url
POST /asset/upload/url
# Audio To Text
Source: https://docs.livepeer.org/v1/api-reference/generate/audio-to-text
POST /api/beta/generate/audio-to-text
# Image To Image
Source: https://docs.livepeer.org/v1/api-reference/generate/image-to-image
POST /api/beta/generate/image-to-image
# Image To Video
Source: https://docs.livepeer.org/v1/api-reference/generate/image-to-video
POST /api/beta/generate/image-to-video
# LLM
Source: https://docs.livepeer.org/v1/api-reference/generate/llm
## Overview
The `llm` pipeline provides an OpenAI-compatible interface for text generation,
designed to integrate seamlessly into media workflows.
## Models
The `llm` pipeline supports **any Hugging Face-compatible LLM model**. Since
models evolve quickly, the set of warm (preloaded) models on Orchestrators
changes regularly.
To see which models are currently available, check the
[Network Capabilities dashboard](https://tools.livepeer.cloud/ai/network-capabilities).\
At the time of writing, the most commonly available model is
[meta-llama/Meta-Llama-3.1-8B-Instruct](https://huggingface.co/meta-llama/Llama-3.1-8B-Instruct).
For faster responses with different
[LLM](https://huggingface.co/models?pipeline_tag=text-generation) diffusion
models, ask Orchestrators to load it on their GPU via the `ai-video` channel
in [Discord Server](https://discord.gg/livepeer).
## Basic Usage Instructions
For a detailed understanding of the `llm` endpoint and to experiment with the
API, see the [Livepeer AI API Reference](/ai/api-reference/llm).
To generate text with the `llm` pipeline, send a `POST` request to the Gateway's
`llm` API endpoint:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -X POST "https:///llm" \
-H "Authorization: Bearer " \
-H "Content-Type: application/json" \
-d '{
"model": "meta-llama/Meta-Llama-3.1-8B-Instruct",
"messages": [
{ "role": "user", "content": "Tell a robot story." }
]
}'
```
In this command:
* `` should be replaced with your AI Gateway's IP address.
* `` should be replaced with your API token.
* `model` is the LLM model to use for generation.
* `messages` is the conversation or prompt input for the model.
For additional optional parameters such as `temperature`, `max_tokens`, or
`stream`, refer to the [Livepeer AI API Reference](/ai/api-reference/llm).
After execution, the Orchestrator processes the request and returns the response
to the Gateway:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"id": "chatcmpl-abc123",
"model": "meta-llama/Meta-Llama-3.1-8B-Instruct",
"choices": [
{
"message": {
"role": "assistant",
"content": "Once upon a time, in a gleaming city of circuits..."
}
}
]
}
```
By default, responses are returned as a single JSON object. To stream output
token-by-token using **Server-Sent Events (SSE)**, set `"stream": true` in the
request body.
## Orchestrator Configuration
To configure your Orchestrator to serve the `llm` pipeline, refer to the
[Orchestrator Configuration](/ai/orchestrators/get-started) guide.
### Tuning Environment Variables
The `llm` pipeline supports several environment variables that can be adjusted
to optimize performance based on your hardware and workload. These are
particularly helpful for managing memory usage and parallelism when running
large models.
Enables 8-bit quantization using `bitsandbytes` for lower memory usage. Set to
`true` to enable. Defaults to `false`.
Number of pipeline parallel stages. Should not exceed the number of model
layers. Defaults to `1`.
Number of tensor parallel units. Must divide evenly into the number of
attention heads in the model. Defaults to `1`.
Maximum number of tokens per input sequence. Defaults to `8192`.
Maximum number of tokens processed in a single batch. Should be greater than
or equal to `MAX_MODEL_LEN`. Defaults to `8192`.
Maximum number of sequences processed per batch. Defaults to `128`.
Target GPU memory utilization as a float between `0` and `1`. Higher values
make fuller use of GPU memory. Defaults to `0.97`.
### System Requirements
The following system requirements are recommended for optimal performance:
* [NVIDIA GPU](https://developer.nvidia.com/cuda-gpus) with **at least 16GB** of
VRAM.
## Recommended Pipeline Pricing
We are planning to simplify the pricing in the future so orchestrators can set
one AI price per compute unit and have the system automatically scale based on
the model's compute requirements.
The `/llm` pipeline is currently priced based on the **maximum output tokens**
specified in the request — not actual usage — due to current payment system
limitations. We're actively working to support usage-based pricing to better
align with industry standards.
The LLM pricing landscape is highly competitive and rapidly evolving.
Orchestrators should set prices based on their infrastructure costs and
[market positioning](https://llmpricecheck.com/). As a reference, inference on
`llama-3-8b-instruct` is currently around `0.08 USD` per 1 million **output
tokens**.
## API Reference
Explore the `llm` endpoint and experiment with the API in the Livepeer AI API
Reference.
# Overview
Source: https://docs.livepeer.org/v1/api-reference/generate/overview
The Generate API is used to run generative AI models.
These APIs implement the [Livepeer AI Gateway API spec](/ai/api-reference) and
are served under the Studio platform suite. They are prefixed with
`/api/beta/generate` and are used to run AI models to generate content.
# Segment Anything 2
Source: https://docs.livepeer.org/v1/api-reference/generate/segment-anything-2
POST /api/beta/generate/segment-anything-2
# Text To Image
Source: https://docs.livepeer.org/v1/api-reference/generate/text-to-image
POST /api/beta/generate/text-to-image
# Upscale
Source: https://docs.livepeer.org/v1/api-reference/generate/upscale
POST /api/beta/generate/upscale
# Create a multistream
Source: https://docs.livepeer.org/v1/api-reference/multistream/create
POST /multistream/target
# Delete a multistream
Source: https://docs.livepeer.org/v1/api-reference/multistream/delete
DELETE /multistream/target/{id}
Make sure to remove any references to the target on existing
streams before actually deleting it from the API.
# Retrieve a multistream
Source: https://docs.livepeer.org/v1/api-reference/multistream/get
GET /multistream/target/{id}
# Retrieve all multistreams
Source: https://docs.livepeer.org/v1/api-reference/multistream/get-all
GET /multistream/target
# Overview
Source: https://docs.livepeer.org/v1/api-reference/multistream/overview
The Multistream target API is used to create, retrieve, update, delete multi-stream targets object from pipeline.
### Multistream target object
Unique identifier for the multistream target.
Name of the multistream target.
Livepeer-compatible multistream target URL (RTMP(S) or SRT). This URL is used
for streaming to the target platform.
Indicates if this multistream target is disabled. If true, it will not be used
for pushing even if configured in a stream object.
Timestamp (in milliseconds) at which the multistream target object was
created.
```json Response theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"id": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"name": "My Multistream Target",
"url": "rtmps://live.my-service.tv/channel/secretKey",
"disabled": "boolean",
"createdAt": 1587667174725
}
```
# Update a multistream
Source: https://docs.livepeer.org/v1/api-reference/multistream/update
PATCH /multistream/target/{id}
# Authentication
Source: https://docs.livepeer.org/v1/api-reference/overview/authentication
Learn more about Livepeer's API.
Livepeer API uses API keys to verify and authorize requests. You can manage and
review your API keys through Livepeer Studio. You need to pass your API key in
the `Authorization` header with a `Bearer` prefix while sending a request.
```
Bearer YOUR_API_KEY
```
It's important to note that your API keys come with significant privileges, so
it's essential to keep them safe and secure! Refrain from sharing your secret
API keys in GitHub or other publicly accessible places.
By default, API keys can only be used from a backend server. This is to ensure
maximum security and prevent that you accidentally expose your account by
including the secret API key in a public web page.
### CORS-Enabled Keys
Please read the below documentation in its entirety before using CORS-enabled
API keys. **There is a different security model for CORS keys.**
Studio supports the creation of CORS-enabled API keys. This is a special option
when generating an API key which allows a webpage to make requests **directly**
to Studio, as opposed to coming from your backend.
#### Security with CORS Keys
**The security model is different for CORS-enabled API keys.** Since any user
has access to these keys, the IDs of assets and streams **must** be kept secret
from anyone who should not have admin control over them. For instance, a viewer
should only have access to the playback ID, since knowing the asset ID (together
with the CORS-enabled API key, which is embedded in the webpage) allows them to
make changes to the asset.
This is the same for streams - if a user has access to a stream ID alongside the
CORS API key, they can modify the stream or view the stream key. If a viewer had
access to the stream ID + CORS API key, they could hijack the stream. **A
`playbackId` should be exposed to the viewer only.**
# Introduction
Source: https://docs.livepeer.org/v1/api-reference/overview/introduction
Learn more about Livepeer's API.
Welcome to the Livepeer API reference docs! Here you'll find all the endpoints
exposed on the standard Livepeer API, learn how to use them and what they
return.
The Livepeer API is organized around REST, has predictable resource-oriented
URLs, accepts JSON request bodies, returns JSON-encoded responses, and uses
standard HTTP response codes, authentication, and verbs.
# Retrieve Playback Info
Source: https://docs.livepeer.org/v1/api-reference/playback/get
GET /playback/{id}
# Overview
Source: https://docs.livepeer.org/v1/api-reference/playback/overview
The Playback API is used to retrieve playback object from pipeline.
### Playback Object
Type of playback, such as live, vod, or recording.
Metadata for the playback information. This includes details about the source,
playback policy, and attestation.
Indicates if the playback is live (1) or not (0).
Reference to the playback-policy schema.
Array of source objects detailing the playback sources. Each source includes
HRN, type, URL, size, width, height, and bitrate.
Human-readable name (HRN) for the playback source format.
MIME type of the playback source.
URL for the playback source.
Size of the playback source file.
Width of the video in pixels.
Height of the video in pixels.
Bitrate of the playback source.
Reference to the attestation schema.
```json Response theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"type": "vod",
"meta": {
"live": 0,
"playbackPolicy": {
"type": "public",
"webhookId": "3e02c844-d364-4d48-b401-24b2773b5d6c",
"webhookContext": {
"foo": "bar"
}
},
"source": [
{
"hrn": "MP4",
"type": "html5/video/mp4",
"url": "https://asset-cdn.lp-playback.studio/hls/1bde4o2i6xycudoy/static360p0.mp4",
"size": 494778,
"width": 204,
"height": 360,
"bitrate": 449890
}
],
"attestation": {
"id": "5b9e63bb-6fd0-4bea-aff2-cc5d4eb9cad0",
"primaryType": "VideoAttestation",
"domain": {
"name": "Verifiable Video",
"version": "1"
},
"message": {
"video": "string",
"attestations": [
{
"role": "string",
"address": "string"
}
],
"signer": "string",
"timestamp": "number"
},
"signature": "string",
"createdAt": 1587667174725,
"signatureType": "eip712",
"storage": {
"ipfs": {
"cid": "bafybeihoqtemwitqajy6d654tmghqqvxmzgblddj2egst6yilplr5num6u",
"url": "ipfs://bafybeihoqtemwitqajy6d654tmghqqvxmzgblddj2egst6yilplr5num6u",
"gatewayUrl": "https://ipfs.io",
"updatedAt": 1587667174725
},
"status": {
"phase": "ready",
"progress": 0.5,
"errorMessage": "Failed to export to IPFS",
"tasks": {
"pending": "string",
"last": "string",
"failed": "string"
}
}
}
}
}
}
```
# Retrieve a session
Source: https://docs.livepeer.org/v1/api-reference/session/get
GET /session/{id}
# Retrieve all sessions
Source: https://docs.livepeer.org/v1/api-reference/session/get-all
GET /session
# Retrieve clips of a session
Source: https://docs.livepeer.org/v1/api-reference/session/get-clip
GET /session/{id}/clips
# Retrieve recorded sessions
Source: https://docs.livepeer.org/v1/api-reference/session/get-recording
GET /stream/{parentId}/sessions
# Overview
Source: https://docs.livepeer.org/v1/api-reference/session/overview
The Sessions API is used to retrieve sessions object from pipeline.
### Session Object
Unique identifier for the session.
Name of the session.
Timestamp of the last activity in the session.
Number of source segments in the session.
Number of transcoded segments in the session.
Duration of all the source segments in seconds.
Duration of all the transcoded segments in seconds.
Total bytes of source segments.
Total bytes of transcoded segments.
Rate at which sourceBytes increases (bytes/second).
Rate at which transcodedBytes increases (bytes/second).
Reference to the stream-health-payload schema for health status.
Reference to the stream-health-payload schema for human-readable issues.
Timestamp (in milliseconds) at which the session was created.
Identifier of the parent stream object.
Indicates whether the stream should be recorded.
Status of the recording process of this stream session.
URL for accessing the recording of this stream session.
URL for the stream session recording packaged in an MP4 format.
Identifier used to form the playback URL.
Array of profiles detailing various streaming qualities.
```json Response theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"id": "de7818e7-610a-4057-8f6f-b785dc1e6f88",
"name": "test_session",
"lastSeen": 1587667174725,
"sourceSegments": 1,
"transcodedSegments": 2,
"sourceSegmentsDuration": 1,
"transcodedSegmentsDuration": 2,
"sourceBytes": 1,
"transcodedBytes": 2,
"ingestRate": 1,
"outgoingRate": 2,
"isHealthy": true,
"issues": [
"Buffer underflow",
"Network congestion"
],
"createdAt": 1587667174725,
"parentId": "de7818e7-610a-4057-8f6f-b785dc1e6f88",
"record": "boolean",
"recordingStatus": "waiting",
"recordingUrl": "https://lp-playback.com/hls/29eb9byolvwdbkue/index.m3u8",
"mp4Url": "https://lp-playback.com/hls/29eb9byolvwdqkue/720.mp4",
"playbackId": "eaw4nk06ts2d0mzb",
"profiles": [
{
"name": "720p",
"width": 1280,
"height": 720,
"bitrate": 3000,
"fps": 30
}
]
}
```
# Create a signing key
Source: https://docs.livepeer.org/v1/api-reference/signing-key/create
POST /access-control/signing-key
The publicKey is a representation of the public key, encoded as base 64 and is passed as a string, and the privateKey is displayed only on creation. This is the only moment where the client can save the private key, otherwise it will be lost. Remember to decode your string when signing JWTs.
Up to 10 signing keys can be generated, after that you must delete at least one signing key to create a new one.
# Delete a signing key
Source: https://docs.livepeer.org/v1/api-reference/signing-key/delete
DELETE /access-control/signing-key/{keyId}
# Retrieve a signing key
Source: https://docs.livepeer.org/v1/api-reference/signing-key/get
GET /access-control/signing-key/{keyId}
# Retrieve signing keys
Source: https://docs.livepeer.org/v1/api-reference/signing-key/get-all
GET /access-control/signing-key
# Overview
Source: https://docs.livepeer.org/v1/api-reference/signing-key/overview
The Access control API is used to create, retrieve, update, delete signing keys object from pipeline.
### Signing key Object
Unique identifier for the signing key.
Name of the signing key.
Timestamp (in milliseconds) at which the signing key was created.
Timestamp of the last activity with the signing key.
The public key portion of the signing key.
Indicates whether the signing key is disabled.
The private key portion of the signing key.
```json Response theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"id": "78df0075-b5f3-4683-a618-1086faca35dc",
"name": "My signing key",
"createdAt": 1587667174725,
"lastSeen": 1587667174725,
"publicKey": "LS0tLS1CRUdJTiBQUklWQVRFIBtFWS0tLS0tCk1JR0hBZ0VBTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEJHMHdhd0lCQVFRZ1RDRzhRWDZKdkR0eC95ZDMKdlpkUHJKR25LcjhiWHRsdXNIL2FOYW5XdHEraFJBTkNBQVE0QnZ6ODI2L2lDaXV1U0NiZVkwc3FmOXljYWh0OApDRFYyUFF2bDFVM1FLSVRBcWRpaktLa0FSUFVkcWRrYWZzR21PMzBDeElPaDBLNWJSQW5XQzd4KwotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tCg==",
"disabled": "boolean",
"privateKey": "LS0tLS1CRUdJTiBQUklWQVRFIBtFWS0tLS0tCk1JR0hBZ0VBTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEJHMHdhd0lCQVFRZ1RDRzhRWDZKdkR0eC95ZDMKdlpkUHJKR25LcjhiWHRsdXNIL2FOYW5XdHEraFJBTkNBQVE0QnZ6ODI2L2lDaXV1U0NiZVkwc3FmOXljYWh0OApDRFYyUFF2bDFVM1FLSVRBcWRpaktLa0FSUFVkcWRrYWZzR21PMzBDeElPaDBLNWJSQW5XQzd4KwotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tCg=="
}
```
# Update a signing key
Source: https://docs.livepeer.org/v1/api-reference/signing-key/update
PATCH /access-control/signing-key/{keyId}
# Add a multistream target
Source: https://docs.livepeer.org/v1/api-reference/stream/add-multistream-target
POST /stream/{id}/create-multistream-target
# Create a livestream
Source: https://docs.livepeer.org/v1/api-reference/stream/create
POST /stream
The only parameter you are required to set is the name of your stream,
but we also highly recommend that you define transcoding profiles
parameter that suits your specific broadcasting configuration.
\
\
If you do not define transcoding rendition profiles when creating the
stream, a default set of profiles will be used. These profiles include
240p, 360p, 480p and 720p.
\
\
The playback policy is set to public by default for new streams. It can
also be added upon the creation of a new stream by adding
`"playbackPolicy": {"type": "jwt"}`
# Create a clip
Source: https://docs.livepeer.org/v1/api-reference/stream/create-clip
POST /clip
# Delete a livestream
Source: https://docs.livepeer.org/v1/api-reference/stream/delete
DELETE /stream/{id}
This will also suspend any active stream sessions, so make sure to wait
until the stream has finished. To explicitly interrupt an active
session, consider instead updating the suspended field in the stream
using the PATCH stream API.
# Remove a multistream target
Source: https://docs.livepeer.org/v1/api-reference/stream/delete-multistream-target
DELETE /stream/{id}/multistream/{targetId}
# Retrieve a livestream
Source: https://docs.livepeer.org/v1/api-reference/stream/get
GET /stream/{id}
# Retrieve all livestreams
Source: https://docs.livepeer.org/v1/api-reference/stream/get-all
GET /stream
# Retrieve clips of a livestream
Source: https://docs.livepeer.org/v1/api-reference/stream/get-clip
GET /stream/{id}/clips
# Overview
Source: https://docs.livepeer.org/v1/api-reference/stream/overview
The Livestream API is used to create, retrieve, update, delete stream object from pipeline.
### Stream Object
Unique identifier for the stream.
Name of the stream.
Reference to the creator-id schema.
Timestamp of the last activity on the stream.
Number of source segments.
Number of transcoded segments.
Duration of all the source segments in seconds.
Duration of all the transcoded segments in seconds.
Total bytes of source segments.
Total bytes of transcoded segments.
Rate at which sourceBytes increases (bytes/second).
Rate at which transcodedBytes increases (bytes/second).
Indicates if the stream is currently active.
Reference to the stream-health-payload schema for health status.
Reference to the stream-health-payload schema for human-readable issues.
Name of the token used to create this stream.
Timestamp (in milliseconds) of when the stream object was created.
Identifier for the parent stream object.
Key used to form the RTMP ingest URL.
Identifier used to form the playback URL.
Reference to the playback-policy schema.
Array of profiles detailing various streaming qualities.
Indicates if the stream should be recorded.
Details about multistreaming targets and their configurations.
Indicates if the stream is currently suspended.
```json Response theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"id": "de7818e7-610a-4057-8f6f-b785dc1e6f88",
"name": "test_stream",
"creatorId": "object",
"lastSeen": 1587667174725,
"sourceSegments": 1,
"transcodedSegments": 2,
"sourceSegmentsDuration": 1,
"transcodedSegmentsDuration": 2,
"sourceBytes": 1,
"transcodedBytes": 2,
"ingestRate": 1,
"outgoingRate": 2,
"isActive": "boolean",
"isHealthy": true,
"issues": ["Buffer underflow", "Network congestion"],
"createdByTokenName": "staging key",
"createdAt": 1587667174725,
"parentId": "de7818e7-610a-4057-8f6f-b785dc1e6f88",
"streamKey": "hgebdhhigq",
"playbackId": "eaw4nk06ts2d0mzb",
"playbackPolicy": {
"type": "public",
"webhookId": "3e02c844-d364-4d48-b401-24b2773b5d6c",
"webhookContext": {
"foo": "bar"
}
},
"profiles": [
{
"name": "720p",
"width": 1280,
"height": 720,
"bitrate": 3000,
"fps": 30
}
],
"record": "boolean",
"multistream": {
"targets": [
{
"id": "PUSH123",
"profile": "720p"
}
]
},
"suspended": "boolean"
}
```
# Terminates a livestream
Source: https://docs.livepeer.org/v1/api-reference/stream/terminate
DELETE /stream/{id}/terminate
`DELETE /stream/{id}/terminate` can be used to terminate an ongoing
session on a live stream. Unlike suspending the stream, it allows the
streamer to restart streaming even immediately, but it will force
terminate the current session and stop the recording.
\
\
A 204 No Content status response indicates the stream was successfully
terminated.
# Update a livestream
Source: https://docs.livepeer.org/v1/api-reference/stream/update
PATCH /stream/{id}
# Retrieve a task
Source: https://docs.livepeer.org/v1/api-reference/task/get
GET /task/{taskId}
# Retrieve tasks
Source: https://docs.livepeer.org/v1/api-reference/task/get-all
GET /task
# Overview
Source: https://docs.livepeer.org/v1/api-reference/task/overview
The Tasks API is used to retrieve tasks object from pipeline.
### Task Object
Task ID.
Type of the task, such as upload, import, export, etc.
Timestamp (in milliseconds) at which the task was created.
Timestamp (in milliseconds) at which the task was scheduled for execution.
ID of the input asset for the task.
ID of the output asset for the task.
Parameters of the task, which vary depending on the task type.
Status of the task, including phase, update time, and error message.
Output of the task, specifics depend on the task type.
```json Response theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"id": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"type": "upload",
"createdAt": 1587667174725,
"scheduledAt": 1587667174725,
"inputAssetId": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"outputAssetId": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"params": {
"upload": {
"url": "https://cdn.livepeer.com/ABC123/filename.mp4",
"encryption": {
"encryptedKey": "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JR0hBZ0VBTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEJHMHdhd0lCQVFRZ1RDRzhRWDZKdkR0eC95ZDMKdlpkUHJKR25LcjhiWHRsdXNIL2FOYW5XdHEraFJBTkNBQVE0QnZ6ODI2L2lDaXV1U0NiZVkwc3FmOXljYWh0OApDRFYyUFF2bDFVM1FLSVRBcWRpaktLa0FSUFVkcWRrYWZzR21PMzBDeElPaDBLNWJSQW5XQzd4KwotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tCg=="
},
"recordedSessionId": "78df0075-b5f3-4683-a618-1086faca35dc"
},
"import": {
"url": "https://cdn.livepeer.com/ABC123/filename.mp4",
"encryption": {
"encryptedKey": "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JR0hBZ0VBTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEJHMHdhd0lCQVFRZ1RDRzhRWDZKdkR0eC95ZDMKdlpkUHJKR25LcjhiWHRsdXNIL2FOYW5XdHEraFJBTkNBQVE0QnZ6ODI2L2lDaXV1U0NiZVkwc3FmOXljYWh0OApDRFYyUFF2bDFVM1FLSVRBcWRpaktLa0FSUFVkcWRrYWZzR21PMzBDeElPaDBLNWJSQW5XQzd4KwotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tCg=="
},
"recordedSessionId": "78df0075-b5f3-4683-a618-1086faca35dc"
},
"exportData": {
"content": "object",
"ipfs": {
"nftMetadataTemplate": "file",
"nftMetadata": "object",
"pinata": {
"jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MDI4NjQwNzcsImlhdCI6MTYwMjI3NjA3NywiaXNzIjoiYXBpLmlzc3VlciIsInN1YiI6I"
}
},
"type": "string",
"id": "string"
},
"transcode": {
"profile": {
"width": 1280,
"name": "720p",
"height": 720,
"bitrate": 4000,
"fps": 30,
"fpsDen": 1,
"gop": "60",
"profile": "H264High",
"encoder": "h264"
}
},
"transcode-file": {
"input": {
"url": "https://cdn.livepeer.com/ABC123/filename.mp4"
},
"storage": {
"url": "s3+https://accessKeyId:secretAccessKey@s3Endpoint/bucket"
},
"outputs": {
"hls": {
"path": "/samplevideo/hls"
},
"mp4": {
"path": "/samplevideo/mp4"
}
},
"profiles": [
{
"width": 1280,
"name": "720p",
"height": 720,
"bitrate": 4000,
"fps": 30,
"fpsDen": 1,
"gop": "60",
"profile": "H264High",
"encoder": "h264"
}
],
"targetSegmentSizeSecs": "number",
"c2pa": "boolean"
}
},
"clip": {
"url": "string",
"clipStrategy": {
"startTime": "number",
"endTime": "number",
"playbackId": "string"
},
"catalystPipelineStrategy": "catalyst",
"sessionId": "string",
"inputId": "string"
},
"status": {
"phase": "pending",
"updatedAt": 1587667174725,
"progress": "number",
"errorMessage": "string",
"retries": "number",
"step": "string"
},
"output": {
"upload": {
"videoFilePath": "string",
"metadataFilePath": "string",
"assetSpec": {
"id": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"type": "video",
"playbackId": "eaw4nk06ts2d0mzb",
"staticMp4": "boolean",
"c2pa": "boolean",
"playbackUrl": "https://livepeercdn.com/asset/ea03f37e-f861-4cdd-b495-0e60b6d753ad/index.m3u8",
"downloadUrl": "https://livepeercdn.com/asset/eaw4nk06ts2d0mzb/video",
"playbackPolicy": {
"type": "public",
"webhookId": "3e02c844-d364-4d48-b401-24b2773b5d6c",
"webhookContext": {
"foo": "bar"
}
},
"source": {
"type": "url",
"url": "https://example.com/video.mp4",
"gatewayUrl": "https://example.com/video.mp4"
},
"creatorId": "object",
"storage": {
"ipfs": {
"spec": {
"nftMetadataTemplate": "file",
"nftMetadata": {
"name": "My NFT",
"description": "My NFT description"
}
}
}
},
"status": {
"phase": "ready",
"updatedAt": 1587667174725,
"progress": 100
},
"name": "filename.mp4",
"createdAt": 1587667174725,
"size": 84934509,
"hash": [
{
"hash": "9b560b28b85378a5004117539196ab24e21bbd75b0e9eb1a8bc7c5fd80dc5b57",
"algorithm": "sha256"
}
],
"videoSpec": {
"format": "mp4",
"duration": 23.8328,
"bitrate": 1000000,
"tracks": [
{
"type": "video",
"codec": "h264",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"width": 1920,
"height": 1080,
"pixelFormat": "yuv420p",
"fps": 30
},
{
"type": "audio",
"codec": "aac",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"channels": 2,
"sampleRate": 44100,
"bitDepth": 16
}
]
}
}
},
"import": {
"videoFilePath": "string",
"metadataFilePath": "string",
"assetSpec": {
"id": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"type": "video",
"playbackId": "eaw4nk06ts2d0mzb",
"staticMp4": "boolean",
"c2pa": "boolean",
"playbackUrl": "https://livepeercdn.com/asset/ea03f37e-f861-4cdd-b495-0e60b6d753ad/index.m3u8",
"downloadUrl": "https://livepeercdn.com/asset/eaw4nk06ts2d0mzb/video",
"playbackPolicy": {
"type": "public",
"webhookId": "3e02c844-d364-4d48-b401-24b2773b5d6c",
"webhookContext": {
"foo": "bar"
}
},
"source": {
"type": "url",
"url": "https://example.com/video.mp4",
"gatewayUrl": "https://example.com/video.mp4"
},
"creatorId": "object",
"storage": {
"ipfs": {
"spec": {
"nftMetadataTemplate": "file",
"nftMetadata": {
"name": "My NFT",
"description": "My NFT description"
}
}
}
},
"status": {
"phase": "ready",
"updatedAt": 1587667174725,
"progress": 100
},
"name": "filename.mp4",
"createdAt": 1587667174725,
"size": 84934509,
"hash": [
{
"hash": "9b560b28b85378a5004117539196ab24e21bbd75b0e9eb1a8bc7c5fd80dc5b57",
"algorithm": "sha256"
}
],
"videoSpec": {
"format": "mp4",
"duration": 23.8328,
"bitrate": 1000000,
"tracks": [
{
"type": "video",
"codec": "h264",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"width": 1920,
"height": 1080,
"pixelFormat": "yuv420p",
"fps": 30
},
{
"type": "audio",
"codec": "aac",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"channels": 2,
"sampleRate": 44100,
"bitDepth": 16
}
]
}
}
},
"export": {
"ipfs": {
"videoFileCid": "string",
"videoFileUrl": "string",
"videoFileGatewayUrl": "string",
"nftMetadataCid": "string",
"nftMetadataUrl": "string",
"nftMetadataGatewayUrl": "string"
}
},
"exportData": {
"ipfs": {
"cid": "string"
}
},
"transcode": {
"asset": {
"videoFilePath": "string",
"metadataFilePath": "string",
"assetSpec": {
"id": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"type": "video",
"playbackId": "eaw4nk06ts2d0mzb",
"staticMp4": "boolean",
"c2pa": "boolean",
"playbackUrl": "https://livepeercdn.com/asset/ea03f37e-f861-4cdd-b495-0e60b6d753ad/index.m3u8",
"downloadUrl": "https://livepeercdn.com/asset/eaw4nk06ts2d0mzb/video",
"playbackPolicy": {
"type": "public",
"webhookId": "3e02c844-d364-4d48-b401-24b2773b5d6c",
"webhookContext": {
"foo": "bar"
}
},
"source": {
"type": "url",
"url": "https://example.com/video.mp4",
"gatewayUrl": "https://example.com/video.mp4"
},
"creatorId": "object",
"storage": {
"ipfs": {
"spec": {
"nftMetadataTemplate": "file",
"nftMetadata": {
"name": "My NFT",
"description": "My NFT description"
}
}
}
},
"status": {
"phase": "ready",
"updatedAt": 1587667174725,
"progress": 100
},
"name": "filename.mp4",
"createdAt": 1587667174725,
"size": 84934509,
"hash": [
{
"hash": "9b560b28b85378a5004117539196ab24e21bbd75b0e9eb1a8bc7c5fd80dc5b57",
"algorithm": "sha256"
}
],
"videoSpec": {
"format": "mp4",
"duration": 23.8328,
"bitrate": 1000000,
"tracks": [
{
"type": "video",
"codec": "h264",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"width": 1920,
"height": 1080,
"pixelFormat": "yuv420p",
"fps": 30
},
{
"type": "audio",
"codec": "aac",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"channels": 2,
"sampleRate": 44100,
"bitDepth": 16
}
]
}
}
}
}
}
}
```
# Transcode a video
Source: https://docs.livepeer.org/v1/api-reference/transcode/create
POST /transcode
`POST /transcode` transcodes a video file and uploads the results to the
specified storage service.
\
\
Transcoding is asynchronous so you will need to check the status of the
task in order to determine when transcoding is complete. The `id` field
in the response is the unique ID for the transcoding `Task`. The task
status can be queried using the [GET tasks
endpoint](https://docs.livepeer.org/reference/api/get-tasks):
\
\
When `status.phase` is `completed`, transcoding will be complete and
the results will be stored in the storage service and the specified
output location.
\
\
The results will be available under `params.outputs.hls.path` and
`params.outputs.mp4.path` in the specified storage service.
## Input
\
This endpoint currently supports the following inputs:
- HTTP
- S3 API Compatible Service
\
\
**HTTP**
\
A public HTTP URL can be used to read a video file.
```json
{
"url": "https://www.example.com/video.mp4"
}
```
| Name | Type | Description |
| ---- | ------ | ------------------------------------ |
| url | string | A public HTTP URL for the video file. |
Note: For IPFS HTTP gateway URLs, the API currently only supports “path
style” URLs and does not support “subdomain style” URLs. The API will
support both styles of URLs in a future update.
\
\
**S3 API Compatible Service**
\
\
S3 credentials can be used to authenticate with a S3 API compatible
service to read a video file.
```json
{
"type": "s3",
"endpoint": "https://gateway.storjshare.io",
"credentials": {
"accessKeyId": "$ACCESS_KEY_ID",
"secretAccessKey": "$SECRET_ACCESS_KEY"
},
"bucket": "inbucket",
"path": "/video/source.mp4"
}
```
## Storage
\
This endpoint currently supports the following storage services:
- S3 API Compatible Service
- Web3 Storage
\
\
**S3 API Compatible Service**
```json
{
"type": "s3",
"endpoint": "https://gateway.storjshare.io",
"credentials": {
"accessKeyId": "$ACCESS_KEY_ID",
"secretAccessKey": "$SECRET_ACCESS_KEY"
},
"bucket": "mybucket"
}
```
**Web3 Storage**
```json
{
"type": "web3.storage",
"credentials": {
"proof": "$UCAN_DELEGATION_PROOF",
}
}
```
## Outputs
\
This endpoint currently supports the following output types:
- HLS
- MP4
**HLS**
```json
{
"hls": {
"path": "/samplevideo/hls"
}
}
```
**MP4**
```json
{
"mp4": {
"path": "/samplevideo/mp4"
}
}
```
# Overview
Source: https://docs.livepeer.org/v1/api-reference/transcode/overview
The Transcode API is used to create transcode object from pipeline.
### Transcode Object
Task ID.
Type of the task, such as upload, import, export, etc.
Timestamp (in milliseconds) at which the task was created.
Timestamp (in milliseconds) at which the task was scheduled for execution.
ID of the input asset for the task.
ID of the output asset for the task.
Parameters of the task, which vary depending on the task type.
Status of the task, including phase, update time, and error message.
Output of the task, specifics depend on the task type.
```json Response theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"id": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"type": "upload",
"createdAt": 1587667174725,
"scheduledAt": 1587667174725,
"inputAssetId": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"outputAssetId": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"params": {
"upload": {
"url": "https://cdn.livepeer.com/ABC123/filename.mp4",
"encryption": {
"encryptedKey": "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JR0hBZ0VBTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEJHMHdhd0lCQVFRZ1RDRzhRWDZKdkR0eC95ZDMKdlpkUHJKR25LcjhiWHRsdXNIL2FOYW5XdHEraFJBTkNBQVE0QnZ6ODI2L2lDaXV1U0NiZVkwc3FmOXljYWh0OApDRFYyUFF2bDFVM1FLSVRBcWRpaktLa0FSUFVkcWRrYWZzR21PMzBDeElPaDBLNWJSQW5XQzd4KwotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tCg=="
},
"recordedSessionId": "78df0075-b5f3-4683-a618-1086faca35dc"
},
"import": {
"url": "https://cdn.livepeer.com/ABC123/filename.mp4",
"encryption": {
"encryptedKey": "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JR0hBZ0VBTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEJHMHdhd0lCQVFRZ1RDRzhRWDZKdkR0eC95ZDMKdlpkUHJKR25LcjhiWHRsdXNIL2FOYW5XdHEraFJBTkNBQVE0QnZ6ODI2L2lDaXV1U0NiZVkwc3FmOXljYWh0OApDRFYyUFF2bDFVM1FLSVRBcWRpaktLa0FSUFVkcWRrYWZzR21PMzBDeElPaDBLNWJSQW5XQzd4KwotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tCg=="
},
"recordedSessionId": "78df0075-b5f3-4683-a618-1086faca35dc"
},
"exportData": {
"content": "object",
"ipfs": {
"nftMetadataTemplate": "file",
"nftMetadata": "object",
"pinata": {
"jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MDI4NjQwNzcsImlhdCI6MTYwMjI3NjA3NywiaXNzIjoiYXBpLmlzc3VlciIsInN1YiI6I"
}
},
"type": "string",
"id": "string"
},
"transcode": {
"profile": {
"width": 1280,
"name": "720p",
"height": 720,
"bitrate": 4000,
"fps": 30,
"fpsDen": 1,
"gop": "60",
"profile": "H264High",
"encoder": "h264"
}
},
"transcode-file": {
"input": {
"url": "https://cdn.livepeer.com/ABC123/filename.mp4"
},
"storage": {
"url": "s3+https://accessKeyId:secretAccessKey@s3Endpoint/bucket"
},
"outputs": {
"hls": {
"path": "/samplevideo/hls"
},
"mp4": {
"path": "/samplevideo/mp4"
}
},
"profiles": [
{
"width": 1280,
"name": "720p",
"height": 720,
"bitrate": 4000,
"fps": 30,
"fpsDen": 1,
"gop": "60",
"profile": "H264High",
"encoder": "h264"
}
],
"targetSegmentSizeSecs": "number",
"c2pa": "boolean"
}
},
"clip": {
"url": "string",
"clipStrategy": {
"startTime": "number",
"endTime": "number",
"playbackId": "string"
},
"catalystPipelineStrategy": "catalyst",
"sessionId": "string",
"inputId": "string"
},
"status": {
"phase": "pending",
"updatedAt": 1587667174725,
"progress": "number",
"errorMessage": "string",
"retries": "number",
"step": "string"
},
"output": {
"upload": {
"videoFilePath": "string",
"metadataFilePath": "string",
"assetSpec": {
"id": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"type": "video",
"playbackId": "eaw4nk06ts2d0mzb",
"staticMp4": "boolean",
"c2pa": "boolean",
"playbackUrl": "https://livepeercdn.com/asset/ea03f37e-f861-4cdd-b495-0e60b6d753ad/index.m3u8",
"downloadUrl": "https://livepeercdn.com/asset/eaw4nk06ts2d0mzb/video",
"playbackPolicy": {
"type": "public",
"webhookId": "3e02c844-d364-4d48-b401-24b2773b5d6c",
"webhookContext": {
"foo": "bar"
}
},
"source": {
"type": "url",
"url": "https://example.com/video.mp4",
"gatewayUrl": "https://example.com/video.mp4"
},
"creatorId": "object",
"storage": {
"ipfs": {
"spec": {
"nftMetadataTemplate": "file",
"nftMetadata": {
"name": "My NFT",
"description": "My NFT description"
}
}
}
},
"status": {
"phase": "ready",
"updatedAt": 1587667174725,
"progress": 100
},
"name": "filename.mp4",
"createdAt": 1587667174725,
"size": 84934509,
"hash": [
{
"hash": "9b560b28b85378a5004117539196ab24e21bbd75b0e9eb1a8bc7c5fd80dc5b57",
"algorithm": "sha256"
}
],
"videoSpec": {
"format": "mp4",
"duration": 23.8328,
"bitrate": 1000000,
"tracks": [
{
"type": "video",
"codec": "h264",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"width": 1920,
"height": 1080,
"pixelFormat": "yuv420p",
"fps": 30
},
{
"type": "audio",
"codec": "aac",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"channels": 2,
"sampleRate": 44100,
"bitDepth": 16
}
]
}
}
},
"import": {
"videoFilePath": "string",
"metadataFilePath": "string",
"assetSpec": {
"id": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"type": "video",
"playbackId": "eaw4nk06ts2d0mzb",
"staticMp4": "boolean",
"c2pa": "boolean",
"playbackUrl": "https://livepeercdn.com/asset/ea03f37e-f861-4cdd-b495-0e60b6d753ad/index.m3u8",
"downloadUrl": "https://livepeercdn.com/asset/eaw4nk06ts2d0mzb/video",
"playbackPolicy": {
"type": "public",
"webhookId": "3e02c844-d364-4d48-b401-24b2773b5d6c",
"webhookContext": {
"foo": "bar"
}
},
"source": {
"type": "url",
"url": "https://example.com/video.mp4",
"gatewayUrl": "https://example.com/video.mp4"
},
"creatorId": "object",
"storage": {
"ipfs": {
"spec": {
"nftMetadataTemplate": "file",
"nftMetadata": {
"name": "My NFT",
"description": "My NFT description"
}
}
}
},
"status": {
"phase": "ready",
"updatedAt": 1587667174725,
"progress": 100
},
"name": "filename.mp4",
"createdAt": 1587667174725,
"size": 84934509,
"hash": [
{
"hash": "9b560b28b85378a5004117539196ab24e21bbd75b0e9eb1a8bc7c5fd80dc5b57",
"algorithm": "sha256"
}
],
"videoSpec": {
"format": "mp4",
"duration": 23.8328,
"bitrate": 1000000,
"tracks": [
{
"type": "video",
"codec": "h264",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"width": 1920,
"height": 1080,
"pixelFormat": "yuv420p",
"fps": 30
},
{
"type": "audio",
"codec": "aac",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"channels": 2,
"sampleRate": 44100,
"bitDepth": 16
}
]
}
}
},
"export": {
"ipfs": {
"videoFileCid": "string",
"videoFileUrl": "string",
"videoFileGatewayUrl": "string",
"nftMetadataCid": "string",
"nftMetadataUrl": "string",
"nftMetadataGatewayUrl": "string"
}
},
"exportData": {
"ipfs": {
"cid": "string"
}
},
"transcode": {
"asset": {
"videoFilePath": "string",
"metadataFilePath": "string",
"assetSpec": {
"id": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"type": "video",
"playbackId": "eaw4nk06ts2d0mzb",
"staticMp4": "boolean",
"c2pa": "boolean",
"playbackUrl": "https://livepeercdn.com/asset/ea03f37e-f861-4cdd-b495-0e60b6d753ad/index.m3u8",
"downloadUrl": "https://livepeercdn.com/asset/eaw4nk06ts2d0mzb/video",
"playbackPolicy": {
"type": "public",
"webhookId": "3e02c844-d364-4d48-b401-24b2773b5d6c",
"webhookContext": {
"foo": "bar"
}
},
"source": {
"type": "url",
"url": "https://example.com/video.mp4",
"gatewayUrl": "https://example.com/video.mp4"
},
"creatorId": "object",
"storage": {
"ipfs": {
"spec": {
"nftMetadataTemplate": "file",
"nftMetadata": {
"name": "My NFT",
"description": "My NFT description"
}
}
}
},
"status": {
"phase": "ready",
"updatedAt": 1587667174725,
"progress": 100
},
"name": "filename.mp4",
"createdAt": 1587667174725,
"size": 84934509,
"hash": [
{
"hash": "9b560b28b85378a5004117539196ab24e21bbd75b0e9eb1a8bc7c5fd80dc5b57",
"algorithm": "sha256"
}
],
"videoSpec": {
"format": "mp4",
"duration": 23.8328,
"bitrate": 1000000,
"tracks": [
{
"type": "video",
"codec": "h264",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"width": 1920,
"height": 1080,
"pixelFormat": "yuv420p",
"fps": 30
},
{
"type": "audio",
"codec": "aac",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"channels": 2,
"sampleRate": 44100,
"bitDepth": 16
}
]
}
}
}
}
}
}
```
# Query creator viewership metrics
Source: https://docs.livepeer.org/v1/api-reference/viewership/get-creators-metrics
GET /data/views/query/creator
Requires a proof of ownership to be sent in the request, which for now is just the assetId or streamId parameters (1 of those must be in the query-string).
# Query public total views metrics
Source: https://docs.livepeer.org/v1/api-reference/viewership/get-public-total-views
GET /data/views/query/total/{playbackId}
Allows querying for the public metrics for viewership about a video.
This can be called from the frontend with a CORS key, or even
unauthenticated.
# Query realtime viewership
Source: https://docs.livepeer.org/v1/api-reference/viewership/get-realtime-viewership
GET /data/views/now
Requires a private (non-CORS) API key to be used.
# Query usage metrics
Source: https://docs.livepeer.org/v1/api-reference/viewership/get-usage-metrics
GET /data/usage/query
# Query viewership metrics
Source: https://docs.livepeer.org/v1/api-reference/viewership/get-viewership-metrics
GET /data/views/query
Requires a private (non-CORS) API key to be used.
# Create a webhook
Source: https://docs.livepeer.org/v1/api-reference/webhook/create
POST /webhook
To create a new webhook, you need to make an API call with the events you want to listen for and the URL that will be called when those events occur.
# Delete a webhook
Source: https://docs.livepeer.org/v1/api-reference/webhook/delete
DELETE /webhook/{id}
# Retrieve a webhook
Source: https://docs.livepeer.org/v1/api-reference/webhook/get
GET /webhook/{id}
# Retrieve all webhooks
Source: https://docs.livepeer.org/v1/api-reference/webhook/get-all
GET /webhook
# Overview
Source: https://docs.livepeer.org/v1/api-reference/webhook/overview
The Webhooks API is used to create, retrieve, update, delete webhooks object from pipeline.
### Webhook Object
Unique identifier for the webhook.
Name of the webhook.
Timestamp (in milliseconds) at which the webhook object was created.
List of events that the webhook subscribes to. Possible events include
stream.started, stream.detection, recording.ready, etc.
URL of the webhook endpoint.
Shared secret used to sign the webhook payload.
StreamId of the stream to which the webhook is applied.
Status of the webhook, including last failure and last triggered timestamp.
Details about the last failure of the webhook, including timestamp, error
message, response, and status code.
Timestamp (in milliseconds) at which the webhook was last triggered.
```json Response theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"id": "de7818e7-610a-4057-8f6f-b785dc1e6f88",
"name": "My webhook",
"createdAt": 1587667174725,
"events": [
"stream.started",
"recording.ready"
],
"url": "https://webhook.example.com",
"sharedSecret": "mySharedSecret",
"streamId": "de7818e7-610a-4057-8f6f-b785dc1e6f88",
"status": {
"lastFailure": {
"timestamp": 1587667174725,
"error": "Error message",
"response": "Response body",
"statusCode": 500
},
"lastTriggeredAt": 1587667174725
}
}
```
# Update a webhook
Source: https://docs.livepeer.org/v1/api-reference/webhook/update
PUT /webhook/{id}
# Bridge LPT to Arbitrum
Source: https://docs.livepeer.org/v1/delegators/guides/bridge-lpt-to-arbitrum
Contract addresses in this guide may be outdated. For current verified addresses, see:
**[Livepeer Contract Addresses](/v2/about/resources/livepeer-contract-addresses)**
This guide will walk tokenholders through the process of moving LPT from the
Ethereum mainnet to Arbitrum and vice versa.
**This only applies if you have not delegated your LPT to an orchestrator on
L1**
Please note that you will need some ETH in your wallet to complete this guide.
If you are using testnet, you will need Rinkeby ETH.
1. Make sure your wallet (i.e. Metamask) is connected to the Ethereum mainnet
(Rinkeby if using testnet) and then navigate to the
[Arbitrum Bridge](https://bridge.arbitrum.io/)
2. Click "Token", and enter the L1 LPT contract address
0x58b6a8a3302369daec383334672404ee733ab239. If you are using testnet, use the
`LivepeerToken` address for Rinkeby.

4. Press "enter" on your keyboard. It will take 5-10 seconds for LPT to appear.

6. Select LPT from the dropdown. Once you've done this, you should see your L1
balance.
7. Click `Deposit` to move your L1 LPT to L2. This will initiate an Approval
transaction. The first of 2 transactions required to bridge LPT to Arbitrum.
8. After the Approval transaction status changes from pending to success (about
10 mins) LPT can now be Deposited.

10. Click 'Deposit' and confirm the transaction in your wallet to complete the
bridging of LPT from L1 to L2

### Bridging from L2 to L1
The same general instructions apply with three differences:
* You should start with your wallet connected to Arbitrum (Arbitrum Rinkeby if
using testnet)
* You will need to manually approve the amount that you are bridging using the
[Arbiscan UI](https://arbiscan.io/address/0x289ba1701C2F088cf0faf8B3705246331cB8A839#writeContract).
To do so, connect your wallet, scroll to the Approve function, enter the
L2LPTGateway address
[0x6D2457a4ad276000A615295f7A80F79E48CcD318](https://arbiscan.io/address/0x6D2457a4ad276000A615295f7A80F79E48CcD318)
and the amount you'll be transferring and click "Write". Note that the amount
is in "Wei", so use a [Unit Converter](https://etherscan.io/unitconverter)
(e.g. if you want to bridge 10 LPT, you need to enter 10000000000000000000).
* We are looking into options to remove this step. If it seems complex, we
recommend swapping to ETH via
[Uniswap](https://app.uniswap.org/#/swap?chain=arbitrum) and then
transferring the ETH from L2 to L1 instead.
* Next, click on the arrow below the amount input. The button will switch from
"Deposit" to "Withdraw"
* Click on "Token" -> "Manage token lists" -> enable "Arbed CMC List" and click
on "Back to Select Token". You should now be able to choose LPT in the list.
* After you've sent the withdraw tx, you need to wait \~1 week until you can
claim your LPT on L1. You'll see the countdown below. Once the confirmation
period is over, you can connect to the Ethereum mainnet and click "Claim" to
withdraw your LPT on L1.
### Bridging Failures
The Arbitrum rollup can fail to bridge tokens correctly if the gas prices are
fluctuating by too much, or if the transaction runs out of gas. The former can
be caused by gas prices changing from when the original "bridge" transaction was
submitted, to when it was sequenced and submitted on L2. In this case, tokens
will not reach your L2 wallet after an hour. Arbitrum
[provides a page](https://retryable-tx-panel.arbitrum.io/) to check on the
status of your L1 deposit transaction:
In the event of a failure of LPT to bridge due to gas spikes, you should see a
message similar to the following:

You should then be able to connect your wallet and resubmit the bridge
transaction. This will retry the previous transaction. Make sure to do this in a
timely manner, since the
[L2 retry buffer is limited](https://docs.arbitrum.io/arbos/l1-to-l2-messaging).
# Migrate stake to Arbitrum
Source: https://docs.livepeer.org/v1/delegators/guides/migrate-stake-to-arbitrum
This guide is applicable to delegators who delegated their LPT to an
orchestrator on the Ethereum mainnet prior to February 14th, 2022. Once you have
successfully completed the migration, this guide is no longer applicable and you
will use Arbitrum in lieu of Ethereum Mainnet for all protocol actions.
Claiming your delegated stake and earned ETH on Arbitrum is highly encouraged
to ensure that (1) you continue earning inflationary rewards and fees and (2)
you will be able to withdraw any currently delegated stake and earned ETH
fees. As of February 14th, 2022, withdrawals on the Ethereum Mainnet will be
disabled and all inflationary rewards and ETH fees will be disbursed on
Arbitrum.
## Prerequisites for all chains
* Before using this guide, you will need make sure your Arbitrum wallet has
enough arbETH to cover gas for the `claim` transaction. If you do not have
arbETH in your wallet, you will need to add some using one of the bridges or
on-ramps listed [here](https://portal.arbitrum.one/).
* The migration must be completed using the Livepeer explorer
* **If you use a contract account rather than an EOA**: You will need to
interact directly with the Migrator contract methods. Please use the guide
[here](/orchestrators/guides/migrate-from-contract-wallet). *If you don’t know
what this means, it probably doesn’t apply to you.*
## Claiming via the Explorer
1. Navigate to the [Livepeer Explorer](http://explorer.livepeer.org). If you
have not connected the wallet that you used to delegate your LPT, connect it
using the prompt in the upper left hand corner. If you haven't switched your
network to Arbitrum, you'll be prompted to do so.
There are a few options for connecting a wallet to Arbitrum. The wallet you choose should be the same one with which you originally delegated your LPT on the Ethereum mainnet. It should also contain a small amount of arbETH to pay for the `claim` on Arbitrum.
2. **Claim your stake, rewards, and fees**
Click `Claim` to initiate a transaction that will claim your stake, rewards
and fees.
If your orchestrator has not migrated and has not conveyed plans to migrate,
you will see a prompt to choose a new orchestrator.
3. **View your profile**
Once the `claim` transaction has been confirmed (this usually takes a few
seconds on Arbitrum), you see a link to your profile. Here, you'll be able
to see your newly claimed balances.
You will see an [Arbiscan](https://arbiscan.io/) link to the transaction id
in case you want to look at the submitted transaction.
# Yield Calculation on Explorer
Source: https://docs.livepeer.org/v1/delegators/guides/yield-calculation
The Livepeer protocol is built around workers who perform video transcoding. An
orchestrator is the name for the protocol participant who performs the
transcoding on the network - see our
[visual introduction](https://livepeer.org/primer). If another user is looking
to participate in the Livepeer network, they can contribute by staking (bonding)
LPT with an orchestrator and earning passive rewards for improving the economic
security of the network.
The explorer includes a calculation of return on investment for LPT stake to an
orchestrator. This document explains how that calculation is performed and how
it can be inaccurate/manipulated by orchestrators.
## Calculation
### Orchestrator Parameters
When an orchestrator registers their Ethereum address on the network, they are
required to choose their parameters for how they share revenue with stakers.
These percentages are defined as fee share, $s_{fees}$, and reward share,
$s_{rewards}$. These can be changed at any time.
#### Orchestrator Metrics
An orchestrator also has performance metrics which are used. They must request
inflationary rewards each round on behalf of their delegators. The ratio of
successful reward calls, $r_{rewards}$, is defined as:
$$
r_{rewards} = rewardCalls / n
$$
Where $n$ is the number of rounds (up to 90 rounds depending on the time the
orchestrator has been active) and $rewardCalls$ is the count of successful
reward calls.
An orchestrator also has $l_{orch}$ which is the active stake they currently
have on the network.
Lastly, orchestrators earn fees for work performed, and the average is taken
over the course of 90 days as $v_{daily}$, which is denominated in ETH.
### Protocol Parameters
There are also protocol-level parameters which factor into how inflationary
rewards are distributed and change over time.
The inflation rate increases/decreases when the target participation rate is not
met. For simplicity, we assume in the yield calculation that the current
inflation rate, $r_{inf}$, will stay constant.
The current token supply is defined as $l_{total}$ and the current active stake
(LPT which has been delegated) is $l_{active}$.
### Equation
#### Transcoding Fees
The transcoding fees are simpler and calculated using:
$$
yield_{ETH} = (v_{daily} * 365) * s_{fees} * \frac{p}{p + l_{orch}}
$$
The first part calculates the estimated fee volume in ETH for the orchestrator
for the year.
The second includes the fee share which the orchestrator has set.
The last part takes the ratio of the delegator's stake to the total orchestrator
stake.
#### Inflationary Rewards
The combined equation also includes input from the user, which is the amount of
LPT they want to stake. This principle is defined as $p$.
$$
yield_{LPT} = \frac{l_{total} * (1 + r_{inf})^{417} - l_{total}}{l_{active}} * ((p + l_{orch}) * r_{rewards}) * \left( s_{rewards} * \frac{p}{p + l_{orch}} \right)
$$
The first part of the equation is the estimated total rewards which will be
given out to all orchestrators over the next year, based on current inflation,
active stake, and Ethereum block times (417 rounds in one year).
The second part then calculates the amount of rewards which the orchestrator
would receive over the year.
The last part calculates the ratio that the delegator will receive, based on
their principal, $p$, that they stake on the orchestrator, as well as the
orchestrators reward share, $s_{rewards}$.
#### Combined Equation
The total yield can then be calculated as (with $price_{LPT/ETH}$ pulled from
Uniswap):
$$
yield_{total} = yield_{LPT} + yield_{ETH} * (price_{LPT/ETH})
$$
The implementation of this equation can be found in the
[Explorer Github repository](https://github.com/livepeer/explorer/blob/main/lib/roi.ts).
## Inaccuracies/Pitfalls
### Variable Orchestrator Parameters
The parameters which an orchestrator sets for their fee cut and reward cut are
highly subject to change. A malicious orchestrator could set their fee cut to be
very low, and then manipulate that number once they have a large number of
delegators. A delegator should look for orchestrators who have not changed their
fee/reward cuts often, and continue to monitor their orchestrator and switch if
they change their rewards to less favorable percentages.
### Inflation Rate Change
As mentioned previously, the inflation rate is subject to change depending on
the participation rate (the amount of LPT staked in the network). The yield
calculation assumes that the participation rate will stay constant, but this
could prove to be inaccurate.
# Introduction
Source: https://docs.livepeer.org/v1/delegators/introduction
Explore APIs, guides, and examples
If you're looking for documentation on Livepeer's hosted realtime
StreamDiffusion AI platform "Daydream", please navigate
[here](https://pipelines.livepeer.org/docs)
Learn how to add live and on-demand video experience to your app using Livepeer
Studio. Effortlessly manage livestreams, video uploads, API keys, network usage,
billing, and more.
Get started with Livepeer Studio in less than 5 minutes.
Learn how to add live or on-demand video experiences to your app.
Explore the Livepeer Studio API
Get up and running with SDKs and pre-built UI components
## Explore the Livepeer Studio SDKs
Explore developer SDKs, pre-built UI components, and tools for interacting with
the Livepeer Studio API.
### Server-side SDKs
### React Components
Fully customizable video player component for seamless playback
Full-featured broadcast component with controls, settings, and device
selection
[View all developer tools](/sdks/introduction)
# CLI
Source: https://docs.livepeer.org/v1/delegators/livepeer-studio-cli
Generate a new Livepeer app.
The Livepeer Studio CLI is a command line tool that helps you generate a new
Livepeer app in just a few seconds.
## Getting Started
First, create a Livepeer API key
[here](https://livepeer.studio/dashboard/developers/api-keys). Next, use the CLI
to generate a new project.
```sh theme={"theme":{"light":"github-light","dark":"dark-plus"}}
npx @livepeer/create
```
When prompted, enter your Livepeer **API key** and **Stream ID**.
Once the app has been created, `cd` into the new directory and run the start
command:
```sh theme={"theme":{"light":"github-light","dark":"dark-plus"}}
npm run dev
```
# Quickstart
Source: https://docs.livepeer.org/v1/delegators/quick-start
Learn how to create an API key and start adding live and on-demand video to your app or website!
First, go to [Livepeer Studio](https://livepeer.studio), if you haven't already,
and create an account. Once you've created an account, you'll be able to create
an API key by clicking on the "Create API Key" button on Developers page.
We do not recommend using ["CORS-enabled" API
keys](/api-reference/overview/authentication) - they will be deprecated in an
upcoming release. We recommend making requests from your backend to the
Livepeer Studio API.
You can now use this API key in Livepeer SDKs and APIs in order to authenticate
your requests and start building.
We recommend creating separate accounts for your development and production
environments. This will allow you to easily isolate your environments. We will
be shipping a solution for multi-environment management soon.
In this exampe, we will use Javascript anld React to upload a video. Make sure
to set up a React app first.
## Install the JS SDK and Livepeer React
We install both the NodeJS SDK (which works in all JS environments with `fetch`)
and the Livepeer React library, which provides composable React primitives for
building video apps.
```
npm install livepeer @livepeer/react
```
## Set up the SDK
Add an API key to the environment variables, and construct a new Livepeer SDK
client.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import Livepeer from "livepeer";
const livepeer = new Livepeer({
apiKey: process.env.YOUR_PRIVATE_API_KEY,
});
```
## Retrieve playback info
We can now use the SDK on the backend to fetch the playback info for our asset.
This asset was uploaded using the dashboard, but this can also be an asset
created from an application.
```ts theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { getSrc } from "@livepeer/react/external";
const playbackId = "f5eese9wwl88k4g8";
export const getPlaybackSource = () => {
const playbackInfo = await livepeer.playback.get(playbackId);
const src = getSrc(playbackInfo.playbackInfo);
return src;
};
```
## Play the asset
We can now use Player component from the SDK to play a video. In the below
example, we style the elements with Tailwind, but you can use any styling
solution:
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { PauseIcon, PlayIcon } from "@livepeer/react/assets";
import { getSrc } from "@livepeer/react/external";
import * as Player from "@livepeer/react/player";
import { vodSource } from "./source";
export const DemoPlayer = ({ src }: { src: Src[] | null }) => {
return (
);
};
```
## Start building
Check out the [SDKs](/sdks/introduction) and
[API Reference](/api-reference/overview/introduction) pages to learn more about
how to use the SDKs and API to build your application.
You can also refer to the [Guides](/developers/guides/overview) section for more
in-depth tutorials on how to use the SDKs and API to build specific
applications.
Don't know where to start? Check out these four tutorials:
* [Learn how to create a livestream](/developers/guides/create-livestream)
* [Learn how to listen to asset events](/developers/guides/listen-to-asset-events)
# API Support Matrix
Source: https://docs.livepeer.org/v1/references/api-support-matrix
## On Demand
### Inputs
Currently, only file sizes up to 30GB are supported.
#### Video
| Container | Video codecs supported with container |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| MPEG-4 (.mp4) | Uncompressed, AVC Intra 50/100, DivX/Xvid, H.261, H.262, H.263, AVC (H.264), HEVC (H.265), JPEG 2000, MPEG-2, MPEG-4 part 2, VC-1 |
| QuickTime (.mov). | Uncompressed, AVC Intra 50/100, DivX/Xvid, DV/DVCPRO, H.261, H.262, H.263, AVC (H.264), HEVC (H.265), JPEG 2000 (J2K), MJPEG, MPEG-2, MPEG-4 part 2, QuickTime Animation (RLE) |
| Audio Video Interleave (.avi) | Uncompressed, Canopus HQ, DivX/Xvid, DV/DVCPRO, MJPEG |
| Adobe Flash (.flv) | AVC (H.264), Flash 9 File, H.263 |
| Matroska (.mkv) | AAC, Dolby Digital (AC3), Dolby Digital Plus (EAC3), Opus, WMA, WMA2 |
| WebM (.webm) | VP8, VP9 |
| Advanced Systems Format (.wmv) | WMA, WMA2, WMA Pro |
#### Audio
| Container | Audio codecs supported with container |
| ------------------------------ | ----------------------------------------------------------------------------------------------------------- |
| MPEG-4 (.mp4) | AAC, Dolby Digital (AC3), Dolby Digital Plus (EAC3), PCM, WMA, WMA2 |
| QuickTime (.mov) | AAC, MP3, PCM |
| Audio Video Interleave (.avi) | Dolby Digital (AC3), Dolby Digital Plus (EAC3), Dolby E frames carried in PCM streams, MP3, MPEG Audio, PCM |
| Adobe Flash (.flv) | AAC |
| Matroska (.mkv) | AAC, Dolby Digital (AC3), Dolby Digital Plus (EAC3), Opus, WMA, WMA2 |
| WebM (.webm) | Opus, Vorbis |
| Advanced Systems Format (.wmv) | WMA, WMA2, WMA Pro |
#### Other Attributes
| Attribute | Notes |
| ---------- | ------------------------------------------------------------------------- |
| Resolution | Maximum resolution is \[8192]x\[4320] or \[4320]x\[8192] in portrait mode |
### Outputs
#### Video
| Container | Video codecs supported with container |
| ------------- | ------------------------------------- |
| MPEG-4 (.mp4) | AVC (H.264) |
| HLS | AVC (H.264) |
#### Audio
| Container | Audio codecs supported with container |
| ------------- | ------------------------------------- |
| MPEG-4 (.mp4) | AAC |
## Livestream
### Ingest Support
| attribute | notes |
| ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Location | Global |
| Ingest Format | RTMP, SRT (Beta) |
| Ingest Codec | H264 + AAC |
| Ingest Authentication | Webhook based |
| Encoder Software | Supported tested: OBS 25.0.8, ffmpeg 4.3, Streamaxia Supported untested: Xsplit, other versions of OBS and ffmpeg, other RTMP encoders, SRT encoders Unsupported: WebRTC |
| Framerate | Between 5fps and 60fps, passthrough or custom |
| GOP Size (Keyframe Interval) | Supported tested: Constant GOP, Variable GOP of 0.5s to 8s Supported untested: Xsplit, Other versions of OBS and ffmpeg, other RTMP encoders Unsupported: Variable GOP not within 0.5s to 8s |
### Transcoding Support
| attribute | notes |
| ------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| Location | Global |
| Codec | H264 + AAC |
| H264 Transcoding Profiles | Baseline, Main, High |
| FPS | Supported tested: 24, 25, 30, 60 fps, uniform across all renditions Supported untested: custom fps, uniform across all renditions |
| Resolution | Supported tested: Custom resolution up to 1080pSupported untested: Custom resolution up to 4k |
| Pixel format | YUV4:2:0 |
### Video Workflow Support
| attribute | notes |
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| On Demand upload format | MP4 |
| Live latency | 10-18 seconds with good RTMP ingest health, 2s segment size, and standard 3 seg buffering in player |
| Live output format | HLS playback URL (m3u8) |
| H264 Transcoding Profiles | Baseline, Main, High |
| Video players | Supported tested: Livepeer UI Kit Player, video.js, hls.js, safari/ios native player, Theoplayer; Supported untested: JWPlayer, android native, Shaka, Exo, Bitmovin, Brightcove |
| Video Delivery Location | Supported tested: EU, USSupported untested: Asia, South America, Australia, Africa |
| Livestream recording | Only available for paying users. HLS playback URL (m3u8) available 5 minutes after session ends. Livepeer.Studio stores recording and serves playback via CDN. There is no limit on recording length. |
| Recording output format | HLS playback URL (m3u8) |
| CDN delivery | CDN delivery is only available for paying users. |
| Non-CDN Delivery | Non-CDN delivery for free tier users is limited to 10 viewers per account. Free tier users will have transcoding limited to 240p after 30 free minutes. |
| Custom CDN | Only for custom pricing tier users. |
| Stream Status | active or inactive |
| Stream length | We can support streams up to 12 hours in length. Please reach out to [contact@livepeer.studio](mailto:contact@livepeer.studio) if you’re looking to run longer uninterrupted streams through Livepeer.Studio. |
| Scalability | 1000 concurrent streams across all users. Please contact us at [contact@livepeer.studio](mailto:contact@livepeer.studio) for additional capacity |
# Awesome Livepeer
Source: https://docs.livepeer.org/v1/references/awesome-livepeer
# Contract Addresses
Source: https://docs.livepeer.org/v1/references/contract-addresses
Look up current Livepeer protocol contract addresses across supported networks and deployed versions — Arbitrum One (active) and Ethereum Mainnet (legacy).
**This page is no longer maintained.** Contract addresses on this page may be outdated or incorrect.
The canonical, automatically verified contract addresses are at:
**[Livepeer Contract Addresses](/v2/about/resources/livepeer-contract-addresses)**
All addresses on the canonical page are verified on-chain weekly and updated automatically from the protocol's governor-scripts repository.
Addresses of deployed contracts of the Livepeer protocol on multiple networks.
## Current
### Arbitrum One
All contracts on Arbitrum One implement the Delta version of the protocol.
* **Governor**: [`0xD9dEd6f9959176F0A04dcf88a0d2306178A736a6`](https://arbiscan.io/address/0xD9dEd6f9959176F0A04dcf88a0d2306178A736a6)
* **Controller**: [`0xD8E8328501E9645d16Cf49539efC04f734606ee4`](https://arbiscan.io/address/0xD8E8328501E9645d16Cf49539efC04f734606ee4)
* **LivepeerToken**: [`0x289ba1701C2F088cf0faf8B3705246331cB8A839`](https://arbiscan.io/address/0x289ba1701C2F088cf0faf8B3705246331cB8A839)
* **Minter**: [`0xc20DE37170B45774e6CD3d2304017fc962f27252`](https://arbiscan.io/address/0xc20DE37170B45774e6CD3d2304017fc962f27252)
* **BondingManager (Proxy)**: [`0x35Bcf3c30594191d53231E4FF333E8A770453e40`](https://arbiscan.io/address/0x35Bcf3c30594191d53231E4FF333E8A770453e40)
* **BondingManager (Target)**: [`0x4bA7E7531Ab56bC8d78dB4FDc88D21F621f34BB4`](https://arbiscan.io/address/0x4bA7E7531Ab56bC8d78dB4FDc88D21F621f34BB4)
* **TicketBroker (Proxy)**: [`0xa8bB618B1520E284046F3dFc448851A1Ff26e41B`](https://arbiscan.io/address/0xa8bB618B1520E284046F3dFc448851A1Ff26e41B)
* **TicketBroker (Target)**: [`0xea1b0F6c8D158328a6e3D3F924B86A759F41465c`](https://arbiscan.io/address/0xea1b0F6c8D158328a6e3D3F924B86A759F41465c)
* **RoundsManager (Proxy)**: [`0xdd6f56DcC28D3F5f27084381fE8Df634985cc39f`](https://arbiscan.io/address/0xdd6f56DcC28D3F5f27084381fE8Df634985cc39f)
* **RoundsManager (Target)**: [`0x92d804Ed49D92438aEA6fe552BD9163aacb7E841`](https://arbiscan.io/address/0x92d804Ed49D92438aEA6fe552BD9163aacb7E841)
* **BondingVotes (Proxy)**: [`0x0B9C254837E72Ebe9Fe04960C43B69782E68169A`](https://arbiscan.io/address/0x0B9C254837E72Ebe9Fe04960C43B69782E68169A)
* **BondingVotes (Target)**: [`0x68AF80376Bc1CA0C25a83b28e5570E8c7bdD3119`](https://arbiscan.io/address/0x68AF80376Bc1CA0C25a83b28e5570E8c7bdD3119)
* **Treasury**: [`0xf82C1FF415F1fCf582554fDba790E27019c8E8C4`](https://arbiscan.io/address/0xf82C1FF415F1fCf582554fDba790E27019c8E8C4)
* **LivepeerGovernor (Proxy)**: [`0xcFE4E2879B786C3aa075813F0E364bb5acCb6aa0`](https://arbiscan.io/address/0xcFE4E2879B786C3aa075813F0E364bb5acCb6aa0)
* **LivepeerGovernor (Target)**: [`0xd2Ce37BCB287CaDc40647f567C2D3C4220901634`](https://arbiscan.io/address/0xd2Ce37BCB287CaDc40647f567C2D3C4220901634)
* **ServiceRegistry (Proxy)**: [`0xC92d3A360b8f9e083bA64DE15d95Cf8180897431`](https://arbiscan.io/address/0xC92d3A360b8f9e083bA64DE15d95Cf8180897431)
* **ServiceRegistry (Target)**: [`0x38093CDca43aeCd7bb474983519A246e93A3b0a7`](https://arbiscan.io/address/0x38093CDca43aeCd7bb474983519A246e93A3b0a7)
* **AIServiceRegistry (Target)**: [`0x04C0b249740175999E5BF5c9ac1dA92431EF34C5`](https://arbiscan.io/address/0x04C0b249740175999E5BF5c9ac1dA92431EF34C5) (detached from controller)
* **SortedDoublyLL**: [`0xC45f6918F7Bcac7aBc8fe05302b3cDF39776cdeb`](https://arbiscan.io/address/0xC45f6918F7Bcac7aBc8fe05302b3cDF39776cdeb)
* **PollCreator**: [`0x8bb50806D60c492c0004DAD5D9627DAA2d9732E6`](https://arbiscan.io/address/0x8bb50806D60c492c0004DAD5D9627DAA2d9732E6)
* **MerkleSnapshot**: [`0x10736ffaCe687658F88a46D042631d182C7757f7`](https://arbiscan.io/address/0x10736ffaCe687658F88a46D042631d182C7757f7)
* **DelegatorPool**: [`0xfdb06109032AD3671a8f14f5f2E78f4B9E81b567`](https://arbiscan.io/address/0xfdb06109032AD3671a8f14f5f2E78f4B9E81b567)
* **L2LPTDataCache**: [`0xd78b6bD09cd28A83cFb21aFa0DA95c685A6bb0B1`](https://arbiscan.io/address/0xd78b6bD09cd28A83cFb21aFa0DA95c685A6bb0B1)
* **L2LPTGateway**: [`0x6D2457a4ad276000A615295f7A80F79E48CcD318`](https://arbiscan.io/address/0x6D2457a4ad276000A615295f7A80F79E48CcD318)
* **L2Migrator (Proxy)**: [`0x148D5b6B4df9530c7C76A810bd1Cdf69EC4c2085`](https://arbiscan.io/address/0x148D5b6B4df9530c7C76A810bd1Cdf69EC4c2085)
* **L2Migrator (Target)**: [`0x93BB030735747708b4D33093A98d4c804Cd6B58C`](https://arbiscan.io/address/0x93BB030735747708b4D33093A98d4c804Cd6B58C)
### Ethereum Mainnet
The following contracts on Ethereum Mainnet implement the Delta version of the protocol:
* Governor
* LivepeerToken
* L1Escrow
* L1LPTDataCache
* L1LPTGateway
* L1Migrator
* BridgeMinter
Since the Confluence upgrade, the protocol has been deployed to Arbitrum One and all contracts on Ethereum Mainnet besides the above are paused.
* **Governor**: [`0xFC3CBed6A3476F7616CC70f078397700136eEBFd`](https://etherscan.io/address/0xFC3CBed6A3476F7616CC70f078397700136eEBFd)
* **Controller**: [`0xf96d54e490317c557a967abfa5d6e33006be69b3`](https://etherscan.io/address/0xf96d54e490317c557a967abfa5d6e33006be69b3)
* **LivepeerToken**: [`0x58b6a8a3302369daec383334672404ee733ab239`](https://etherscan.io/address/0x58b6a8a3302369daec383334672404ee733ab239)
* **Minter**: [`0x505F8c2ee81f1C6fa0D88e918eF0491222E05818`](https://etherscan.io/address/0x505F8c2ee81f1C6fa0D88e918eF0491222E05818)
* **BondingManager (Proxy)**: [`0x511bc4556d823ae99630ae8de28b9b80df90ea2e`](https://etherscan.io/address/0x511bc4556d823ae99630ae8de28b9b80df90ea2e)
* **BondingManager (Target)**: [`0x5FE3565dB7F1Dd8d6A9E968D45BD2Aee3836a1D4`](https://etherscan.io/address/0x5FE3565dB7F1Dd8d6A9E968D45BD2Aee3836a1D4)
* **TicketBroker (Proxy)**: [`0x5b1ce829384eebfa30286f12d1e7a695ca45f5d2`](https://etherscan.io/address/0x5b1ce829384eebfa30286f12d1e7a695ca45f5d2)
* **TicketBroker (Target)**: [`0x6F582E2bB19ac31D4B1e6eDD0c2eFEabD700f808`](https://etherscan.io/address/0x6F582E2bB19ac31D4B1e6eDD0c2eFEabD700f808)
* **RoundsManager (Proxy)**: [`0x3984fc4ceeef1739135476f625d36d6c35c40dc3`](https://etherscan.io/address/0x3984fc4ceeef1739135476f625d36d6c35c40dc3)
* **RoundsManager (Target)**: [`0xC89fE48382F8fda6992dC590786A84275bCD1C57`](https://etherscan.io/address/0xC89fE48382F8fda6992dC590786A84275bCD1C57)
* **ServiceRegistry (Proxy)**: [`0x406a112f3218b988c66778fd72fc8467f2601366`](https://etherscan.io/address/0x406a112f3218b988c66778fd72fc8467f2601366)
* **ServiceRegistry (Target)**: [`0x72d9dfa25f75a5f2c27b7336e643a559ae6aeb8e`](https://etherscan.io/address/0x72d9dfa25f75a5f2c27b7336e643a559ae6aeb8e)
* **GenesisManager**: [`0x3a9543d4767b2c914ea22fd0b07e17b0901aaebf`](https://etherscan.io/address/0x3a9543d4767b2c914ea22fd0b07e17b0901aaebf)
* **MerkleMine**: [`0x8e306b005773bee6ba6a6e8972bc79d766cc15c8`](https://etherscan.io/address/0x8e306b005773bee6ba6a6e8972bc79d766cc15c8)
* **MultiMerkleMine**: [`0x182ebf4c80b28efc45ad992ecbb9f730e31e8c7f`](https://etherscan.io/address/0x182ebf4c80b28efc45ad992ecbb9f730e31e8c7f)
* **SortedDoublyLL**: [`0x1a0b2ca69ca2c7f96e2529faa6d63f881655d81a`](https://etherscan.io/address/0x1a0b2ca69ca2c7f96e2529faa6d63f881655d81a)
* **Refunder**: [`0x780c98cbb0cc21d6617c05332bd5cf6f847c71c2`](https://etherscan.io/address/0x780c98cbb0cc21d6617c05332bd5cf6f847c71c2)
* **PollCreator**: [`0xBf824EDb6b94D9B52d972d5B25bCc19b4e6E3F3C`](https://etherscan.io/address/0xBf824EDb6b94D9B52d972d5B25bCc19b4e6E3F3C)
* **MerkleSnapshot**: [`0x24ebEd82c681f435E944BEEbFAEEAaE443D08438`](https://etherscan.io/address/0x24ebEd82c681f435E944BEEbFAEEAaE443D08438)
* **L1Escrow**: [`0x6A23F4940BD5BA117Da261f98aae51A8BFfa210A`](https://etherscan.io/address/0x6A23F4940BD5BA117Da261f98aae51A8BFfa210A)
* **L1LPTDataCache**: [`0x1d24838b35A9c138Ac157A852e19e948aD6323D7`](https://etherscan.io/address/0x1d24838b35A9c138Ac157A852e19e948aD6323D7)
* **L1LPTGateway**: [`0x6142f1C8bBF02E6A6bd074E8d564c9A5420a0676`](https://etherscan.io/address/0x6142f1C8bBF02E6A6bd074E8d564c9A5420a0676)
* **L1Migrator**: [`0x21146B872D3A95d2cF9afeD03eE5a783DaE9A89A`](https://etherscan.io/address/0x21146B872D3A95d2cF9afeD03eE5a783DaE9A89A)
* **BridgeMinter**: [`0x8dDDB96CF36AC8860f1DE5C7c4698fd499FAB405`](https://etherscan.io/address/0x8dDDB96CF36AC8860f1DE5C7c4698fd499FAB405)
## Historical (DEPRECATED — FOR REFERENCE ONLY)
### Arbitrum One
#### BondingManager (Target)
* **V1**: [`0xe479B9fbA2Cd65f822f451fC8C145c663B995CE6`](https://arbiscan.io/address/0xe479B9fbA2Cd65f822f451fC8C145c663B995CE6)
* **V2**: [`0xC40df4db2f99e7e235780A93B192F1a934f0c45b`](https://arbiscan.io/address/0xC40df4db2f99e7e235780A93B192F1a934f0c45b)
* **V3**: [`0x3757DB506ECd9CBE643660C0F5b70db5b321202C`](https://arbiscan.io/address/0x3757DB506ECd9CBE643660C0F5b70db5b321202C)
* **V4**: [`0x0f9C425E7374602C20370d3fd263155B4c3bDc91`](https://arbiscan.io/address/0x0f9C425E7374602C20370d3fd263155B4c3bDc91)
* **V5**: [`0x3a941e1094B9E33efABB26a9047a8ABb4b257907`](https://arbiscan.io/address/0x3a941e1094B9E33efABB26a9047a8ABb4b257907)
* **V6**: [`0x9c9209c9ff6996513b3673d69ee7b36a6c58a8cf`](https://arbiscan.io/address/0x9c9209c9ff6996513b3673d69ee7b36a6c58a8cf)
* **V7**: [`0x363cdB9BaE210Ef182c60b5a496139E980330127`](https://arbiscan.io/address/0x363cdB9BaE210Ef182c60b5a496139E980330127)
* **V8**: [`0x557093B1Ab53412166beAd939f34244170b6525B`](https://arbiscan.io/address/0x557093B1Ab53412166beAd939f34244170b6525B)
* **V9**: [`0x6b397f20DC227B4E23fEc20BBDBe166d0DFFC452`](https://arbiscan.io/address/0x6b397f20DC227B4E23fEc20BBDBe166d0DFFC452)
* **V10**: [`0xd1C1F5d44D8F83ca2A05Baf40461e550cFDDecA2`](https://arbiscan.io/address/0xd1C1F5d44D8F83ca2A05Baf40461e550cFDDecA2)
* **V11 (current)**: [`0x4bA7E7531Ab56bC8d78dB4FDc88D21F621f34BB4`](https://arbiscan.io/address/0x4bA7E7531Ab56bC8d78dB4FDc88D21F621f34BB4)
#### BondingVotes (Target)
* **V1**: [`0x1561fC5F7Efc049476224005DFf38256dccfc509`](https://arbiscan.io/address/0x1561fC5F7Efc049476224005DFf38256dccfc509)
#### TicketBroker (Target)
* **V1**: [`0x7Beb84c52ce96DFd90431FAA97378994a8baa6df`](https://arbiscan.io/address/0x7Beb84c52ce96DFd90431FAA97378994a8baa6df)
* **V2 (current)**: [`0xea1b0F6c8D158328a6e3D3F924B86A759F41465c`](https://arbiscan.io/address/0xea1b0F6c8D158328a6e3D3F924B86A759F41465c)
#### Minter
* **V1**: [`0x4969dcCF5186e1c49411638fc8A2a020Fdab752E`](https://arbiscan.io/address/0x4969dcCF5186e1c49411638fc8A2a020Fdab752E)
#### L2Migrator (Target)
* **V1**: [`0x4F59b39e2ea628fe8371BDfd51B063319339c7EE`](https://arbiscan.io/address/0x4F59b39e2ea628fe8371BDfd51B063319339c7EE)
### Ethereum Mainnet
#### LivepeerVerifier
* **V1**: [`0xf623811b08b45792d0223d77d9c922dae29712ec`](https://etherscan.io/address/0xf623811b08b45792d0223d77d9c922dae29712ec)
* **V2**: [`0xe4be2a35dec0063f9dfccb9b740b1acb7eefefec`](https://etherscan.io/address/0xe4be2a35dec0063f9dfccb9b740b1acb7eefefec)
#### Minter
* **V1**: [`0x8573f2f5a3bd960eee3d998473e50c75cdbe6828`](https://etherscan.io/address/0x8573f2f5a3bd960eee3d998473e50c75cdbe6828)
#### BondingManager (Target)
* **V1**: [`0x81eb0b10ff8703905904e4d91cf6aa575d59736f`](https://etherscan.io/address/0x81eb0b10ff8703905904e4d91cf6aa575d59736f)
* **V2**: [`0x5A9512826EAAF1FE4190f89443314E95A515fE24`](https://etherscan.io/address/0x5A9512826EAAF1FE4190f89443314E95A515fE24)
* **V3**: [`0x633101b3f15f93c5f415830d48e56b9b1f7ba584`](https://etherscan.io/address/0x633101b3f15f93c5f415830d48e56b9b1f7ba584)
* **V4**: [`0x05C03EA0039f2e828A725A82939fc1e90de38B44`](https://etherscan.io/address/0x05C03EA0039f2e828A725A82939fc1e90de38B44)
* **V5**: [`0xCBAa6eA4886b535FC7ABACe3F3985Ed03b3b80a0`](https://etherscan.io/address/0xCBAa6eA4886b535FC7ABACe3F3985Ed03b3b80a0)
* **V6**: [`0xDC6eE74A18994caD3876a078B6fa4920FD9C507d`](https://etherscan.io/address/0xDC6eE74A18994caD3876a078B6fa4920FD9C507d)
* **V7**: [`0x1a6007d1D0583452Bd6f45a4e1a9190B15Fbd7E3`](https://etherscan.io/address/0x1a6007d1D0583452Bd6f45a4e1a9190B15Fbd7E3)
* **V8**: [`0xef5E170b679ddaF5e22ADC10fD23DDdB79E3C0c5`](https://etherscan.io/address/0xef5E170b679ddaF5e22ADC10fD23DDdB79E3C0c5)
* **V9**: [`0xc8a695155648F18B0cfd6989498B6f8b2c4cc56A`](https://etherscan.io/address/0xc8a695155648F18B0cfd6989498B6f8b2c4cc56A)
* **V10**: [`0x35F99F326681FE4F38719491be48Ab4950795013`](https://etherscan.io/address/0x35F99F326681FE4F38719491be48Ab4950795013)
* **V11**: [`0xAC0153a8C5227e43506901a4f3f83FD000c8178f`](https://etherscan.io/address/0xAC0153a8C5227e43506901a4f3f83FD000c8178f)
* **V12**: [`0x246edEBae14b186a67e3d466A485321169a8bcD5`](https://etherscan.io/address/0x246edEBae14b186a67e3d466A485321169a8bcD5)
* **V13**: [`0x223398d0BF9cc24960b3886CC481dBf5276EdeD2`](https://etherscan.io/address/0x223398d0BF9cc24960b3886CC481dBf5276EdeD2)
* **V14**: [`0x0da7c263eCF5cD3ddba275b9A2D63320E28fD287`](https://etherscan.io/address/0x0da7c263eCF5cD3ddba275b9A2D63320E28fD287)
#### JobsManager (Proxy)
* **V1**: [`0xbf07ff45f14c9ff0571b9fbdc7e2b62d29931224`](https://etherscan.io/address/0xbf07ff45f14c9ff0571b9fbdc7e2b62d29931224)
#### JobsManager (Target)
* **V1**: [`0x68b463bca7d561118636e9f028ff0f2e8398dd6a`](https://etherscan.io/address/0x68b463bca7d561118636e9f028ff0f2e8398dd6a)
* **V2**: [`0xB620c762dd4bC350602936d7401BB8393Ee6687c`](https://etherscan.io/address/0xB620c762dd4bC350602936d7401BB8393Ee6687c)
* **V3**: [`0x8eade5eec609572bf53deadb88d36f862ddec517`](https://etherscan.io/address/0x8eade5eec609572bf53deadb88d36f862ddec517)
#### RoundsManager (Target)
* **V1**: [`0xa3aa52ce79e85a21d9ccda705c57e426b160112c`](https://etherscan.io/address/0xa3aa52ce79e85a21d9ccda705c57e426b160112c)
* **V2**: [`0x857d4bf18a80f03d3d11f438825cd3d0aa0d9d68`](https://etherscan.io/address/0x857d4bf18a80f03d3d11f438825cd3d0aa0d9d68)
#### MerkleProof
* **V1**: [`0x289ba1701c2f088cf0faf8b3705246331cb8a839`](https://etherscan.io/address/0x289ba1701c2f088cf0faf8b3705246331cb8a839)
#### ECRecovery
* **V1**: [`0xd8e8328501e9645d16cf49539efc04f734606ee4`](https://etherscan.io/address/0xd8e8328501e9645d16cf49539efc04f734606ee4)
#### JobLib
* **V1**: [`0x4969dccf5186e1c49411638fc8a2a020fdab752e`](https://etherscan.io/address/0x4969dccf5186e1c49411638fc8a2a020fdab752e)
# Example Applications
Source: https://docs.livepeer.org/v1/references/example-applications
Curated collection of Livepeer example applications and integrations
Enjoy a curated collection of Livepeer example applications and integrations.
Use these starter projects to build your own video applications.
| Example | Description |
| -------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| [React Native Example App](https://github.com/suhailkakar/Livepeer-YouTube) | Example application which demonstrates how to use Livepeer React to create a React Native YouTube clone. |
| [Justcast.it](https://github.com/victorges/justcast.it) | Web app that provides code for adding "1-click starting a livestream" so that you can create a stream using the Livepeer API. |
| [EVM Token-Gated Livestream](https://github.com/suhailkakar/Livepeer-EVM-Tokengating) | Example application which demonstrates how to create and tokengate a livestream using Livepeer on EVM compatible chains. |
| [Decentralized storage playback](https://github.com/suhailkakar/livepeer-dStorage-playback/) | Example application which demonstrates how to play back a video from decentralized storage such as IPFS and Arweave using Livepeer. |
# Bandwidth Requirements
Source: https://docs.livepeer.org/v1/references/go-livepeer/bandwidth-requirements
The bandwidth requirements for video miners are based on the amount of video
data that needs to be uploaded and downloaded during transcoding.
The amount of available bandwidth will not only impact the number of streams
that can be transcoded on a machine, but also the speed of data upload/download
which needs to be fast so that video streaming applications can receive
transcoded results as soon as possible.
The amount of bandwidth required for a stream will depend on the bitrate of the
source stream and the bitrate of the output renditions. The download bandwidth
required for a single stream can be roughly estimated as the bitrate of the
source stream. The upload bandwidth required for a single stream can be roughly
estimated as the sum of the bitrates of each of the output renditions for the
stream. As a result, the total number of streams that can be transcoded given a
certain amount of available of bandwidth will vary.
While there is not a strict bandwidth requirement for video miners, past testing
has demonstrated that 1G upload/download bandwidth is a good starting point if
possible. If you do not have access to this amount of bandwidth you will still
be able to transcode on the network, but you will have a lower ceiling on the
number of streams you will be able to handle.
Upload/download bandwidth available can be tested with tools such as:
* [speedtest](https://www.speedtest.net/apps/cli)
* By default the tool will run a bandwidth test against the closest public
server, but there is also an option to run the test against a specified
public server
* Note: The results of this test also depend on the available bandwidth on the
server used
* [iperf3](https://iperf.fr/)
* This tool can be run on client and server machines that you have access to
* If you have access to a machine with good bandwidth availability in a region
that you expect/want to receive streams from, then this tool will likely be
more useful than speedtest
# CLI Reference
Source: https://docs.livepeer.org/v1/references/go-livepeer/cli-reference
The `livepeer` binary in `go-livepeer` has a number of configurable options. You
can set your configuration using command-line flags, environment variables, or a
config file.
A comprehensive list of options can be found below. They are sourced and
regularly updated from
[this file](https://github.com/livepeer/go-livepeer/blob/master/cmd/livepeer/livepeer.go).
The
[go-livepeer developer docs](https://github.com/livepeer/go-livepeer/tree/master/doc)
also contain instructions for using flags to enable certain functionality in
`livepeer`.
## Options
### Configuration
* config: Path to config file.
### Network and Addresses
* network: Network to connect to. Default `offchain`
* rtmpAddr: Address to bind for RTMP commands. Default `127.0.0.1:+RtmpPort`
* cliAddr: Address to bind for CLI commands. Default `127.0.0.1:+CliPort`
* httpAddr: Address to bind for HTTP commands. No default
* serviceAddr: Orchestrator only. Overrides the on-chain serviceURI that
gateways can use to contact this node; may be an IP or hostname. No default
* orchAddr: Orchestrator to connect to as a standalone transcoder. No default.
* verifierURL: URL of the verifier to use. No default.
* verifierPath: Path to verifier shared volume. No default.
* localVerify: Set to true to enable local verification i.e. pixel count and
signature verification. Default `true`. However, if you are running in
offchain mode, this will be set to false.
* httpIngest: Set to true to enable HTTP ingest. Default `true`. However, if (1)
you do not provide a value, (2) you provide a non-local URL for `httpAddr`,
and (3) you do not provide an `authWebhookURL`, this will be set to false.
### Transcoding
* orchestrator: Set to true to be an orchestrator. Default `false`
* transcoder: Set to true to be an transcoder. Default `false`
* gateway: Set to true to be an gateway (formerly known as *Broadcaster*).
Default `false`
* orchSecret: Shared secret with the orchestrator as a standalone transcoder or
path to file
* transcodingOptions: Transcoding options for broadcast job, or path to json
config. Default `P240p30fps16x9,P360p30fps16x9`
* maxAttempts: Maximum transcode attempts. Default `3`
* selectRandFreq: Frequency to randomly select unknown orchestrators (on-chain
mode only). Default `0.3`
* maxSessions: Maximum number of concurrent transcoding sessions for
Orchestrator, maximum number or RTMP streams for Gateway, or maximum capacity
for transcoder. Default `10`
* currentManifest: Expose the currently active ManifestID as
"/stream/current.m3u8". Default `false`
* nvidia: Comma-separated list of Nvidia GPU device IDs (or "all" for all
available devices). No default
* testTranscoder: Test Nvidia GPU transcoding at startup. Default `true`
* sceneClassificationModelPath: Path to scene classification model. No default
### Onchain
* ethAcctAddr: Existing Eth account address. For use when multiple ETH accounts
exist in the keystore directory
* ethPassword: Password for existing Eth account address or path to file
* ethKeystorePath: Path to ETH keystore directory or keyfile. If keyfile,
overrides -ethAcctAddr and uses parent directory
* ethOrchAddr: address of an on-chain registered orchestrator. No default
* ethUrl: EVM-compatible chain node JSON-RPC URL. No default
* txTimeout: Amount of time (ms) to wait for a transaction to confirm before
timing out. Default `300000 (5 mins)`
* maxTxReplacements: Number of times to automatically replace pending
transactions. Default `1`
* gasLimit: Gas limit for ETH transaction. Default `0`
* minGasPrice: Minimum gas price (priority fee + base fee) for ETH transactions
in wei, 10 Gwei = 10000000000. If not set, this will be the network's default
min gas fee.
* maxGasPrice: Maximum gas price (priority fee + base fee) for ETH transactions
in wei, 40 Gwei = 40000000000. Default `0`
* ethController: Protocol smart contract address. No default
* initializeRound: Set to true if running as a transcoder and the node should
automatically initialize new rounds. Default false.
* ticketEV: The expected value for PM tickets. Default `1000000000000`
* maxTicketEV: The maximum acceptable expected value for PM tickets. Default
`3000000000000`
* depositMultiplier: The deposit multiplier used to determine max acceptable
faceValue for PM tickets. Default `1`
* pricePerUnit: The price per 'pixelsPerUnit' amount pixels. Must be greater
than 0. Error if not set.
* maxPricePerUnit: The maximum transcoding price (in wei) per 'pixelsPerUnit' a
gateway is willing to accept. If not set explicitly, gateway is willing to
accept ANY price. Default `0`
* pixelsPerUnit: Amount of pixels per unit. Set to '> 1' to have smaller price
granularity than 1 wei / pixel. Default `1`
* pricePerGateway: json list of price per gateway or path to json config file.
Example:
`{"gateways":[{"ethaddress":"address1","priceperunit":1000,"pixelsperunit":1},{"ethaddress":"address2","priceperunit":1200,"pixelsperunit":1}]}`
* autoAdjustPrice: Enable/disable automatic price adjustments based on the
overhead for redeeming tickets. Default `true`
* blockPollingInterval: Interval in seconds at which different blockchain event
services poll for blocks. Default `5`
* redeemer: Set to true to run a ticket redemption service. Default `false`
* redeemerAddr: URL of the ticket redemption service to use. No default
* reward: Set to true to run a reward service. If you do not want to
automatically call `reward()`, you need to explicitly set this to `false` for
any node that's registered onchain. Otherwise, it will default to true.
* monitor: Set to true to send performance metrics. Default `false`
* version: Print out the version. Default `false`
* v: Log verbosity - . No default
* metadataQueueUri: URI for message broker to send operation metadata. No
default
* metadataAmqpExchange: Name of AMQP exchange to send operation metadata.
Default `lp_golivepeer_metadata`
* metadataPublishTimeout: Max time (ms) to wait in background for publishing
operation metadata events. Default `1000 (1s)`
* maxFaceValue: Set the maximum face value of a ticket (in wei). No default
### Storage
* datadir: Directory that data is stored in. No default
* objectstore: URL of primary object store. No default
* recordstore: URL of object store for recodings. No default
### API
* authWebhookURL: RTMP authentication webhook URL. No default
* orchWebhookURL: Orchestrator discovery callback URL. No default
* detectionWebhookURL: (Experimental) Detection results callback URL. No default
# GPU Support
Source: https://docs.livepeer.org/v1/references/go-livepeer/gpu-support
Livepeer enables node operators to transcode video on GPUs while concurrently
mining cryptocurrencies and performing other CUDA operations such as machine
learning. As there is a very wide range of GPU hardware out there, this document
aims to crowdsource a list of specific GPU models that have been tested and
verified to work on Livepeer. If you've tested an additional model, please
submit an update to this document.
## Overview
* Livepeer supports transcoding on NVIDIA GPUs with NVENC/NVDEC. Any GPU
[listed here](https://developer.nvidia.com/video-encode-and-decode-gpu-support-matrix-new)
with those chips should theoretically work. Note that different models may be
subject to different session limits that restrict the amount of video that can
be transcoded.
* See
[this document which lists tested driver versions](https://github.com/livepeer/go-livepeer/blob/master/doc/gpu.md)
on the NVIDIA cards.
| GPU Model | Tested Transcoding | Tested Concurrent Ethash Mining | Notes | |
| ----------------------------- | ------------------ | ------------------------------- | ------------------------------------------------------------------------------------------------------ | - |
| NVIDIA GeForce GTX 950 | ✅ | | [Benchmarks](https://forum.livepeer.org/t/gtx-950-quadro-p400-benchmarks/1497) | |
| NVIDIA GeForce GTX 1060 | ✅ | ✅ | | |
| NVIDIA GeForce GTX 1070 | ✅ | | | |
| NVIDIA GeForce GTX 1070 Ti | ✅ | ✅ | | |
| NVIDIA GeForce GTX 1080 | ✅ | | | |
| NVIDIA GeForce GTX 1080 Ti | ✅ | | | |
| NVIDIA Tesla T4 | ✅ | | | |
| NVIDIA GeForce GTX 1660 Ti | ✅ | | | |
| NVIDIA GeForce GTX 1660 SUPER | ✅ | | | |
| NVIDIA GeForce GTX 2080 Ti | ✅ | ✅ | | |
| NVIDIA GeForce RTX 3080 | ✅ | ✅ | [Benchmarks](https://forum.livepeer.org/t/dual-ethash-mining-transcoding-w-rtx-3080-10g-cuda-mps/1161) | |
| NVIDIA GeForce GTX 3090 | ✅ | ✅ | | |
| NVIDIA Titan V | ✅ | ✅ | | |
| NVIDIA Quadro P400 | ✅ | | [Benchmarks](https://forum.livepeer.org/t/gtx-950-quadro-p400-benchmarks/1497) | |
| NVIDIA Quadro T600 | ✅ | | [Benchmarks](https://forum.livepeer.org/t/nvidia-quadro-t600-benchmark/1650) | |
# Hardware Requirements
Source: https://docs.livepeer.org/v1/references/go-livepeer/hardware-requirements
The hardware requirements for video miners are based on the computational
resources required for transcoding.
## GPU
A GPU with a built-in hardware video encoder/decoder is **strongly** recommended
because it will significantly speed up transcoding and it will be difficult to
compete for work in the marketplace without one. Transcoding capacity will scale
with the number of GPUs available.
Currently, `livepeer` only supports Nvidia GPUs with
[NVENC (hardware video encoder) and NVDEC (hardware video decoder) support](https://developer.nvidia.com/video-encode-and-decode-gpu-support-matrix-new).
For a list of of GPUs that have been tested and that are known to be supported
by `livepeer`, see [this page](/references/go-livepeer/gpu-support).
## CPU
CPU transcoding using a software video encoder/decoder is possible, but not
recommended due to its significant speed disadvantage relative to GPU
transcoding. If you choose to do CPU transcoding (perhaps to try things out or
as a temporary measure until a GPU is available), generally a CPU with more
cores will improve transcoding speed.
## RAM
TBD.
## Disk
TBD.
# Prometheus Metrics
Source: https://docs.livepeer.org/v1/references/go-livepeer/prometheus-metrics
Livepeer exposes a number of metrics via the Prometheus exporter. This page
documents all metrics that you can scrape via the `/metrics` endpoint when the
[monitoring is enabled](/orchestrators/guides/monitor-metrics).
## Livepeer metrics
### General
| Name | Description | Node Type |
| -------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | ------------------------------------------- |
| `livepeer_versions` | Versions used by Livepeer node. | Gateway, Orchestrator, Transcoder, Redeemer |
| `livepeer_segment_source_appeared_total` | SegmentSourceAppeared | Gateway |
| `livepeer_segment_source_emerged_total` | SegmentEmerged | Gateway |
| `livepeer_segment_source_emerged_unprocessed_total` | Raw number of segments emerged from segmenter. | Gateway, Orchestrator |
| `livepeer_segment_source_uploaded_total` | SegmentUploaded | Gateway, Orchestrator, Transcoder |
| `livepeer_segment_source_upload_failed_total` | SegmentUploadedFailed | Gateway |
| `livepeer_segment_transcoded_downloaded_total` | SegmentDownloaded | Gateway, Orchestrator |
| `livepeer_segment_transcoded_total` | SegmentTranscoded | Gateway, Orchestrator |
| `livepeer_segment_transcoded_unprocessed_total` | Raw number of segments successfully transcoded. | Gateway |
| `livepeer_segment_transcode_failed_total` | SegmentTranscodeFailed | Gateway |
| `livepeer_segment_transcoded_all_appeared_total` | SegmentTranscodedAllAppeared | Gateway |
| `livepeer_stream_created_total` | StreamCreated | Gateway |
| `livepeer_stream_started_total` | StreamStarted | Gateway |
| `livepeer_stream_ended_total` | StreamEnded | Gateway |
| `livepeer_max_sessions_total` | Max Sessions | Gateway, Orchestrator, Transcoder, Redeemer |
| `livepeer_current_sessions_total` | Number of streams currently transcoding | Gateway, Orchestrator |
| `livepeer_discovery_errors_total` | Number of discover errors | Gateway |
| `livepeer_transcode_retried` | Number of times segment transcode was retried | Gateway |
| `livepeer_transcoders_number` | Number of transcoders currently connected to orchestrator | Gateway, Orchestrator, Transcoder, Redeemer |
| `livepeer_transcoders_capacity` | Total advertised capacity of transcoders currently connected to orchestrator | Gateway, Orchestrator, Transcoder, Redeemer |
| `livepeer_transcoders_load` | Total load of transcoders currently connected to orchestrator | Gateway, Orchestrator, Transcoder, Redeemer |
| `livepeer_success_rate` | Number of transcoded segments divided on number of source segments | Gateway, Orchestrator, Transcoder, Redeemer |
| `livepeer_success_rate_per_stream` | Number of transcoded segments divided on number of source segments, per stream | Gateway |
| `livepeer_transcode_time_seconds` | TranscodeTime, seconds | Gateway, Orchestrator |
| `livepeer_transcode_overall_latency_seconds` | Transcoding latency, from source segment emerged from segmenter till all transcoded segment apeeared in manifest | Gateway |
| `livepeer_upload_time_seconds` | UploadTime, seconds | Gateway, Orchestrator, Transcoder |
| `livepeer_download_time_seconds` | Download time | Gateway, Orchestrator |
| `livepeer_auth_webhook_time_milliseconds` | Authentication webhook execution time, milliseconds | Gateway |
| `livepeer_source_segment_duration_seconds` | Source segment's duration | Gateway, Orchestrator |
| `livepeer_http_client_timeout_1` | Number of times HTTP connection was dropped before transcoding complete | Gateway |
| `livepeer_http_client_timeout_2` | Number of times HTTP connection was dropped before transcoded segments was sent back to client | Gateway |
| `livepeer_http_client_segment_transcoded_realtime_ratio` | Ratio of source segment duration / transcode time as measured on HTTP client | Gateway |
| `livepeer_http_client_segment_transcoded_realtime_3x` | Number of segment transcoded 3x faster than realtime | Gateway |
| `livepeer_http_client_segment_transcoded_realtime_2x` | Number of segment transcoded 2x faster than realtime | Gateway |
| `livepeer_http_client_segment_transcoded_realtime_1x` | Number of segment transcoded 1x faster than realtime | Gateway |
| `livepeer_http_client_segment_transcoded_realtime_half` | Number of segment transcoded no more than two times slower than realtime | Gateway |
| `livepeer_http_client_segment_transcoded_realtime_slow` | Number of segment transcoded more than two times slower than realtime | Gateway |
| `livepeer_transcode_score` | Ratio of source segment duration vs. transcode time | Gateway, Orchestrator |
| `livepeer_recording_save_latency` | How long it takes to save segment to the OS | Gateway |
| `livepeer_recording_save_errors` | Number of errors during save to the recording OS | Gateway |
| `livepeer_recording_saved_segments` | Number of segments saved to the recording OS | Gateway |
| `livepeer_orchestrator_swaps` | Number of orchestrator swaps mid-stream | Gateway |
### Sending payments
| Name | Description | Node Type |
| -------------------------------- | ---------------------------------------------- | --------- |
| `livepeer_ticket_value_sent` | Ticket value sent | Gateway |
| `livepeer_tickets_sent` | Tickets sent | Gateway |
| `livepeer_payment_create_errors` | Errors when creating payments | Gateway |
| `livepeer_gateway_deposit` | Current remaining deposit for the gateway node | Gateway |
| `livepeer_gateway_reserve` | Current remaining reserve for the gateway node | Gateway |
### Receiving payments
| Name | Description | Node Type |
| ----------------------------------- | -------------------------------------------------- | ------------------------------- |
| `livepeer_ticket_value_recv` | Ticket value received | Orchestrator |
| `livepeer_tickets_recv` | Tickets received | Orchestrator |
| `livepeer_payment_recv_errors` | Errors when receiving payments | Orchestrator |
| `livepeer_winning_tickets_recv` | Winning tickets received | Orchestrator |
| `livepeer_value_redeemed` | Winning ticket value redeemed | Orchestrator, Redeemer |
| `livepeer_ticket_redemption_errors` | Errors when redeeming tickets | Orchestrator, Redeemer |
| `livepeer_suggested_gas_price` | Suggested gas price for winning ticket redemption | Gateway, Orchestrator, Redeemer |
| `livepeer_min_gas_price` | Minimum gas price to use for gas price suggestions | Gateway, Orchestrator, Redeemer |
| `livepeer_max_gas_price` | Maximum gas price to use for gas price suggestions | Gateway, Orchestrator, Redeemer |
| `livepeer_transcoding_price` | Transcoding price per pixel | Orchestrator |
### Pixel accounting
| Name | Description | Node Type |
| ------------------------------- | ------------------------ | --------------------- |
| `livepeer_mil_pixels_processed` | Million pixels processed | Gateway, Orchestrator |
### Fast verification
| Name | Description | Node Type |
| ----------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | --------- |
| `livepeer_fast_verification_done` | Number of fast verifications done | Gateway |
| `livepeer_fast_verification_failed` | Number of fast verifications failed | Gateway |
| `livepeer_fast_verification_enabled_current_sessions_total` | Number of currently transcoded streams that have fast verification enabled | Gateway |
| `livepeer_fast_verification_using_current_sessions_total` | Number of currently transcoded streams that have fast verification enabled and that are using an untrusted orchestrator | Gateway |
# Livestream
Source: https://docs.livepeer.org/v1/references/knowledge-base/livestream
Diagnose: We do not have a feature to livestream audio only, but it is being
planned. Visit our feature request page for updates.
[https://livepeer.canny.io/feature-requests](https://livepeer.canny.io/feature-requests) Workaround: Add `?video=false` to
the end of the playback URL. Ex.
[https://livepeercdn.com/hls/playbackId/index.m3u8?video=false](https://livepeercdn.com/hls/playbackId/index.m3u8?video=false)
Diagnose: This is supported but has not been thoroughly tested.
Workaround: When creating a stream, add the following to the profile:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"name": "1080p",
"bitrate": 5000000,
"fps": 30,
"width": 1920,
"height": 1080
}
```
Diagnose: At the moment, we do not offer closed captioning features.
Workaround: This has been added to the feature request [https://livepeer.canny.io/feature-requests/p/adding-subtitles-to-your-video-assets](https://livepeer.canny.io/feature-requests/p/adding-subtitles-to-your-video-assets)
Diagnose: You can suspend the stream
Workaround: Use either the API or SDK to suspend the stream. [https://docs.livepeer.org/reference/api#update-a-stream](https://docs.livepeer.org/reference/api#update-a-stream) or [https://docs.livepeer.org/reference/livepeer-js/stream/useUpdateStream#suspend](https://docs.livepeer.org/reference/livepeer-js/stream/useUpdateStream#suspend)
Diagnose: Yes, it is under the `sourceBytes` in the stream object.
Workaround: [https://docs.livepeer.org/reference/api#retrieve-a-stream](https://docs.livepeer.org/reference/api#retrieve-a-stream)
Diagnose: Short form videos need to use the MP4 playback as default
Workaround: Get the MP4 playback from the asset object and set it as the source. If you use the HLS instead for short form videos, this will affect the playback experience for users drastically.
Diagnose: If you're using livepeer.studio you can force a region.
Workaround: Replace the `rtmp://rtmp.livepeer.com/live/streamkey` with the region you want to force the broadcast to. Ex. `rtmp://sin-rtmp.livepeer.com/live/streamkey`, contact us for a list of regions available.
Diagnose: When creating a stream, set the profile object of the stream empty.
Workaround: `profile:[]`
Diagnose: You can use latency inject to increase the latency for a stream as a trade-off to reduce buffering.
Workaround: You add the query to the end of the playback URL in the amount of seconds you want to increase the latency. Ex. `&latency=10&buffer=10`
Diagnose: You can add a query to the end of the playback url.
Workaround: `?video=640x360,1m&pswait&trackcount=9`
# Playback
Source: https://docs.livepeer.org/v1/references/knowledge-base/playback
Diagnose: This is due to the low latency playback feature using WebRTC. If
there are bframes in the stream, the default behavior is to fallback to HLS
playback, which means a slight increase in latency. Workaround: In the
settings of the gateway, turn off the use of frames. If using OBS, select
Livepeer as the service for the video settings.
[https://docs.livepeer.org/guides/developing/stream-via-obs#input-your-stream-settings](https://docs.livepeer.org/guides/developing/stream-via-obs#input-your-stream-settings)
Diagnose: Reconnection: If a stream is down, attempt to retry for that stream
from other nodes nearby until there is a connection(using Livepeer player)
Workaround: Implement a retry logic or switch over to the Livepeer player with
the SDK or iframe embedded player.
Diagnose: We do not support pagination yet but it is a pending feature. You can use the playbackId as a workaround.
Workaround: A short term workaround could be to "paginate" by playbackId instead.
* First list all playback ids with: `/api/data/views/query?breakdownBy[]=playbackId`
* then viewers by playbackId with `/api/data/views/query?playbackId=&breakdownBy[]=viewerId`
Diagnose: Yes, you can use the iframe embedded player and set the width and
height in the iframe tag, however the best way to do this is to use the aspect
ratio.
There are two solutions to accomplish this:
1. If you are using react component, you can pass `lowLatency="force"` to the player component.
You can
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
2. If you are using the iframe embedded player, you can add `lowLatency=true` to
the query string. `lvpr.tv/?v={playbackid}&lowLatency=true`
You can use a poster image by default for a player, then, when playback info API returns the thumbnail url, you can start to use dynamic thumbnail for preview.
Here is how to set up a poster image in Player:
You can set the poster image for a video by utilizing the poster property in Livepeer’s Player component. This property can take either an image URL or a React component as its value.
To set the poster image with a URL, you can use the following code example:
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Player } from "@livepeer/react";
function PlayerComponent() {
return (
);
}
```
If you prefer using a React component, then you can create an image component
and pass it as a value to the poster property. Here is a code example that
illustrates how you can do this:
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
=
import { Player } from "@livepeer/react";
import Image from "next/image";
import yourPosterImage from "./images/your-image-file.png";
const PosterImageComponent = () => {
return (
);
};
function PlayerComponent() {
return (
}
/>
);
};
```
# Vod
Source: https://docs.livepeer.org/v1/references/knowledge-base/vod
Diagnose: The playback format is HLS and for any asset that is \< 2 minutes is MP4.
Workaround: N/A
Diagnose: You can use our webhook to get the status of an asset while it is
being uploaded. Workaround: You can use these events for asset statuses:
`asset.created` `asset.updated` `asset.ready` `asset.failed` `asset.deleted`
[https://docs.livepeer.org/guides/developing/listen-for-webhooks#request](https://docs.livepeer.org/guides/developing/listen-for-webhooks#request)
Diagnose: A new asset with a different Id will be created. Workaround: N/A
Diagnose: Check to make sure that the asset is not using access control.
Workaround: Check the playback information of the asset and make sure that the playback policy is set to `null` or `public`. Use the API endpoint to check: `https://livepeer.studio/api/playback/Playback_Id`
Diagnose: Anything with more than 1 video track will be reduced to 1 video
track. Workaround: N/A
Diagnose: Any other tracks and data types (subtitles/captions, metadata, track
titles, chapter data, etc) will be removed. Workaround: N/A
Diagnose: If the error specifies 401 or 403, this is indicating that there is
an issue with the credentials of your storage. Workaround: Make sure that the
storage credentials allow for both reading and writing to it.
Diagnose: If you close or refresh the page the video is being uploaded, this
can cause the asset to fail. Workaround: Do not refresh or close the page when
uploading with the Livepeer Studio dashboard, otherwise, it will cause the
asset to fail
Diagnose: Check to see if the asset had codecs that are being supported.
Workaround: No support for assets using VP9 codec in an MP4 container see our
[support matrix](https://docs.livepeer.org/references/api-support-matrix).
Diagnose: Make sure the asset is not over the size limit. Workaround: Only up
to 30GB file size is supported
Diagnose: Make sure that the amount of uploads is not exceeding the limit.
Workaround: Limited to 20 uploads at a time with 5 assets processing at the
same time
Diagnose: You can fetch usage of storage in a given time frame using the API
Workaround:
[https://livepeer.studio/data/usage/query?from=UNIX\_TIMESTAMP\_MILLISECONDS\&to=UNIX\_TIMESTAMP\_MILLISECONDS](https://livepeer.studio/data/usage/query?from=UNIX_TIMESTAMP_MILLISECONDS\&to=UNIX_TIMESTAMP_MILLISECONDS)
# Go
Source: https://docs.livepeer.org/v1/sdks/go
Learn how to create your first stream using the Livepeer Go SDK.
To get the most out of this guide, you’ll need to:
* [Create an API key](https://livepeer.studio/dashboard/developers/api-keys)
Get the Livepeer Go SDK.
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
go get github.com/livepeer/livepeer-go
```
The first step is to initialize the SDK with your Livepeer Studio API key.
```go theme={"theme":{"light":"github-light","dark":"dark-plus"}}
package main
import (
"context"
livepeer "github.com/livepeer/livepeer-go"
"github.com/livepeer/livepeer-go/models/components"
"log"
)
func main() {
lpClient := livepeer.New(
livepeer.WithSecurity(""),
)
}
```
Now that you have the SDK installed and initialized, you can use it in your app.
Let's create a stream.
```go theme={"theme":{"light":"github-light","dark":"dark-plus"}}
package main
import (
"context"
livepeer "github.com/livepeer/livepeer-go"
"github.com/livepeer/livepeer-go/models/components"
"log"
)
func main() {
lpClient := livepeer.New(
livepeer.WithSecurity(""),
)
ctx := context.Background()
res, err := lpClient.Stream.Create(ctx, components.NewStreamPayload{
Name: "test_stream",
})
if err != nil {
log.Fatal(err)
}
if res.Stream != nil {
log.Printf("Stream created successfully")
}
}
```
See an example on GitHub.
## Next steps
Checkout Livepeer [API Reference](/api-reference) to learn more about the
Livepeer API and the Go SDK.
# SDKs
Source: https://docs.livepeer.org/v1/sdks/introduction
Explore developer SDKs, pre-built UI components, and tools for interacting with the Livepeer Studio API.
## Server-side SDKs
Server-side SDKs reduce the amount of work required to use the Livepeer Studio
API. Install a language-specific SDK into your application, initialize with your
API key and get started with just 2 lines of code.
## React Components
Build with composable React primitives for both broadcasting and playback.
Fully customizable video player component for seamless playback
Full-featured broadcast component with controls, settings, and device
selection
# JavaScript
Source: https://docs.livepeer.org/v1/sdks/javascript
Learn how to create your first stream using the Livepeer Javascript SDK.
To get the most out of this guide, you’ll need to:
* [Create an API key](https://livepeer.studio/dashboard/developers/api-keys)
Get the Livepeer Javascript SDK.
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
npm install livepeer
```
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
yarn add livepeer
```
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
pnpm install livepeer
```
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
bun install livepeer
```
The first step is to initialize the SDK with your Livepeer Studio API key.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Livepeer } from "livepeer";
const livepeer = new Livepeer({
apiKey: "", // Your API key
});
```
Now that you have the SDK installed and initialized, you can use it in your app.
Let's create a stream.
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Livepeer } from "livepeer";
const livepeer = new Livepeer({
apiKey: "",
});
const main = async () => {
const { stream } = await livepeer.stream.create({
name: "Hello from JS SDK!",
});
console.log(stream);
};
main();
```
See the full example on GitHub.
## Next steps
Checkout Livepeer [API Reference](/api-reference) to learn more about the
Livepeer API and the Javascript SDK.
# Python
Source: https://docs.livepeer.org/v1/sdks/python
Learn how to create your first stream using the Livepeer Python SDK.
To get the most out of this guide, you’ll need to:
* [Create an API key](https://livepeer.studio/dashboard/developers/api-keys)
Get the Livepeer Python SDK.
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
pip install git+https://github.com/livepeer/livepeer-python.git
```
The first step is to initialize the SDK with your Livepeer Studio API key.
```python theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import livepeer
from livepeer.models import components
lpClient = livepeer.Livepeer(
api_key="",
)
```
Now that you have the SDK installed and initialized, you can use it in your app.
Let's create a stream.
```python theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import livepeer
from livepeer.models import components
lpClient = livepeer.Livepeer(
api_key="",
)
req = components.NewStreamPayload(
name='test_stream',
)
res = s.stream.create(req)
if res.stream is not None:
# handle response
pass
```
See an example on GitHub.
## Next steps
Checkout Livepeer [API Reference](/api-reference) to learn more about the
Livepeer API and the Javascript SDK.
# Getting Started
Source: https://docs.livepeer.org/v1/sdks/react/getting-started
Get started building with Livepeer React
Livepeer React is a set of prebuilt and customizable UI primitives for building
live or on-demand video experiences.
## Installation
Install Livepeer React using your favorite package manager.
```
npm i @livepeer/react
```
## Build with the primitives
You can use `Player` primitives to build a media playback experience, and
`Broadcast` primitives to build an in-browser broadcasting experience.
Below, we create a simple player and broadcast experience with minimal controls.
The player only includes a play/pause button, and the broadcast has a start/stop
streaming button.
## Integrate with Studio
Now that we've started using the primitives, we need something to play or
broadcast! We can integrate with the Livepeer Studio API to start playing media.
The below example shows the use of the `livepeer` JS SDK, but any other
language's SDK can be used to fetch the playback info or stream object.
```ts theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// this is a server function, which uses the API key
// on the backend
import { Livepeer } from "livepeer"
import { getSrc } from "@livepeer/react/external";
const livepeer = new Livepeer({
apiKey: "YOUR_API_KEY"
})
export async function getSourceForPlaybackId(playbackId: string) {
const response = await livepeer.playback.get(playbackId);
// the return value can be passed directly to the Player as `src`
return getSrc(response.playbackInfo);
}
```
```ts theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// this is a server function, which uses the API key
// on the backend
import { Livepeer } from "livepeer"
import { getIngest } from "@livepeer/react/external";
const livepeer = new Livepeer({
apiKey: "YOUR_API_KEY"
})
export async function getIngestUrlForStreamId(streamId: string) {
const stream = await livepeer.stream.get(streamId);
// the return value can be passed directly to the Broadcast as `ingestUrl`
return getIngest(stream.stream);
}
```
Want to learn more? Continue reading the documentation for more details.
# Container
Source: https://docs.livepeer.org/v1/sdks/react/player/Container
The `Container` component is the container element for the Player. It wraps all other elements and acts as an aspect ratio container by default.
The `Container` component acts as the container div element for the Player,
using either
[@radix-ui/react-aspect-ratio](https://www.radix-ui.com/primitives/docs/components/aspect-ratio)
or a standard div element. It selectively renders one of these based on the
presence of an `aspectRatio` prop. We show above how to disable the aspect
ratio element.
## Features
* Provides an aspect ratio container to reduce
[Cumulative Layout Shift](https://web.dev/cls/)
* Dynamic data attributes for custom styling based on the current media state
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
export default () => (
{/* Place child elements here, like Video and Controls */}
{/* Or place other controls outside of here, to not be bound by the aspect ratio Container */}
);
```
## Data Attributes
These attributes are dynamically updated based on the current state.
### `data-livepeer-aspect-ratio` or `data-livepeer-wrapper`
Indicates the container type. It's present if the container is an aspect ratio
container (with `data-livepeer-aspect-ratio`) or a regular div (with
`data-livepeer-wrapper`).
When `aspectRatio` is set to `null` on the Root component, then it will be a
regular div wrapper with `position: relative`.
### `data-fullscreen`
Reflects whether the content is in fullscreen mode.
* `"true"`: The content is in fullscreen mode.
* `"false"`: The content is not in fullscreen mode.
### `data-playing`
Indicates if the content is currently playing.
* `"true"`: The content is playing.
* `"false"`: The content is not playing.
### `data-can-play`
Shows if the content can be played.
* `"true"`: The content can be played.
* `"false"`: The content cannot be played due to some restrictions or lack of
data.
### `data-playback-rate`
Displays the current playback rate.
* `"normal"`: The playback is at normal speed.
* `"fast"`: The playback is at a speed faster than normal.
* `"slow"`: The playback is at a speed slower than normal.
* `"constant"`: The playback rate is constant (neither fast nor slow).
### `data-error`
Indicates if there is an error in the content.
* `"true"`: There is an error in the content.
* `"false"`: There are no errors in the content.
### `data-loading`
Shows if the content is loading.
* `"true"`: The content is loading.
* `"false"`: The content is not loading.
### `data-live`
Indicates if the content is live.
* `"true"`: The content is live.
* `"false"`: The content is not live.
### `data-has-played`
Reflects if the content has been played.
* `"true"`: The content has been played at least once.
* `"false"`: The content has not been played yet.
### `data-controls-hidden`
Shows if the controls are hidden.
* `"true"`: The controls are hidden.
* `"false"`: The controls are visible.
### `data-picture-in-picture`
Indicates if the picture-in-picture mode is active.
* `"true"`: The picture-in-picture mode is active.
* `"false"`: The picture-in-picture mode is not active.
### `data-video-quality`
Displays the current video quality, directly reflecting the `videoQuality` value
from the state. It can be a string indicating the quality level (e.g., `"720p"`,
`"1080p"`).
# Error
Source: https://docs.livepeer.org/v1/sdks/react/player/Error
The `ErrorIndicator` component is a visual representation of error states in media playback based on error types.
The `Error` component can be shown for all error types, or a subset of them.
It is usually recommended to be more granular in the error types, since some
errors are more "fatal" and some cannot be recovered from.
## Features
* Conditional rendering based on the error state, customizable with the
`matcher` pattern
* Dynamic data attributes for custom styling based on the current error state
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
export default () => (
);
```
## Props
The component accepts all props suitable for a div element, in addition to the
following specific props:
### `forceMount`
A boolean to force the component's presence in the DOM, useful for controlling
animations with external libraries.
### `matcher`
A prop to define the condition under which the `ErrorIndicator` should be
visible. It can be a string indicating a broad category of errors (like `"all"`
or `"not-permissions"`) or a more specific error type. Alternatively, it can be
a function for custom logic, receiving the PlaybackError type and returning a
boolean for whether it should be shown.
## Data Attributes
### `data-livepeer-error-indicator`
Always present to indicate the component's role.
### `data-error-state`
Indicates whether there is an error (`"true"` or `"false"`).
### `data-error-type`
Specifies the type of the current error or `"none"` if no error is present.
Could be one of:
`"offline" | "access-control" | "fallback" | "permissions" | "unknown" | "none"`
### `data-visible`
Reflects whether the indicator is currently visible (`"true"` or `"false"`).
This is often used for dynamically applying enter/exit CSS animations.
# Root
Source: https://docs.livepeer.org/v1/sdks/react/player/Root
The `Player.Root` component is the React Context wrapper for the Player.
This is a comprehensive example of how the Player elements can fit together to
build an advanced video player. This does not only show the Root Player, but
how the Root can be used to provide a state store to all of its children.
## Features
* Pure React Context provider to pass the media store state to all components
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
export default () => (
{/* All child components which use the state store. */}
);
```
## Compatibility
The compatibility table below applies to the Player broadly, since the Root
component is only a React context.
| Browser | Version |
| ------------------ | ------- |
| Chrome | 102+ |
| Chrome for Android | 105+ |
| iOS Safari | 12.2+ |
| Edge | 103+ |
| Safari | 13.1+ |
| Firefox | 103+ |
| Opera | 89+ |
| Samsung Internet | 17+ |
| UC Browser | 13.4+ |
| Firefox Android | 104+ |
| Opera Mini | all |
We aim to support
[\~93%](https://browsersl.ist/#q=last+2+versions%2C%3E+0.2%25%2Cnot+dead) of
browsers tracked on [caniuse](https://caniuse.com/). We use
[browserslist](https://browsersl.ist/) to track compatibility.
## Usage
The `Player.Root` component is a React Context wrapper which passes the player
state store down to all of the child components. It is responsible for creating
the [Zustand](https://github.com/pmndrs/zustand) state store which is consumed
by the children, and listens for media/browser events and keeps state in sync.
The Player automatically handles different source types, such as WebRTC, MP4, and HLS.
These are seamlessly integrated so that playback has low latency under all
network conditions.
It is compatible with WebRTC WHEP endpoints, HLS (and low latency HLS), or
typical media file playable by an HTML5 video element (MP4, WebM).
## Props
### `src`
Defines the source for the Player. It accepts `Src[]`, which can be derived from
various sources like Livepeer playback info, Cloudflare stream data, Mux URLs,
or simple strings.
See `getSrc` for docs on how to easily generate this parameter.
### `autoPlay` and `volume`
Sets the video to autoplay when the content comes into focus on the webpage. If
`autoPlay` is specified, `volume` is highly recommended to be set to 0.
Autoplay will not work
[in many modern browsers](https://developer.chrome.com/blog/autoplay/) without
setting mute to 0.
### `aspectRatio`
Specifies the aspect ratio of the content. Recommended for an optimal
broadcasting experience to minimize
[Cumulative Layout Shift](https://web.dev/cls/). The default value is `16 / 9`.
Set to `null` to disable the aspect ratio container (see `Container`).
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{...}
```
### `hotkeys`
Enables keyboard hotkeys for controlling the player. Enabled by default
(`true`). It's recommended to follow ARIA guidelines by keeping this enabled
unless you're implementing custom hotkeys or there's a conflict with existing
ones.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{...}
```
### `viewerId`
Sets the viewer ID for the broadcast, useful for metrics and viewership API
integration.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{...}
```
### `onError`
An optional callback for handling broadcasting errors. It's called with `null`
when the previous error is resolved. The callback receives the parameter:
```ts theme={"theme":{"light":"github-light","dark":"dark-plus"}}
type PlaybackError = {
type: "offline" | "access-control" | "fallback" | "permissions" | "unknown";
message: string;
};
```
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
console.log(error)}>{...}
```
### `jwt` or `accessKey`
These define ways to play back a video which has a playback policy applied to
it. Your application can prevent playback unless the user meets
application-specific requirements. This can be done either with JWTs or
webhooks.
Defines the JSON Web Token (JWT) or access key used to access media gated by a
`jwt` or `webhook` playback policy respectively. It's crucial for implementing
application-specific access control like restricting viewership based on certain
criteria (e.g., having an activated account, etc.).
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{...}{...}
```
### `lowLatency`
Enables low-latency playback for live streams via WebRTC by default. If set to
`"force"`, it forces WebRTC playback and disables fallback to HLS. This is ideal
for applications requiring low latency and can tolerate possible connectivity
issues inherent to WebRTC.
Defaults to `true`. If this does not succeed in playing back (commonly due to a
slow network or connectivity issues), the Player will automatically fall back to
HLS playback. Also, if the stream contains B-frames (bidirectional frames, which
are common for users streaming with OBS or other streaming apps), the Player
will automatically switch to HLS, so that out-of-order frames are not displayed.
OBS users should be instructed to use the Livepeer stream profile, or to
manually turn off B-frames in their stream. See our [Stream from
OBS](/developers/guides/stream-via-obs) docs for more information.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{...}
```
### `timeout`
Sets the timeout duration for playback before switching to the next source,
including SDP negotiation for WebRTC, waiting for WebRTC to play, and server
responses. The default is 10000 milliseconds.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{...}
```
### `storage`
Configures the storage option for saving persistent states like volume and video
quality. The default is `localStorage` in the browser. Set to `null` to disable
storage.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{...}
```
# Video
Source: https://docs.livepeer.org/v1/sdks/react/player/Video
The `Video` component renders the actual video content and manages various aspects of media playback.
#### Features
* Synchronizes state with the HTML5 video element
* Keyboard hotkeys (`←`/`→` to seek, `K` to pause, `M` to toggle mute, `F`
fullscreen, `I` picture-in-picture)
* Adheres to [WAI-ARIA](https://w3c.github.io/aria/) design patterns
### Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
export default () => (
);
```
## Props
The component accepts most props suitable for a HTML5 `video` tag, except for
`src`, `poster`, `autoPlay`, and `preload`, which are managed internally or
provided explicitly through props.
### `poster`
Optional. Controls the poster source. By default, it uses the thumbnail from the
`Root` src input. Set to `null` to disable the default poster image from the
`Root` src.
### `hlsConfig`
Optional. Controls the HLS.js config. By default, it adds JWT or Access Token
headers to HLS segment requests.
## Data Attributes
### `data-livepeer-video`
Serves to identify the component's role within the Player.
### `data-livepeer-source-type`
Indicates the type of the current source, such as "none" when there's no source,
or other types based on the media being played.
This can be of the type: `"audio" | "video" | "hls" | "webrtc" | "none"`
# Audio To Text
Source: https://docs.livepeer.org/v1/ai/api-reference/audio-to-text
post /audio-to-text
Transcribe audio files to text.
The default Gateway used in this guide is the public
[Livepeer.cloud](https://www.livepeer.cloud/) Gateway. It is free to use but
not intended for production-ready applications. For production-ready
applications, consider using the [Livepeer Studio](https://livepeer.studio/)
Gateway, which requires an API token. Alternatively, you can set up your own
Gateway node or partner with one via the `ai-video` channel on
[Discord](https://discord.gg/livepeer).
Please note that the exact parameters, default values, and responses may vary
between models. For more information on model-specific parameters, please
refer to the respective model documentation available in the [audio-to-text
pipeline](/ai/pipelines/audio-to-text). Not all parameters might be available
for a given model.
# Image To Image
Source: https://docs.livepeer.org/v1/ai/api-reference/image-to-image
post /image-to-image
Apply image transformations to a provided image.
The default Gateway used in this guide is the public
[Livepeer.cloud](https://www.livepeer.cloud/) Gateway. It is free to use but
not intended for production-ready applications. For production-ready
applications, consider using the [Livepeer Studio](https://livepeer.studio/)
Gateway, which requires an API token. Alternatively, you can set up your own
Gateway node or partner with one via the `ai-video` channel on
[Discord](https://discord.gg/livepeer).
Please note that the exact parameters, default values, and responses may vary
between models. For more information on model-specific parameters, please
refer to the respective model documentation available in the [image-to-image
pipeline](/ai/pipelines/image-to-image). Not all parameters might be available
for a given model.
# Image To Text
Source: https://docs.livepeer.org/v1/ai/api-reference/image-to-text
post /image-to-text
Transform image files to text.
The default Gateway used in this guide is the public
[Livepeer.cloud](https://www.livepeer.cloud/) Gateway. It is free to use but
not intended for production-ready applications. For production-ready
applications, consider using the [Livepeer Studio](https://livepeer.studio/)
Gateway, which requires an API token. Alternatively, you can set up your own
Gateway node or partner with one via the `ai-video` channel on
[Discord](https://discord.gg/livepeer).
Please note that the exact parameters, default values, and responses may vary
between models. For more information on model-specific parameters, please
refer to the respective model documentation available in the [image-to-text
pipeline](/ai/pipelines/image-to-text). Not all parameters might be available
for a given model.
# Image To Video
Source: https://docs.livepeer.org/v1/ai/api-reference/image-to-video
post /image-to-video
Generate a video from a provided image.
The default Gateway used in this guide is the public
[Livepeer.cloud](https://www.livepeer.cloud/) Gateway. It is free to use but
not intended for production-ready applications. For production-ready
applications, consider using the [Livepeer Studio](https://livepeer.studio/)
Gateway, which requires an API token. Alternatively, you can set up your own
Gateway node or partner with one via the `ai-video` channel on
[Discord](https://discord.gg/livepeer).
Please note that the exact parameters, default values, and responses may vary
between models. For more information on model-specific parameters, please
refer to the respective model documentation available in the [image-to-video
pipeline](/ai/pipelines/image-to-video). Not all parameters might be available
for a given model.
# LLM
Source: https://docs.livepeer.org/v1/ai/api-reference/llm
post /llm
Generate text using a language model.
The LLM pipeline is OpenAI API-compatible but does **not** implement all
features of the OpenAI API.
The default Gateway used in this guide is the public
[Livepeer.cloud](https://www.livepeer.cloud/) Gateway. It is free to use but
not intended for production-ready applications. For production-ready
applications, consider using the [Livepeer Studio](https://livepeer.studio/)
Gateway, which requires an API token. Alternatively, you can set up your own
Gateway node or partner with one via the `ai-video` channel on
[Discord](https://discord.gg/livepeer).
### Streaming Responses
Ensure your client supports SSE and processes each `data:` line as it arrives.
By default, the `/llm` endpoint returns a single JSON response in the OpenAI
[chat/completions](https://platform.openai.com/docs/api-reference/chat/object)
format, as shown in the sidebar.
To receive responses token-by-token, set `"stream": true` in the request body.
The server will then use **Server-Sent Events (SSE)** to stream output in real
time.
Each streamed chunk will look like:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
data: {
"choices": [
{
"delta": {
"content": "...token...",
"role": "assistant"
},
"finish_reason": null
}
]
}
```
The final chunk will have empty content and `"finish_reason": "stop"`:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
data: {
"choices": [
{
"delta": {
"content": "",
"role": "assistant"
},
"finish_reason": "stop"
}
]
}
```
# Introduction
Source: https://docs.livepeer.org/v1/ai/api-reference/overview
Learn more about Livepeer's AI API.
Welcome to the Livepeer AI API reference docs! Here you'll find all the
endpoints exposed on the standard Livepeer AI API, learn how to use them and
what they return.
The Livepeer API is organized around REST, has predictable resource-oriented
URLs, accepts JSON request bodies, returns JSON-encoded responses, and uses
standard HTTP response codes, authentication, and verbs.
There are multiple gateway providers active in the ecosystem that can be used to
interact with the Livepeer AI network. For more details, visit the
[AI Gateways](/ai/builders/gateways) page.
# Segment Anything 2
Source: https://docs.livepeer.org/v1/ai/api-reference/segment-anything-2
post /segment-anything-2
Segment objects in an image.
The default Gateway used in this guide is the public
[Livepeer.cloud](https://www.livepeer.cloud/) Gateway. It is free to use but
not intended for production-ready applications. For production-ready
applications, consider using the [Livepeer Studio](https://livepeer.studio/)
Gateway, which requires an API token. Alternatively, you can set up your own
Gateway node or partner with one via the `ai-video` channel on
[Discord](https://discord.gg/livepeer).
Please note that the exact parameters, default values, and responses may vary
between models. For more information on model-specific parameters, please
refer to the respective model documentation available in the
[segment-anything-2 pipeline](/ai/pipelines/segment-anything-2). Not all
parameters might be available for a given model.
# Text To Image
Source: https://docs.livepeer.org/v1/ai/api-reference/text-to-image
post /text-to-image
Generate images from text prompts.
The default Gateway used in this guide is the public
[Livepeer.cloud](https://www.livepeer.cloud/) Gateway. It is free to use but
not intended for production-ready applications. For production-ready
applications, consider using the [Livepeer Studio](https://livepeer.studio/)
Gateway, which requires an API token. Alternatively, you can set up your own
Gateway node or partner with one via the `ai-video` channel on
[Discord](https://discord.gg/livepeer).
Please note that the exact parameters, default values, and responses may vary
between models. For more information on model-specific parameters, please
refer to the respective model documentation available in the [text
pipeline](/ai/pipelines/text-to-image). Not all parameters might be available
for a given model.
# Text To Speech
Source: https://docs.livepeer.org/v1/ai/api-reference/text-to-speech
post /text-to-speech
Generate a text-to-speech audio file based on the provided text input and speaker description.
The default Gateway used in this guide is the public
[Livepeer.cloud](https://www.livepeer.cloud/) Gateway. It is free to use but
not intended for production-ready applications. For production-ready
applications, consider using the [Livepeer Studio](https://livepeer.studio/)
Gateway, which requires an API token. Alternatively, you can set up your own
Gateway node or partner with one via the `ai-video` channel on
[Discord](https://discord.gg/livepeer).
Please note that the exact parameters, default values, and responses may vary
between models. For more information on model-specific parameters, please
refer to the respective model documentation available in the [text-to-speech
pipeline](/ai/pipelines/text-to-speech). Not all parameters might be available
for a given model.
# Upscale
Source: https://docs.livepeer.org/v1/ai/api-reference/upscale
post /upscale
Upscale an image by increasing its resolution.
The default Gateway used in this guide is the public
[Livepeer.cloud](https://www.livepeer.cloud/) Gateway. It is free to use but
not intended for production-ready applications. For production-ready
applications, consider using the [Livepeer Studio](https://livepeer.studio/)
Gateway, which requires an API token. Alternatively, you can set up your own
Gateway node or partner with one via the `ai-video` channel on
[Discord](https://discord.gg/livepeer).
Please note that the exact parameters, default values, and responses may vary
between models. For more information on model-specific parameters, please
refer to the respective model documentation available in the [upscaling
pipeline](/ai/pipelines/upscale). Not all parameters might be available for a
given model.
# AI Gateways
Source: https://docs.livepeer.org/v1/ai/builders/gateways
There are multiple AI gateways available in the Livepeer ecosystem that you can
use to interact with the Livepeer AI network. Each gateway has its own unique
features and capabilities. Here are some of the gateways that you can use to
interact with the Livepeer AI network.
}
>
The Livepeer Cloud Community Gateway, offered by [Livepeer Cloud
SPE](https://www.livepeer.cloud/), provides an effortless and free way to
experiment with the Livepeer AI network.
}
>
The [Livepeer Studio](https://livepeer.studio/) Gateway is a
production-ready solution for interacting with the Livepeer AI network,
offering advanced tools and resources for developers.
# Building on Livepeer AI
Source: https://docs.livepeer.org/v1/ai/builders/get-started
Livepeer AI, now in its **Beta** phase, is fully operational and already
powering a diverse range of cutting-edge [applications](/ai/builders/showcase).
Developers are actively building on the platform, with a rapidly growing
community. While the network continues to evolve with frequent updates, its
stable foundation offers an exciting space for innovation. With a variety of
[easy-to-use client SDKs](/ai/sdks/overview), developers can dive in and start
shaping the future of AI-powered solutions.
Discover the available AI pipelines.
Explore developer SDKs for interacting with the Livepeer AI API.
Choose an AI Gateway to interact with the AI Subnet.
Explore and interact with the Livepeer AI API.
Explore projects built on Livepeer AI.
# Showcase
Source: https://docs.livepeer.org/v1/ai/builders/showcase
If you would like your project to be featured, please contact us at
[ai@livepeer.org](mailto:ai@livepeer.org).
Several
[startups](https://mirror.xyz/livepeer.eth/XcpTZyAkc40kdQMGHZ7prAO7gnB2S1y45iacMtdzrII),
applications, and projects have been developed using Livepeer AI. Below are a
few that have agreed to be featured.
A mobile app that enables anyone to create **stunning gif expressions** with
generative AI, powered by the Livepeer network.
An open-source platform, built on **Stability-AI/StableStudio**, designed for
experimenting with all pipelines on the AI Subnet.
Create images and videos for **free** on the Livepeer network with this generator.
A robust open-source tool for testing and comparing the complete feature set
of Livepeers AI pipeline - including custom-built **experimental features**.
# Get Started
Source: https://docs.livepeer.org/v1/ai/contributors/coming-soon
Amazing that you decided to join our open-source community and help us
democratize AI! 🎉
All our software is open-source, and anyone can permissionlessly add their AI
compute job to the Livepeer network. We have a strong developer community with a
[core developer group](https://github.com/livepeer/project-management) and tens
of open-source developers. The best way to get in touch with this community and
start developing is by joining our [Discord](https://discord.gg/livepeer).
We also offer multiple opportunities for developers to get rewarded for their
contributions, such as our
[grants program](https://livepeer.notion.site/Livepeer-Grants-Program-f91071b5030d4c31ad4dd08e7c026526),
[software bounty program](https://github.com/livepeer/bounties), and
[bug bounty program](https://immunefi.com/bug-bounty/livepeer/information/) for
security researchers.
Let's build something amazing together! 🚀
Contribution guidelines are coming soon. In the meantime, join the `ai-video`
channel on the [Livepeer Discord](https://discord.gg/livepeer) for any
questions or assistance. Let's build something amazing together! 🚀
# Get Started
Source: https://docs.livepeer.org/v1/ai/gateways/get-started
If you're interested in joining Livepeer AI as a **Gateway** (formerly known as
a *Broadcaster*) to perform **AI inference task routing** and provide inference
services to customers, this guide is for you. It builds on the
[Gateway Setup Guide](/gateways/guides/gateway-overview) for the Mainnet
Transcoding Network, with additional steps specific to AI operations.
Dive into the **subpages** for a step-by-step walkthrough of the AI-specific
setup. For foundational knowledge on general Gateway operations, refer to the
[Gateway Setup Guide](/gateways/guides/gateway-overview). This guide extends it
with the steps needed for AI task routing.
Visit the Gateway Setup Guide for detailed instructions on setting up a
Gateway node on the Mainnet Transcoding Network.
## Prerequisites
Before you begin setting up your AI Gateway node, ensure you have:
* A [Linux](https://ubuntu.com/download/desktop) system (Support for Windows and
macOS coming soon)
* Root user access to the system
# Onchain
Source: https://docs.livepeer.org/v1/ai/gateways/onchain
### On-chain Setup
In the previous section, we covered the **off-chain** configuration of your AI
Gateway node. This section will explain how to connect your AI Gateway to the
Livepeer AI network to start requesting AI inference jobs **on-chain**.
## Prerequisites
* A dedicated static IP address or domain name for your AI Gateway node
* A funded Ethereum account with enough ETH to cover gas fees and AI inference
job payments
## Launching your On-chain AI Gateway
Once your AI Gateway is set up **off-chain**, it's time to connect it to the
Livepeer AI network for **on-chain** inference jobs. The process is similar to
setting up a Mainnet Transcoding Network Gateway, with a few extra flags
specific to Livepeer AI. You can refer to the
[Mainnet Transcoding Network Gateway](/gateways/guides/gateway-overview) guide
for more information. Here’s a summary of the key steps:
Ensure your AI Gateway node is functioning correctly **off-chain** before connecting it to the Livepeer AI network. Refer to [the previous section](/ai/gateways/start-gateway) for details.
Make sure your Ethereum account has enough ETH to cover gas fees and AI inference job payments. For more details, see the [Fund Gateway Guide](/gateways/guides/fund-gateway).
Deposit enough funds into your AI Gateway to cover the **deposit** and **reserve** needed for AI inference requests. Follow the steps in the [Deposit Gateway Funds via Livepeer CLI](/gateways/guides/fund-gateway#deposit-gateway-funds-via-livepeer-cli) guide.
Configure transcoding options even though the AI Gateway doesn’t handle transcoding, due to current Livepeer AI software requirements. See the [Transcoding Options](/gateways/guides/transcoding-options) guide for more information.
Now launch your AI Gateway node. The process is similar to the **docker** or **binary** setup in the [previous section](/ai/gateways/start-gateway), but requires additional flags to enable on-chain functionality. Example:
* `-aiServiceRegistry`: Ensures that the Gateway is connected to the Livepeer AI network.
* `-network=arbitrum-one-mainnet`: Connects the AI Gateway to the Arbitrum Mainnet network.
* `-ethUrl=https://arb1.arbitrum.io/rpc`: Sets the Arbitrum Mainnet RPC URL. Replace it with your own if necessary.
* `-ethKeystorePath=/root/.lpData/arbitrum-one-mainnet/keystore`: Sets the path to the Ethereum keystore file for the AI Gateway.
* `-ethAcctAddr `: Sets the Ethereum account address for the AI Gateway.
* `-ethPassword=/root/.lpData/.eth_secret`: Sets the path to the Ethereum keystore password file.
* `-ethOrchAddr=`: Sets the Ethereum address of the Mainnet Transcoding Network Gateway.
* `-maxTotalEV=100000000000000`: Ensures the AI Gateway complies with the max ticket value limits in `go-livepeer`.
* `-maxPricePerUnit=`: This defaults to 0. Set to acceptable max price in wei (or USD, e.g. 0.02USD) willing to pay. Note: this can impact amount of Orchestrators available to process the work.
* `-ignoreMaxPriceIfNeeded=`: This defaults to false. Set to true if want to process requests if no Orchestrators are under maxPricePerUnit or do not want to use a max price.
* `-maxPricePerCapability=/path/to/maxPrices.json`: This flag sets the max price per unit for one or many pipeline/models. Refer to the [Set Max Price Per Pipeline and Model](#set-max-price-per-pipeline-and-model-optional) section for more details.
## Set Max Price Per Pipeline and Model (Optional)
To avoid overpaying for AI inference jobs, you can set a maximum price per unit
for each pipeline and model. This feature is optional and can be configured
using the `-maxPricePerCapability` flag. If a price is not set for a specific
pipeline/model, the `-maxPricePerUnit` price will be used. The flag input should
be a JSON file with the specified max prices. The example below demonstrates the
following configurations:
* Set the price for the `image-to-image` pipeline and model
`ByteDance/SDXL-Lightning` to 1,700,000 wei per unit (pixels).
* Set the price for the `text-to-image` pipeline and model
`stabilityai/stable-diffusion-3-medium-diffusers` to 4,768,371 wei per unit
(pixels).
* Set the price for the `upscale` pipeline for all models to 4,768,371 wei per
unit. The `pixels_per_unit` defaults to `1` if not specified.
* Set the price for the `image-to-video` pipeline for all models to 3,390,842
wei per unit (pixels).
* Set the price for the `audio-to-text` pipeline for all models to 12,882,811
wei per unit (milliseconds of audio).
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"capabilities_prices": [
{
"pipeline": "image-to-image",
"model_id": "ByteDance/SDXL-Lightning",
"price_per_unit": 1700000,
"pixels_per_unit": 1
},
{
"pipeline": "text-to-image",
"model_id": "stabilityai/stable-diffusion-3-medium-diffusers",
"price_per_unit": 4768371,
"pixels_per_unit": 1
},
{
"pipeline": "upscale",
"model_id": "default",
"price_per_unit": 4768371
},
{
"pipeline": "image-to-video",
"price_per_unit": 3390842,
"pixels_per_unit": 1
},
{
"pipeline": "audio-to-text",
"price_per_unit": 12882811
}
]
}
```
# Start gateway
Source: https://docs.livepeer.org/v1/ai/gateways/start-gateway
### Start your AI Gateway
The Livepeer AI network is currently in **Beta** but is already integrated into
the main [go-livepeer](https://github.com/livepeer/go-livepeer) software. 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.
## Start the AI Gateway
Follow the steps below to start your Livepeer AI Gateway node:
Fetch the latest [Livepeer AI Docker image](https://hub.docker.com/r/livepeer/go-livepeer) with the following command:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
docker pull livepeer/go-livepeer:master
```
Run the Docker container for your AI Gateway node:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
docker run \
--name livepeer_ai_gateway \
-v ~/.lpData2/:/root/.lpData2 \
-p 8937:8937 \
--network host \
livepeer/go-livepeer:master \
-datadir ~/.lpData2 \
-gateway \
-orchAddr \
-httpAddr 0.0.0.0:8937 \
-v 6 \
-httpIngest
```
This command launches an **off-chain** AI Gateway node. The flags are similar to those used for a Mainnet Transcoding Network Gateway. See the [go-livepeer CLI reference](/references/go-livepeer/cli-reference) for details.
Upon successful startup, you should see output similar to:
```bash 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:8937
I0501 11:07:47.609963 1 lpms.go:92] LPMS Server listening on rtmp://127.0.0.1:1935
```
Ensure that port `8937` is open and accessible, and configure your router for port forwarding if necessary to make the Gateway accessible from the internet.
Download the latest Livepeer AI binary for your system:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
wget https://build.livepeer.live/go-livepeer/livepeer--.tar.gz
```
Replace `` and `` with your operating system and architecture (e.g., `linux-amd64` for Linux AMD64). For more details, see the [go-livepeer installation guide](/orchestrators/guides/install-go-livepeer#install-using-a-binary-release).
The Windows and MacOS (amd64) binaries of Livepeer AI are not available yet.
Once downloaded, extract the binary to a directory of your choice.
Start the AI Gateway node with the following command:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
./livepeer \
-datadir ~/.lpData2 \
-gateway \
-orchAddr \
-httpAddr 0.0.0.0:8937 \
-v 6 \
-httpIngest
```
This command launches an **off-chain** AI Gateway node. Refer to the [go-livepeer CLI reference](/references/go-livepeer/cli-reference) for more details on the flags.
Check the terminal for the following output to confirm successful startup:
```bash 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:8937
I0501 11:07:47.609963 1 lpms.go:92] LPMS Server listening on rtmp://127.0.0.1:1935
```
Ensure that port `8937` is open and accessible, and configure port forwarding if needed.
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 [Livepeer installation guide](/orchestrators/guides/install-go-livepeer#install-using-a-binary-release) or reach out to the Livepeer community on [Discord](https://discord.gg/livepeer) for assistance.
## Confirm the AI Gateway is Operational
After launching your Livepeer AI Gateway node, verify its operation by sending
an AI inference request. Ensure that the Gateway is connected to an active
**off-chain** AI Orchestrator node. For instructions on setting up an AI
Orchestrator, refer to the
[AI Orchestrator Setup Guide](/ai/orchestrators/get-started).
Start an AI Orchestrator node on port `8936` by following the [AI Orchestrator Setup Guide](/ai/orchestrators/get-started). Ensure that the Orchestrator has loaded the necessary model (e.g., "ByteDance/SDXL-Lightning").
Specify the Orchestrator's address when launching the Gateway. Replace `` with the Orchestrator's address:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
-orchAddr 0.0.0.0:8936
```
To submit an AI inference request, refer to the [AI API reference](/ai/api-reference/text-to-image). For example, to generate an image from text, use the following `curl` command:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -X POST "http://0.0.0.0:8937/text-to-image" \
-H "Content-Type: application/json" \
-d '{
"model_id":"ByteDance/SDXL-Lightning",
"prompt":"A cool cat on the beach",
"width": 1024,
"height": 1024
}'
```
If the request is successful, you should see a response like this:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"images": [
{
"seed": 2562822894,
"url": "https://0.0.0.0:8937/stream/d0fc1fc6/8fdf5a94.png"
}
]
}
```
Refer to the [Text-to-image Pipeline Documentation](/ai/pipelines/text-to-image) for more information.
# What is Livepeer AI?
Source: https://docs.livepeer.org/v1/ai/introduction
The Livepeer AI network is in its **Beta** phase. Bugs or issues may be
encountered. Contributions to improvement are appreciated - please report
problems via the [issue
tracker](https://github.com/livepeer/go-livepeer/issues/new/choose). Feedback
is invaluable for enhancing the Livepeer AI network. Thank you for your
contributions!
Livepeer AI, also known as the **Livepeer AI (Video) Network**, is the first
step toward bringing powerful AI video capabilities into the Livepeer network.
It enables video developers to add a rapidly growing suite of **generative AI
features** such as [text-to-image](/ai/pipelines/text-to-image),
[image-to-image](/ai/pipelines/image-to-image),
[image-to-video](/ai/pipelines/image-to-video), and
[upscaling](/ai/pipelines/upscale) to their applications. Livepeer Node
operators are able to **earn revenue by deploying their GPU resources** for AI
processing tasks. Ready to dive in? Choose one of the cards below to kickstart
your journey with the AI Subnet.
## Kickstart Your Journey
Explore the available AI pipelines.
Set up your AI Orchestrator node and earn fees from AI tasks.
Establish an AI Gateway to serve a broad customer base with AI tasks.
Develop your innovative app on the AI Subnet efficiently and at scale.
Discover projects built on the AI Subnet.
Explore developer SDKs for interacting with the Livepeer AI API.
Choose an AI Gateway to interact with the AI Subnet.
Explore the AI Subnet API to integrate AI capabilities into your projects.
## Background on Livepeer AI
Livepeer AI, initially proposed in
[this SPE treasury proposal](https://explorer.livepeer.org/treasury/82843445347363563575858115586375001878287509193479217286690041153234635982713),
represents a significant evolution within the Livepeer ecosystem. This
**decentralized**, **open-source** framework seamlessly integrates a variety of
**generative image and video AI inference** tasks into the existing Livepeer
network infrastructure. These enhancements strengthen Livepeer's transcoding
services, celebrated for their **low cost** and **high reliability**, while also
paving the way for groundbreaking applications across both emerging Web3
environments and established Web2 sectors.
Designed to revolutionize creative processes, Livepeer AI reflects Livepeer's
commitment to creating a **globally accessible open video infrastructure**. By
striving to **democratize AI**, Livepeer AI empowers users to leverage any form
of image and video compute with advanced AI tools. By equipping video
applications with these tools and reducing reliance on centralized computing
resources, we are dedicated to extending **cutting-edge AI capabilities** to a
broader audience, fostering a more equitable digital landscape. Additionally, we
are committed to
[supporting open-source research](https://livepeer.notion.site/Livepeer-Grants-Program-f91071b5030d4c31ad4dd08e7c026526)
by funding researchers who develop in the open, further driving innovation and
collaboration within the community.
### Advantages of Livepeer AI
* **Decentralization**: Enhances security and resilience by eliminating single
points of failure.
* **Cost-Effectiveness**: Provides AI inference capabilities at a significantly
lower cost compared to traditional cloud services.
* **Scalability**: Easily scales in response to user demand, ensuring reliable
service without interruptions.
* **Open-Source Innovation**: Encourages collaborative development, accelerating
innovation and broadening the range of supported applications.
### How It Works
Livepeer AI, built on the established Livepeer network, leverages a
**decentralized payment infrastructure** for compensating AI orchestrator nodes
for performing AI inference tasks. The network consists of two primary actors:
* **AI Gateway Nodes**: These nodes manage the flow of AI tasks from
applications and users, directing them to the appropriate Orchestrator nodes
based on capability and current load, ensuring efficient task allocation and
system scalability.
* **AI Orchestrator Nodes**: These nodes manage the execution of AI tasks. They
can perform AI inference tasks on GPUs located on the same machine or be
connected to multiple machines with multiple GPUs, known as **AI Worker
Nodes**. The orchestrator or its worker nodes keep AI models
[warm](/ai/pipelines/overview#warm-models) on their GPUs for immediate
processing and can
[dynamically load models](/ai/pipelines/overview#on-demand-models) as tasks
arrive, optimizing both response time and resource utilization.
This architecture is designed for **scalability**, enabling easy integration of
additional Orchestrator and Gateway nodes as demand increases. Under the hood,
it relies on a specialized
[ai-runner Docker](https://hub.docker.com/r/livepeer/ai-runner) image to execute
inference requests on AI models, simplifying deployment and enhancing the
scalability of new pipelines. Ongoing developments aim to enhance
**performance** and **broaden the container's capabilities** to support
increasingly complex AI models and custom user-defined pipelines.
Below is a simplified diagram illustrating the **complete AI inference
pipeline** within Livepeer AI. Only one AI Orchestrator with one GPU on the same
machine is shown for clarity. In reality, the AI Gateway is connected to
multiple Orchestrators, each of which can have multiple worker nodes with
various GPUs attached.
```mermaid theme={"theme":{"light":"github-light","dark":"dark-plus"}}
graph TD
A[AI Gateway Node] -->|Task Routing| B[AI Orchestrator Node]
B -->|Tasks Execution| C[ai-runner Docker Container]
C -->|Uses Pre-loaded Model| D[GPU Ready/Warm Models]
C -->|Dynamically Loads Model| E[GPU On-Demand]
D -->|Perform Inference| G[Task Completion]
E -->|Perform Inference| G
G -->|Return Results| B
B -->|Send Results Back| A
```
This flow starts at the AI Gateway nodes, which route tasks from applications or
users to an appropriate AI Orchestrator node. The selection of the AI
Orchestrator node is based on factors such as the speed of previous inference
requests, orchestrator stake, advertised price, and more. The AI Orchestrator
node then executes the task in the ai-runner Docker Container. In this
container, the AI Orchestrator can either:
* **Pre-load a model**: Orchestrators keep frequently used models
[warm](ai/pipelines/overview#warm-models) on GPUs, speeding up task
processing.
* **Dynamically load a model**: Orchestrators can
[load models on demand](ai/pipelines/overview#on-demand-models), allowing
flexibility to handle various tasks.
During the selection process, to ensure quick response times, Gateways first
check if there are any Orchestrators available with the requested model 'warm'
on their GPU. If not, they route the task to an Orchestrator that can
dynamically load the model. Once the model is loaded, the task is executed on
the GPU, and the results are returned to the Orchestrator node, which then sends
them back to the Gateway node and finally to the application or user that
requested the task. This architecture ensures Livepeer AI is both **efficient**
and **flexible**, ready to scale and adapt to various AI applications.
### Explore AI Pipelines
Livepeer AI hosts a variety of generative AI pipelines, each supporting
different models. Current offerings primarily utilize
[Diffusion models](https://huggingface.co/docs/diffusers/en/index). Plans are in
place to expand support to include other model types in future updates.
Explore the [AI Pipelines](/ai/pipelines) page to learn more about each
pipeline and the models they support.
### Current Limitations and Future Directions
* **Beta Phase**: Livepeer AI is currently in its **Beta** phase, and users may
encounter bugs or issues during this early stage. It is not yet intended for
high-demand production workloads.
* **Limited Set of Open-source Models Supported**: Livepeer AI currently
supports a limited set of open-source AI models and pipelines available on
[Hugging Face](https://huggingface.co/models). However, this range is
gradually expanding with the goal of supporting custom models in the future.
* **High VRAM GPUs Required for Most Pipelines**: Currently, Livepeer AI
requires GPUs with at least 16GB of VRAM to run most AI inference tasks
effectively. For optimal performance and a higher chance of being selected for
jobs, 30/40 series GPUs or comparable models are recommended. The exact GPU
requirements can be found in the documentation for each pipeline on the
[AI Pipelines](/ai/pipelines) page.
### Livepeer AI Terminology
* **Mainnet Transcoding Network**: Comprises **Orchestrator** and **Gateway**
nodes that perform or coordinate transcoding tasks. The **Orchestrator**
handles the supply-side operations, while the **Gateway** handles the
demand-side.
* **Livepeer AI Network**: A specialized subnet within the Livepeer network
designed for managing AI inference tasks, connecting **Providers**,
**Gateways**, **Orchestrators**, and **Workers** in a decentralized manner.
* **Mainnet Transcoding Network Orchestrator**: A node responsible for handling
transcoding jobs within the Mainnet Transcoding Network. The **Orchestrator**
is a supply-side node that coordinates and ensures the completion of
transcoding tasks. This term is distinct from the **Worker**, which executes
the actual compute jobs.
* **Mainnet Transcoding Network Gateway**: A node that acts as the
**clearinghouse** or middleware, responsible for routing transcoding tasks to
the appropriate **Orchestrator** nodes within the Mainnet Transcoding Network.
Often referred to as the **Gateway** (formerly **Broadcaster**), it remains
**stateless**, ensuring it only holds essential information for task routing
and job verification.
* **Provider**: An entity that operates one or more **Gateways**, potentially
with additional services or developer experience (DevX) abstractions layered
on top. **Providers** facilitate demand-side tasks in both the **Mainnet
Transcoding Network** and the **Livepeer AI Network**.
* **Worker**: Formerly referred to as the **Transcoder**, the **Worker** is a
node that executes compute jobs. This can be running on the same machine as
the **Orchestrator** or remotely. In the **Livepeer AI Network**, **Workers**
execute AI inference tasks, while in the **Mainnet Transcoding Network**, they
handle transcoding jobs.
* **AI Orchestrator**: A specialized node within the **Livepeer AI Network**,
responsible for executing AI inference tasks. The **AI Orchestrator** runs the
required software and handles compute jobs for AI tasks, coordinating with
**Workers** when needed.
* **AI Gateway**: A demand-side node within the **Livepeer AI Network**
responsible for directing AI-related tasks to the appropriate **AI
Orchestrator** nodes. Similar to the **Mainnet Gateway**, it does not manage
developer-related tasks (e.g., DevX persistence) and primarily handles job
instruction and verification for AI inference.
# Attach Remote AI Workers
Source: https://docs.livepeer.org/v1/ai/orchestrators/ai-worker
## Introduction
The **AI Worker** is a crucial component of the Livepeer AI network, responsible
for performing AI inference tasks. It can be run as a separate process on
compute machines distinct from the Orchestrator or combined with the
Orchestrator on the same machine.
## Key Setup Considerations
* **Startup Configuration**: If you decide to use separate AI Workers, this
**must** be selected at the Orchestrator's startup. A combined Orchestrator
**cannot** simultaneously support remote AI Workers.
* **Shared Configuration File**: Both the Orchestrator and AI Workers use the
`aiModels.json` file (see
[Configuring AI Models](/ai/orchestrators/models-config)).
* The **Orchestrator** uses `aiModels.json` to set model pricing.
* The **AI Worker** uses it to manage the runner containers for each model.
## Remote AI Worker Setup
When using experimental external runner containers, ensure they connect to the
AI Worker and not directly to the Orchestrator.
In a split configuration, the Orchestrator manages multiple AI Workers and
allocates tasks based on the connected workers' capacity. Worker **capacity** is
determined by the following formula:
```
runner container count per pipeline/model_id = capacity per pipeline/model_id
```
The **Orchestrator's capacity** is the sum of the capacities of all connected AI
Workers. This setup enables flexible scaling of compute resources by adding or
removing AI Workers as needed.
### Launch Commands for Remote AI Worker
Below are the launch commands for both the Orchestrator and AI Worker nodes.
For the full Orchestrator launch command, see [Start Your AI
Orchestrator](/ai/orchestrators/start-orchestrator).
#### Orchestrator Command
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
docker run \
--name livepeer_ai_orchestrator \
...
livepeer/go-livepeer:master \
-orchestrator \
...
-orchSecret
-serviceAddr
```
#### AI Worker Command
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
docker run \
--name livepeer_ai_worker \
...
livepeer/go-livepeer:master \
-aiWorker \
...
-orchSecret \
-orchAddr
```
**Pricing**: Prices in this example may vary and should be adjusted based on
market research and the operational costs of providing compute.
### Configuration Files (`aiModels.json`)
The `aiModels.json` file configures AI model parameters separately for the
Orchestrator and the AI Worker, with each configuration tailored to the specific
needs of that node.
For detailed guidance on configuring `aiModels.json` with advanced model
settings, see [Configuring AI Models](/ai/orchestrators/models-config).
#### Orchestrator Configuration
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
[
{
"pipeline": "text-to-image",
"model_id": "SG161222/RealVisXL_V4.0_Lightning",
"price_per_unit": 4768371,
"pixels_per_unit": 1
}
]
```
#### AI Worker Configuration
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
[
{
"pipeline": "text-to-image",
"model_id": "SG161222/RealVisXL_V4.0_Lightning",
"warm": true,
"optimization_flags": {
"SFAST": true
}
}
]
```
## Verifying Remote AI Worker Operation
After starting your **remote AI Worker** node, you can verify it is operational
by following the same inference test instructions used for the Orchestrator, as
described in the
[Orchestrator Confirmation Section](/ai/orchestrators/start-orchestrator#confirm-combined-ai-orchestrator-operation).
When accessing the AI Runner from a separate machine, replace `localhost` with
the **Worker Node's IP address** in the inference test instructions.
# Perform Benchmarking
Source: https://docs.livepeer.org/v1/ai/orchestrators/benchmarking
To ensure your GPU(s) are performing optimally and to identify any bottlenecks,
you can run a benchmark test. Optimal performance significantly increases your
chances of being selected for jobs, as inference speed is a crucial factor in
the selection process. This guide will show you how to run a benchmark test on
your GPU(s) to determine the best [pipeline/model](/ai/pipelines/overview)
combination to serve on your GPU(s), thereby maximizing your revenue.
## Prerequisites
Before running a benchmarking test, make sure you have met all the
[prerequisites](/ai/orchestrators/get-started#prerequisites) for running an
Orchestrator node.
## Benchmarking Steps
First, pull the latest AI runner Docker image from [Docker Hub](https://hub.docker.com/r/livepeer/ai-runner). This image contains the necessary tools for benchmarking.
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
docker pull livepeer/ai-runner:latest
```
Next, pull any pipeline-specific images if needed. Check the [pipelines](/ai/pipelines/overview) documentation for more information. For example, to pull the image for the [segment-anything-2](/ai/pipelines/segment-anything-2#pipeline-specific-image) pipeline:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
docker pull livepeer/ai-runner:segment-anything-2
```
Download the AI models you want to benchmark. For more information see the [Download AI Models](/ai/orchestrators/models-download) guide.
Run the benchmark test using the following command. This will simulate the pipeline/model combination on your GPU(s) and measure performance.
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
docker run --gpus -v ./models:/models livepeer/ai-runner:latest python bench.py --pipeline --model_id --runs --num_inference_steps --batch_size
```
Example command:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
docker run --gpus '"device=0"' -v ./models:/models livepeer/ai-runner:latest python bench.py --pipeline text-to-image --model_id stabilityai/sd-turbo --runs 3 --batch_size 3
```
In this command, the following parameters are used:
* ``: Specify which GPU(s) to use. For example, `'"device=0"'` for GPU 0, `'"device=0,1"'` for GPU 0 and GPU 1, or `'"device=all"'` for all GPUs.
* ``: The pipeline to benchmark (e.g., `text-to-image`).
* ``: The model ID to use for benchmarking (e.g., `stabilityai/sd-turbo`).
* ``: The number of benchmark runs to perform.
* ``: The number of inference steps to perform (optional).
For benchmarking script usage information:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
docker run livepeer/ai-runner:latest python bench.py -h
```
After running the benchmark, you should see output similar to the following:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
----AGGREGATE METRICS----
pipeline load time: 5.199s
pipeline load max GPU memory allocated: 5.876GiB
pipeline load max GPU memory reserved: 6.043GiB
avg inference time: 7.538s
avg inference max GPU memory allocated: 6.407GiB
avg inference max GPU memory reserved: 6.729GiB
```
This output shows the performance of your GPU(s) and helps you determine the best pipeline/model combination to serve on your GPU(s).
# Get Started
Source: https://docs.livepeer.org/v1/ai/orchestrators/get-started
If you're interested in joining Livepeer AI as an **Orchestrator** to perform
**AI inference** on the Livepeer AI Network and earn fees, this guide is for
you. It is tailored to help you set up an AI Orchestrator node, building upon
the [Orchestrator Setup Guide](/orchestrators/guides/get-started) for the
Mainnet Transcoding Network, but with additional steps for AI operations.
For a step-by-step walkthrough, refer to the **subpages** of this guide. For a
more general understanding of Orchestrator operations, you can consult the
[Orchestrator Setup Guide](/orchestrators/guides/get-started) for the Mainnet
Transcoding Network, as the AI guide extends upon the foundational knowledge
provided there.
Visit the Orchestrator Setup Guide for detailed instructions on setting up an
Orchestrator node on the Mainnet Transcoding Network.
## Prerequisites
Before setting up your AI Orchestrator node, ensure you meet the following
requirements:
* You are operating a Top 100
[Mainnet Orchestrator](/orchestrators/guides/get-started) on the Mainnet
Transcoding Network
* **High VRAM GPUs Required**: Livepeer AI requires GPUs with at least 16GB of
VRAM for most tasks. For optimal performance and higher job selection chances,
30/40 series GPUs or comparable models are recommended. Exact requirements are
in the [AI Pipelines](/ai/pipelines) documentation.
* **[Docker](https://docs.docker.com/engine/install)** is installed on your
machine
* **[CUDA 12.4](https://developer.nvidia.com/cuda-12-4-0-download-archive)** is
installed on your machine
* **[Nvidia Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html)**
is installed on your machine
* You are using a **[Linux](https://ubuntu.com/download/desktop)** system
(Support for Windows and macOS is coming soon)
* You have
**[Python 3.10](https://www.python.org/downloads/release/python-3100/)** or
higher installed (for downloading and managing AI models)
# Configuring AI Models
Source: https://docs.livepeer.org/v1/ai/orchestrators/models-config
Before deploying your AI Orchestrator node on the Livepeer AI network, you must
choose the AI models you want to serve for AI inference tasks. This guide
assists in configuring these models. The following page,
[Download AI Models](/ai/orchestrators/models-download), provides instructions
for their download. For details on supported pipelines and models, refer to
[Pipelines](/ai/pipelines/text-to-image).
## Configuration File Format
Orchestrators specify supported AI models in an `aiModels.json` file, typically
located in the `~/.lpData` directory. Below is an example configuration showing
currently **recommended** models and their respective prices.
Pricing used in this example is subject to change and should be set
competitively based on market research and costs to provide the compute.
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
[
{
"pipeline": "text-to-image",
"model_id": "SG161222/RealVisXL_V4.0_Lightning",
"price_per_unit": 4768371
},
{
"pipeline": "upscale",
"model_id": "stabilityai/stable-diffusion-x4-upscaler",
"price_per_unit": "0.5e-2USD",
"warm": true,
"optimization_flags": {
"SFAST": true,
"DEEPCACHE": false
}
},
{
"pipeline": "audio-to-text",
"model_id": "openai/whisper-large-v3",
"price_per_unit": 12882811,
"pixels_per_unit": 1,
"currency": "USD",
"url": ":",
"token": "",
"capacity": 1
}
]
```
### Key Configuration Fields
During the **Beta** phase, only one "warm" model per GPU is supported.
The inference pipeline to which the model belongs (e.g., `text-to-image`).
The [Hugging Face model
ID](https://huggingface.co/docs/transformers/en/main_classes/model).
The price in [Wei](https://ethdocs.org/en/latest/ether.html) per unit, which
varies based on the pipeline (e.g., per pixel for `image-to-video`).
If `true`, the model is preloaded on the GPU to decrease runtime.
Optional flags to enhance performance (details below).
Optional URL and port where the model container or custom container manager
software is running. [See External Containers](#external-containers)
Optional token required to interact with the model container or custom
container manager software. [See External Containers](#external-containers)
Optional capacity of the model. This is the number of inference tasks the
model can handle at the same time. This defaults to 1. [See External
Containers](#external-containers)
### Optimization Flags
These flags are still **experimental** and may not always perform as expected.
If you encounter any issues, please report them to the [go-livepeer
repository](https://github.com/livepeer/go-livepeer/issues/new/choose).
At this time, these flags are only compatible with **warm** models.
The Livepeer AI pipelines offer a suite of optimization flags. These are
designed to enhance the performance of **warm** models by either increasing
**inference speed** or reducing **VRAM** usage. Currently, the following flags
are available:
#### Image-to-video Pipeline Optimization
The `SFAST` flag enables the [Stable
Fast](https://github.com/chengzeyi/stable-fast) optimization framework,
potentially boosting inference speed by up to **25%** with **no quality
loss**. Cannot be used in conjunction with `DEEPCACHE`.
#### Text-to-image Pipeline Optimization
**DO NOT** enable `DEEPCACHE` for Lightning/Turbo models since they're already
optimized. Due to [known
limitations](https://github.com/horseee/DeepCache/issues/27), it does not
provide speed benefits and may significantly lower image quality.
The `DEEPCACHE` flag enables the
[DeepCache](https://github.com/horseee/DeepCache) optimization framework,
which can enhance inference speed by up to **50%** with **minimal quality
loss**. The speedup becomes more pronounced as the number of inference steps
increases. Cannot be used simultaneously with `SFAST`.
### External Containers
This feature is intended for advanced users. Incorrect setup can lead to a
lower orchestrator score and reduced fees. If external containers are used, it
is the Orchestrator's responsibility to ensure the correct container with the
correct endpoints is running behind the specified `url`.
External containers can be for one model to stack on top of managed model
containers, an auto-scaling GPU cluster behind a load balancer or anything in
between. Orchestrators can use external containers to extend the models served
or fully replace the AI Worker managed model containers using the
[Docker client Go library](https://pkg.go.dev/github.com/docker/docker/client)
to start and stop containers specified at startup of the AI Worker.
External containers can be used by specifying the `url`, `capacity` and `token`
fields in the model configuration. The only requirement is that the `url`
specified responds as expected to the AI Worker same as the managed containers
would respond (including http error codes). As long as the container management
software acts as a pass through to the model container you can use any container
management software to implement the custom management of the runner containers
including [Kubernetes](https://kubernetes.io/), [Podman](https://podman.io/),
[Docker Swarm](https://docs.docker.com/engine/swarm/),
[Nomad](https://www.nomadproject.io/), or custom scripts to manage container
lifecycles based on request volume
* The `url` set will be used to confirm a model container is running at startup
of the AI Worker using the `/health` endpoint. Inference requests will be
forwarded to the `url` same as they are to the managed containers after
startup.
* The `capacity` should be set to the maximum amount of requests that can be
processed concurrently for the pipeline/model id (default is 1). If auto
scaling containers, take care that the startup time is fast if setting
`warm: true` because slow response time will negatively impact your selection
by Gateways for future requests.
* The `token` field is used to secure the model container `url` from
unauthorized access and is strongly suggested to use if the containers are
exposed to external networks.
We welcome feedback to improve this feature, so please reach out to us if you
have suggestions to enable better experience running external containers.
# Download AI Models
Source: https://docs.livepeer.org/v1/ai/orchestrators/models-download
AI Orchestrators on the Livepeer AI network can choose from various AI models to
advertise on the network. A comprehensive list of currently supported models for
each Livepeer AI pipeline is available on the [Pipelines](/ai/pipelines) page.
Before specifying which models to advertise on the Livepeer AI network, you must
first download the models to your machine. The following steps will guide you
through downloading the **recommended** models for Livepeer AI.
Use the following command to install the HuggingFace CLI:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
pip install huggingface_hub
```
Follow the instructions on the [Hugging Face website](https://huggingface.co/docs/hub/en/security-tokens) to generate an access token with **read** permissions. Then, use the Hugging Face CLI to install the token:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
hf auth login
```
You will be prompted to paste the access token you created on the Hugging Face website.
If you have trouble locating `hf` in your path, it may be necessary to add `/home/$USER/.local/bin/` to your local path.
The currently recommended models include one **gated** model. Therefore, you must accept the terms of the [SVD1.1 model](https://huggingface.co/stabilityai/stable-video-diffusion-img2vid-xt-1-1) on its model page before downloading.
Use the following command to download the **recommended** models for Livepeer AI:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
cd ~/.lpData
latest=$(curl -s https://api.github.com/repos/livepeer/ai-runner/releases/latest | grep '"tag_name":' | cut -d'"' -f4)
curl -s https://raw.githubusercontent.com/livepeer/ai-runner/tags/$latest/runner/dl_checkpoints.sh | bash -s -- --beta
```
This command downloads the recommended models for Livepeer AI and stores them in your machine's `~/.lpData/models` directory. To obtain a complete set of models, omit the `--beta` flag. This will require additional disk space.
# On-chain Setup
Source: https://docs.livepeer.org/v1/ai/orchestrators/onchain
Contract addresses in this guide may be outdated. For current verified addresses, see:
**[Livepeer Contract Addresses](/v2/about/resources/livepeer-contract-addresses)**
The previous section covered the **off-chain** configuration of the AI
Orchestrator node. This section details how to connect an AI Orchestrator node
to the Livepeer AI network and earn fees for processing AI inference jobs.
## Prerequisites
* An established [Mainnet Orchestrator](/orchestrators/guides/get-started)
within the Top 100 on the Livepeer network
* A dedicated static IP address or domain name for your AI Orchestrator node
* An Ethereum wallet funded with enough ETH to cover transaction fees for ticket
redemption
## Ensure you can Redeem Tickets
The Livepeer AI network is currently in **Beta** but is already integrated into
the main [go-livepeer](https://github.com/livepeer/go-livepeer) software.
However, it still uses a separate port for the AI Orchestrator. This means that
your **Mainnet Transcoding Network Orchestrator** is currently unable to
directly redeem AI-related tickets. There are two methods to enable your AI
Orchestrator node to redeem tickets:
To enable ticket redemption for your **AI Orchestrator**, set the ticket recipient to your **Mainnet Transcoding Network Orchestrator**'s Ethereum address. This method allows the earned fees to be credited directly to your main Orchestrator without requiring additional setup or causing disruption.
For security, it's advised to use a separate account from your **Mainnet Transcoding Network Orchestrator**.
Create a new Ethereum wallet for your **AI Orchestrator**. Follow the [Wallet Creation](/orchestrators/guides/get-started#automatic-eth-account-creation) guide in the [Orchestrator](/orchestrators/guides/get-started) documentation for detailed instructions.
Transfer sufficient ETH to the new wallet to cover the gas costs for redeeming AI tickets on-chain.
To direct the fees earned by your AI Orchestrator to your main Orchestrator, set the ticket recipient as the Ethereum address of your main Orchestrator. This can be done by adding the following flag when launching your AI Orchestrator node:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
./livepeer \
-ethOrchAddr \
... \
```
While this method is possible, it's not recommended because it can disrupt performance and add complexity to your **Mainnet Transcoding Network Orchestrator**. Only proceed with this method if you are unable to create a separate wallet for your **AI Orchestrator** and understand the potential implications.
If creating a separate wallet for your **AI Orchestrator** isn't an option, you might want to use a [redemption service](https://github.com/livepeer/go-livepeer/blob/master/doc/redeemer.md). This service allows your **Mainnet Transcoding Network Orchestrator** to redeem tickets for your AI Orchestrator. For more details, check out the [redemption service documentation](https://github.com/livepeer/go-livepeer/blob/master/doc/redeemer.md) and the [go-livepeer CLI documentation](/references/go-livepeer/cli-reference#onchain).
## Advertising Your AI Service URI
To make your AI Orchestrator node discoverable by AI Gateway nodes on the
Livepeer AI network, you need to advertise your **AI service URI** on-chain. You
can do this by registering your service URI with the
[AIServiceRegistry](https://arbiscan.io/address/0x04C0b249740175999E5BF5c9ac1dA92431EF34C5)
contract on the [Arbitrum Mainnet](https://arbitrum.io).
The easiest and recommended method is to use the [Foundry](https://book.getfoundry.sh/getting-started/installation) smart contract deployment toolchain.
Install [Foundry Cast](https://book.getfoundry.sh/cast/) by executing the following commands in your terminal:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -L https://foundry.paradigm.xyz | bash
source /home//.bashrc
foundryup
```
No need to move your **Mainnet Transcoding Network Orchestrator** wallet. You can run Foundry Cast and register your AI Orchestrator from any machine.
Set your Service URI, ensuring it starts with `https://`, using the `SetServiceURI` function on the [AIServiceRegistry](https://arbiscan.io/address/0x04C0b249740175999E5BF5c9ac1dA92431EF34C5) contract. Use the KeyStore file and password from your **Mainnet Transcoding Network Orchestrator** wallet:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
cast send --keystore '' --password '' --rpc-url 0x04C0b249740175999E5BF5c9ac1dA92431EF34C5 "setServiceURI(string)" https://:
```
After successful execution, the output should look like this:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
blockHash: 0x214a65d2dffd1732e971bd3662dcb681663c2eb0c95a33c8918bab0a44e2d3ed
blockNumber: 200370198
```
Verify your Service URI by invoking the `getServiceURI` function on the [AIServiceRegistry](https://arbiscan.io/address/0x04C0b249740175999E5BF5c9ac1dA92431EF34C5) contract:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
cast call --rpc-url 0x04C0b249740175999E5BF5c9ac1dA92431EF34C5 "getServiceURI(address)" | xxd -r -p
```
If successful, the output should be:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
https://:
```
Congratulations! Your **AI Orchestrator** node is now discoverable by **AI Gateway** nodes and ready to execute AI inference tasks on the Livepeer AI network! 🚀
If you prefer to interact with the contract through your browser, use the [Arbitrum Explorer](https://arbiscan.io/address/0x04C0b249740175999E5BF5c9ac1dA92431EF34C5) to call the `setServiceURI` function on the [AIServiceRegistry](https://arbiscan.io/address/0x04C0b249740175999E5BF5c9ac1dA92431EF34C5) contract.
Import the Ethereum wallet associated with your **Mainnet Transcoding Network Orchestrator** into your wallet browser extension. The steps to import your wallet may vary depending on the extension you are using. The steps for MetaMask can be found [here](https://support.metamask.io/hc/en-us/articles/360015489331-How-to-import-an-account).
Visit the [AIServiceRegistry](https://arbiscan.io/address/0x04C0b249740175999E5BF5c9ac1dA92431EF34C5) contract page on the Arbitrum Explorer and click on the `Contract` tab.
On the contract page, click the `Write Contract` button and connect your wallet to the Arbitrum Explorer by clicking the `Connect to Web3` button. Then, select the wallet you imported in the first step.
Access the [setServiceURI](https://arbiscan.io/address/0x04C0b249740175999E5BF5c9ac1dA92431EF34C5#writeContract#F2) function on the contract page and input the **Service URI** for your AI Orchestrator in the `_serviceURI` field. Make sure the Service URI starts with `https://`. After clicking the `Write` button to execute the function, you must confirm the transaction in your wallet extension. Once the transaction is confirmed, your AI Orchestrator's Service URI will
be successfully set.
To verify that the Service URI has been set correctly, click the `Read Contract` button on the contract page. Access the [getServiceURI](https://arbiscan.io/address/0x04C0b249740175999E5BF5c9ac1dA92431EF34C5#readContract#F2) function and input the address of your **Mainnet Transcoding Network Orchestrator** in the `_addr` field. Click the `Query` button to retrieve the Service URI set for your AI Orchestrator.
Congratulations! Your AI Orchestrator node is now discoverable by **AI Gateway** nodes and ready to execute AI inference tasks on the Livepeer AI network! 🚀
Currently, setting your AI service URI using the Livepeer CLI is not supported during the **Beta** phase of the Livepeer AI network. This feature is planned for future releases.
## Launch your On-chain AI Orchestrator
Once you've set your AI service URI on-chain, you can launch your AI
Orchestrator node to start processing AI inference jobs on the Livepeer AI
network. The commands to start the AI Orchestrator are similar to those for the
[off-chain Orchestrator](/ai/orchestrators/start-orchestrator), but with
additional flags to enable on-chain functionality:
* `-AIServiceRegistry`: Ensures that the Orchestrator is connected to the
Livepeer AI network.
* `-network=arbitrum-one-mainnet`: Connects the AI Orchestrator node to the
Arbitrum Mainnet network.
* `-ethUrl=https://arb1.arbitrum.io/rpc`: Sets the Arbitrum Mainnet RPC URL. You
can replace this with your own RPC URL.
* `-ethKeystorePath=/root/.lpData/arbitrum-one-mainnet/keystore`: Sets the path
to the AI Orchestrator's Ethereum keystore file.
* `-ethAcctAddr `: Sets the Ethereum address of the AI
Orchestrator.
* `-ethPassword=/root/.lpData/.eth_secret`: Sets the Ethereum keystore password
file path.
* `-ethOrchAddr=`: Sets the Ethereum address of the
Mainnet Transcoding Network Orchestrator.
Due to current limitations in the Livepeer AI software, the following flag is
required:
* `-ticketEV=2999999999999`: This flag ensures that the AI Orchestrator doesn't
trigger maximum ticket limits set by the `go-livepeer` software.
# Start your AI Orchestrator
Source: https://docs.livepeer.org/v1/ai/orchestrators/start-orchestrator
The Livepeer AI network is currently in its **Beta** stage and is undergoing
active development. Running it on the same machine as your main Orchestrator
or Gateway node may cause stability issues. Please proceed with caution.
The Livepeer AI network is currently in **Beta** but is already integrated into
the main [go-livepeer](https://github.com/livepeer/go-livepeer) software. 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.
## Orchestrator Node Architecture
In the Livepeer AI network, orchestrator operations rely on two primary **node
types**:
* **Orchestrator**: Manages and routes incoming jobs to available compute
resources.
* **Worker**: Performs the actual computation tasks.
The simplest configuration combines both roles on a single machine, utilizing
the machine's GPUs for AI inference tasks, where the orchestrator also functions
as a worker (known as a **combined AI orchestrator**). In this setup, capacity
is limited by the available GPUs and is set as
`runner container count per pipeline/model_id = capacity per pipeline/model_id`.
For expanded scalability, operators can deploy dedicated (remote) worker nodes
that connect to the orchestrator, increasing overall compute capacity.
Instructions for setting up remote workers are available on the
[next page](/ai/orchestrators/ai-worker).
## Start a Combined AI Orchestrator
Please follow the steps below to start your **combined AI orchestrator** node.
Fetch the latest Livepeer AI Docker image from the [Livepeer Docker Hub](https://hub.docker.com/r/livepeer/go-livepeer) with the following command:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
docker pull livepeer/go-livepeer:master
```
The Livepeer AI network employs a [containerized workflow](https://www.ibm.com/topics/containerization) for running AI models. Fetch the latest [AI Runner](https://hub.docker.com/r/livepeer/ai-runner) image with this command:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
docker pull livepeer/ai-runner:latest
```
Next, pull any pipeline-specific images if needed. Check the [pipelines](/ai/pipelines/overview) documentation for more information. For example, to pull the image for the [segment-anything-2](/ai/pipelines/segment-anything-2#pipeline-specific-image) pipeline:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
docker pull livepeer/ai-runner:segment-anything-2
```
The Livepeer AI network leverages pre-trained AI models for inference tasks. Before launching the AI Orchestrator node, verify that the weights of these models are accessible on your machine. For more information, visit the [Download AI Models](/ai/orchestrators/models-download) page.
Confirm that the AI models are correctly set up in the `aiModels.json` file in the `~/.lpData/` directory. For guidance on configuring the `aiModels.json` file, refer to the [AI Models Configuration](/ai/orchestrators/models-config) page. The configuration file should resemble:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
[
{
"pipeline": "text-to-image",
"model_id": "ByteDance/SDXL-Lightning",
"price_per_unit": 4768371,
"warm": true
}
]
```
Execute the Livepeer AI Docker image using the following command:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
docker run \
--name livepeer_ai_orchestrator \
-v ~/.lpData/:/root/.lpData/ \
-v /var/run/docker.sock:/var/run/docker.sock \
--network host \
--gpus all \
livepeer/go-livepeer:master \
-orchestrator \
-serviceAddr 0.0.0.0:8936 \
-v 6 \
-nvidia 0 \
-aiWorker \
-aiModels /root/.lpData/aiModels.json \
-aiModelsDir ~/.lpData/models \
-aiRunnerImage livepeer/ai-runner:latest # OPTIONAL
```
This command launches an **off-chain** AI Orchestrator node. While most of the commands are similar to those used when operating a Mainnet Transcoding Network Orchestrator node (explained in the [go-livepeer CLI reference](/references/go-livepeer/cli-reference)), there are a few **Livepeer AI** specific flags:
* `-aiWorker`: This flag enables the AI Worker functionality.
* `-aiModels`: This flag sets the path to the JSON file that contains the AI models.
* `-aiModelsDir`: This flag indicates the directory where the AI models are stored on the host machine.
* `-aiRunnerImage`: This optional flag specifies which version of the ai-runner image is used. Example: `livepeer/ai-runner:0.0.2`
Moreover, the `--network host` flag facilitates communication between the AI Orchestrator and the AI Runner container.
Lastly, the `-nvidia` can be configured in a few ways. Use a comma seperated list of GPUs ie. `0,1` to activate specific GPU slots, each GPU will need it's own config item in `aiModels.json`. Alternativly we can use `"all"` to activate all GPUs on the machine with a single model loaded in `aiModels.json` (Warning: If different RAM size GPUs are installed it may cause containers to fail if they have less than the required RAM).
Please note that since we use [docker-out-of-docker](https://tdongsi.github.io/blog/2017/04/23/docker-out-of-docker/), the `aiModelsDir` path should be defined as being on the host machine.
If your Livepeer AI Orchestrator node is functioning correctly, you should see the following output:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
2024/05/01 09:01:39 INFO Starting managed container gpu=0 name=text-to-image_ByteDance_SDXL-Lightning modelID=ByteDance/SDXL-Lightning
...
I0405 22:03:17.427058 2655655 rpc.go:301] Connecting RPC to uri=https://0.0.0.0:8936
I0405 22:03:17.430371 2655655 rpc.go:254] Received Ping request
```
To make your Livepeer AI Orchestrator node accessible from the internet, you need to configure your network settings. Ensure that port `8936` is unblocked on your machine. Additionally, consider setting up port forwarding on your router, allowing the Gateway node to be reachable from the internet.
Download the latest Livepeer AI binary for your system:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
wget https://build.livepeer.live/go-livepeer/livepeer--gpu-.tar.gz
```
Replace `` and `` with your system's operating system and architecture. For example, for a Linux system with an AMD64 architecture, the command would be:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
wget https://build.livepeer.live/go-livepeer/livepeer-linux-gpu-amd64.tar.gz
```
See the [go-livepeer installation guide](/orchestrators/guides/install-go-livepeer#install-using-a-binary-release) for more information on the available binaries.
The Windows and MacOS (amd64) binaries of **Livepeer AI** are not available yet.
Once downloaded, extract the binary to a directory of your choice.
The Livepeer AI network employs a [containerized workflow](https://www.ibm.com/topics/containerization) for running AI models. Fetch the latest [AI Runner](https://hub.docker.com/r/livepeer/ai-runner) image with this command:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
docker pull livepeer/ai-runner:latest
```
Next, pull any pipeline-specific images if needed. Check the [pipelines](/ai/pipelines/overview) documentation for more information. For example, to pull the image for the [segment-anything-2](/ai/pipelines/segment-anything-2#pipeline-specific-image) pipeline:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
docker pull livepeer/ai-runner:segment-anything-2
```
The Livepeer AI network leverages pre-trained AI models for inference tasks. Before launching the AI Orchestrator node, verify that the weights of these models are accessible on your machine. For more information, visit the [Download AI Models](/ai/orchestrators/models-download) page.
Confirm that the AI models are correctly set up in the `aiModels.json` file in the `~/.lpData/` directory. For guidance on configuring the `aiModels.json` file, refer to the [AI Models Configuration](/ai/orchestrators/models-config) page. The configuration file should resemble:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
[
{
"pipeline": "text-to-image",
"model_id": "ByteDance/SDXL-Lightning",
"price_per_unit": 4768371,
"warm": true
}
]
```
Run the following command to start your Livepeer AI Orchestrator node:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
./livepeer \
-orchestrator \
-serviceAddr 0.0.0.0:8936 \
-v 6 \
-nvidia "all" \
-aiWorker \
-aiModels ~/.lpData/aiModels.json \
-aiModelsDir ~/.lpData/models \
-aiRunnerImage livepeer/ai-runner:latest # OPTIONAL
```
This command launches an **off-chain** AI Orchestrator node. While most of the commands are similar to those used when operating a Mainnet Transcoding Network Orchestrator node (explained in the [go-livepeer CLI reference](/references/go-livepeer/cli-reference)), there are a few **Livepeer AI** specific flags:
* `-aiWorker`: This flag enables the AI Worker functionality.
* `-aiModels`: This flag sets the path to the JSON file that contains the AI models.
* `-aiModelsDir`: This flag indicates the directory where the AI models are stored.
* `-aiRunnerImage`: This optional flag specifies which version of the ai-runner image is used. Example: `livepeer/ai-runner:0.0.2`
If your Livepeer AI Orchestrator node is functioning correctly, you should see the following output:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
2024/05/01 09:01:39 INFO Starting managed container gpu=0 name=text-to-image_ByteDance_SDXL-Lightning modelID=ByteDance/SDXL-Lightning
...
I0405 22:03:17.427058 2655655 rpc.go:301] Connecting RPC to uri=https://0.0.0.0:8936
I0405 22:03:17.430371 2655655 rpc.go:254] Received Ping request
```
To make your Livepeer AI Orchestrator node accessible from the internet, you need to configure your network settings. Ensure that port `8936` is unblocked on your machine. Additionally, consider setting up port forwarding on your router, allowing the Gateway node to be reachable from the internet.
If no binaries are available 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 by following the instructions in the [Livepeer repository](/orchestrators/guides/install-go-livepeer) or by reaching out to the Livepeer community on [Discord](https://discord.gg/livepeer).
## Verify Combined AI Orchestrator Operation
Once your **combined Livepeer AI Orchestrator** node is running, verify that the
worker is operational by sending an AI inference request directly to the
[ai-runner](https://hub.docker.com/r/livepeer/ai-runner) container. You can
either use the [Swagger UI](https://fastapi.tiangolo.com/features/) interface or
a `curl` command for this check.
Open your web browser and navigate to `http://localhost:8000/docs` to access the Swagger UI interface.
In the Swagger UI, locate the `POST /text-to-image` endpoint and click the `Try it out` button. Use the following example JSON payload:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"prompt": "A cool cat on the beach."
}
```
This request will instruct the AI model to generate an image based on the text in the `prompt` field.
If the AI Orchestrator node is functioning correctly, you should receive a response similar to the following:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"images": [
{
"url": "data:image/png;base64,iVBORw0KGgoAA...",
"seed": 2724904334
}
]
}
```
The `url` field contains the base64 encoded image generated by the AI model. To convert this image to PNG, use a base64 decoder such as [Base64.guru](https://base64.guru/converter/decode/image/png).
Alternatively, you can use the `curl` command to test the AI inference capabilities directly. Run the following command, replacing `` with the IP address of your worker node:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -X POST "http://localost:8000/text-to-image" -H "Content-Type: application/json" -d '{"prompt": "A cool cat on the beach."}'
```
This sends a POST request to the `text-to-image` endpoint on the worker node with the specified JSON payload.
If the AI Worker node is functioning correctly, you should receive a response similar to this:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"images": [
{
"url": "data:image/png;base64,iVBORw0KGgoAA...",
"seed": 2724904334
}
]
}
```
As with the Swagger UI response, the `url` field contains a base64 encoded image that can be decoded into PNG format using a tool like [Base64.guru](https://base64.guru/converter/decode/image/png).
# Audio-to-Text
Source: https://docs.livepeer.org/v1/ai/pipelines/audio-to-text
## Overview
The `audio-to-text` pipeline converts audio from media files into text,
utilizing cutting-edge diffusion models from HuggingFace's
[automatic-speech-recognition (ASR) pipeline](https://huggingface.co/models?pipeline_tag=automatic-speech-recognition).
## Models
### Warm Models
The current warm model requested for the `audio-to-text` pipeline is:
* [openai/whisper-large-v3](https://huggingface.co/openai/whisper-large-v3):
Whisper is a pre-trained model for automatic speech recognition (ASR) and
speech translation.
For faster responses with different
[audio-to-text](https://huggingface.co/models?pipeline_tag=automatic-speech-recognition)
diffusion models, ask Orchestrators to load it on their GPU via the `ai-video`
channel in [Discord Server](https://discord.gg/livepeer).
### On-Demand Models
The following models have been tested and verified for the `audio-to-text`
pipeline:
If a specific model you wish to use is not listed, please submit a [feature
request](https://github.com/livepeer/ai-worker/issues/new?assignees=\&labels=enhancement%2Cmodel\&projects=\&template=model_request.yml)
on GitHub to get the model verified and added to the list.
* [openai/whisper-large-v3](https://huggingface.co/openai/whisper-large-v3): A high-performance ASR model by Open AI.
## Basic Usage Instructions
For a detailed understanding of the `audio-to-text` endpoint and to experiment
with the API, see the [Livepeer AI API
Reference](/ai/api-reference/audio-to-text).
To create an audio transcript using the `audio-to-text` pipeline, submit a
`POST` request to the Gateway's `audio-to-text` API endpoint:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -X POST "https:///audio-to-text" \
-F model_id=openai/whisper-large-v3 \
-F audio=@
```
In this command:
* `` should be replaced with your AI Gateway's IP address.
* `model_id` is the diffusion model for audio transcription.
* `audio` is the path to the audio file to be transcribed.
- Supported file types: `mp4`, `webm`, `mp3`, `flac`, `wav` and `m4a` -
Maximum request size: 50 MB
For additional optional parameters, refer to the
[Livepeer AI API Reference](/ai/api-reference/audio-to-text).
After execution, the Orchestrator processes the request and returns the response
to the Gateway:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"chunks": [
{
"text": " Explore the power of automatic speech recognition",
"timestamp": [0, 1.35]
},
{
"text": " By extracting the text from audio",
"timestamp": [1.35, 2.07]
}
],
"text": " Explore the power of automatic speech recognition By extracting the text from audio"
}
```
## Orchestrator Configuration
To configure your Orchestrator to serve the `audio-to-text` pipeline, refer to
the [Orchestrator Configuration](/ai/orchestrators/get-started) guide.
### System Requirements
The following system requirements are recommended for optimal performance:
* [NVIDIA GPU](https://developer.nvidia.com/cuda-gpus) with **at least 12GB** of
VRAM.
## Recommended Pipeline Pricing
We are planning to simplify the pricing in the future so orchestrators can set
one AI price per compute unit and have the system automatically scale based on
the model's compute requirements.
The pricing for the `audio-to-text` pipeline is based on competitor pricing.
However, we strongly encourage orchestrators to set their own pricing based on
their costs and requirements. Setting a competitive price will help attract more
jobs, as Gateways can set their maximum price for a job. The currently
recommended pricing for this pipeline is `0.02e-6 USD` per **milliseconds** of
audio input.
## API Reference
Explore the `audio-to-text` endpoint and experiment with the API in the
Livepeer AI API Reference.
# Image-to-Image
Source: https://docs.livepeer.org/v1/ai/pipelines/image-to-image
## Overview
The `image-to-image` pipeline of the Livepeer AI network enables **advanced
image manipulations** including style transfer, image enhancement, and more.
This pipeline leverages cutting-edge diffusion models from the HuggingFace
[image-to-image](https://huggingface.co/models?pipeline_tag=image-to-image)
pipeline.
```mermaid theme={"theme":{"light":"github-light","dark":"dark-plus"}}
graph LR
A[
] --> B[Gateway]
E["A hat"] --> B
B --> C[Orchestrator]
C --> B
B --> D[
]
```
## Models
### Warm Models
The current warm model requested for the `image-to-image` pipeline is:
* [timbrooks/instruct-pix2pix](https://huggingface.co/timbrooks/instruct-pix2pix):
A powerful diffusion model that edits images to a high-quality standard based
on human-written instructions.
For faster responses with different
[image-to-image](https://huggingface.co/models?pipeline_tag=image-to-image)
diffusion models, ask Orchestrators to load it on their GPU via the `ai-video`
channel in [Discord Server](https://discord.gg/livepeer).
### On-Demand Models
The following models have been tested and verified for the `image-to-image`
pipeline:
If a specific model you wish to use is not listed, please submit a [feature
request](https://github.com/livepeer/ai-worker/issues/new?assignees=\&labels=enhancement%2Cmodel\&projects=\&template=model_request.yml)
on GitHub to get the model verified and added to the list.
* [timbrooks/instruct-pix2pix](https://huggingface.co/timbrooks/instruct-pix2pix): A powerful diffusion model that edits images to a high-quality standard based on human-written instructions.
* [ByteDance/SDXL-Lightning](https://huggingface.co/ByteDance/SDXL-Lightning): A lightning-fast diffusion model by ByteDance, optimized for high-speed image-to-image transformations.
* [SG161222/RealVisXL\_V4.0](https://huggingface.co/SG161222/RealVisXL_V4.0): A diffusion model that excels in generating high-quality, photorealistic images.
* [SG161222/RealVisXL\_V4.0\_Lightning](https://huggingface.co/SG161222/RealVisXL_V4.0_Lightning): A streamlined version of RealVisXL\_V4.0, designed for faster inference while still aiming for photorealism.
* [stabilityai/sd-turbo](https://huggingface.co/stabilityai/sd-turbo): A robust diffusion model by Stability AI, designed for efficient and high-quality image generation ([limited-commercial use license](https://stability.ai/license)).
* [stabilityai/sdxl-turbo](https://huggingface.co/stabilityai/sdxl-turbo): An extended version of the sd-turbo model, offering enhanced performance for larger and more complex tasks ([limited-commercial use license](https://stability.ai/license)).
## Basic Usage Instructions
For a detailed understanding of the `image-to-image` endpoint and to
experiment with the API, see the [Livepeer AI API
Reference](/ai/api-reference/image-to-image).
To generate an image with the `image-to-image` pipeline, send a `POST` request
to the Gateway's `image-to-image` API endpoint:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -X POST https:///image-to-image \
-F model_id="timbrooks/instruct-pix2pix" \
-F image=@/cool-cat.png \
-F prompt="a hat"
```
In this command:
* `` should be replaced with your AI Gateway's IP address.
* `model_id` is the diffusion model for image generation.
* The `image` field holds the **absolute** path to the image file to be
transformed.
* `prompt` is the text description for the image.
For additional optional parameters, refer to the
[Livepeer AI API Reference](/ai/api-reference/image-to-image).
After execution, the Orchestrator processes the request and returns the response
to the Gateway:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"images": [
{
"nsfw": false,
"seed": 3197613440,
"url": "https:///stream/dd5ad78d/7adde483.png"
}
]
}
```
The `url` in the response is the URL of the generated image. Download the image
with:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -O "https:///stream/dd5ad78d/7adde483.png"
```
## Applying LoRa Models
To apply LoRa filters to an image, include the `loras` field in your request:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -X POST https:///image-to-image \
-F model_id="ByteDance/SDXL-Lightning" \
-F image=@/cool-cat.png \
-F prompt="a hat" \
-F loras='{ "nerijs/pixel-art-xl": 1.2 }'
```
You can find a list of available LoRa models for various models on
[lora-studio](https://huggingface.co/spaces/enzostvs/lora-studio).
## Orchestrator Configuration
To configure your Orchestrator to serve the `image-to-image` pipeline, refer to
the [Orchestrator Configuration](/ai/orchestrators/get-started) guide.
### System Requirements
The following system requirements are recommended for optimal performance:
* [NVIDIA GPU](https://developer.nvidia.com/cuda-gpus) with **at least 20GB** of
VRAM.
## Recommended Pipeline Pricing
We are planning to simplify the pricing in the future so orchestrators can set
one AI price per compute unit and have the system automatically scale based on
the model's compute requirements.
The pricing for the `image-to-image` pipeline is based on competitor pricing.
However, we strongly encourage orchestrators to set their own pricing based on
their costs and requirements. Setting a competitive price will help attract more
jobs, as Gateways can set their maximum price for a job. The current recommended
pricing for this pipeline is `1.9073484e-08 USD` per **input pixel**
(`height * width * output images`).
## API Reference
Explore the `image-to-image` endpoint and experiment with the API in the
Livepeer AI API Reference.
# Image-to-Text
Source: https://docs.livepeer.org/v1/ai/pipelines/image-to-text
## Overview
The `image-to-text` pipeline converts images into text captions. This pipeline
is powered by the latest models in the HuggingFace
[text-to-image](https://huggingface.co/models?pipeline_tag=text-to-image)
pipeline.
## Models
### Warm Models
The current warm model requested for the `image-to-text` pipeline is:
* [Salesforce/blip-image-captioning-large](https://huggingface.co/Salesforce/blip-image-captioning-large)
For faster responses with different
[image-to-text](https://huggingface.co/models?pipeline_tag=text-to-image)
diffusion models, ask Orchestrators to load it on their GPU via the `ai-video`
channel in [Discord Server](https://discord.gg/livepeer).
### On-Demand Models
The following models have been tested and verified for the `image-to-text`
pipeline:
If a specific model you wish to use is not listed, please submit a [feature
request](https://github.com/livepeer/ai-worker/issues/new?assignees=\&labels=enhancement%2Cmodel\&projects=\&template=model_request.yml)
on GitHub to get the model verified and added to the list.
* [Salesforce/blip-image-captioning-large](https://huggingface.co/Salesforce/blip-image-captioning-large)
## Basic Usage Instructions
For a detailed understanding of the `image-to-text` endpoint and to experiment
with the API, see the [Livepeer AI API
Reference](/ai/api-reference/image-to-text).
To create an image caption using the `image-to-text` pipeline, submit a `POST`
request to the Gateway's `image-to-text` API endpoint:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -X POST "https:///image-to-text" \
-F model_id=Salesforce/blip-image-captioning-large \
-F image=@
```
In this command:
* `` should be replaced with your AI Gateway's IP address.
* `model_id` is the diffusion model to use.
* `image` is the path to the image file to be captioned.
Maximum request size: 50 MB
For additional optional parameters, refer to the
[Livepeer AI API Reference](/ai/api-reference/image-to-text).
## Orchestrator Configuration
To configure your Orchestrator to serve the `image-to-text` pipeline, refer to
the [Orchestrator Configuration](/ai/orchestrators/get-started) guide.
### System Requirements
The following system requirements are recommended for optimal performance:
* [NVIDIA GPU](https://developer.nvidia.com/cuda-gpus) with **at least 4GB** of
VRAM.
## Recommended Pipeline Pricing
We are planning to simplify the pricing in the future so orchestrators can set
one AI price per compute unit and have the system automatically scale based on
the model's compute requirements.
The pricing for the `image-to-text` pipeline is based on competitor pricing.
However, we strongly encourage orchestrators to set their own pricing based on
their costs and requirements. Setting a competitive price will help attract more
jobs, as Gateways can set their maximum price for a job. The current recommended
pricing for this pipeline is `2.5e-10 USD` per **input pixel**
(`height * width`).
## API Reference
Explore the `image-to-text` endpoint and experiment with the API in the
Livepeer AI API Reference.
# Image-to-Video
Source: https://docs.livepeer.org/v1/ai/pipelines/image-to-video
## Overview
The `image-to-video` pipeline of the Livepeer AI network allows you to generate
animated **high-quality** videos from images. This pipeline is powered by the
latest diffusion models in the HuggingFace
[image-to-video](https://huggingface.co/models?pipeline_tag=image-to-video)
pipeline.
```mermaid theme={"theme":{"light":"github-light","dark":"dark-plus"}}
graph LR
A[
] --> B[Gateway]
B --> C[Orchestrator]
C --> B
B --> D[
]
```
## Models
### Warm Models
The current warm model requested for the `image-to-video` pipeline is:
* [stabilityai/stable-video-diffusion-img2vid-xt-1-1](https://huggingface.co/stabilityai/stable-video-diffusion-img2vid-xt-1-1):
An updated version of the stable-video-diffusion-img2vid-xt model with
enhanced performance
([limited-commercial use license](https://stability.ai/license)).
For faster responses with different
[image-to-video](https://huggingface.co/models?pipeline_tag=image-to-video)
diffusion models, ask Orchestrators to load it on their GPU via the `ai-video`
channel in [Discord Server](https://discord.gg/livepeer).
### On-Demand Models
The following models have been tested and verified for the `image-to-video`
pipeline:
If a specific model you wish to use is not listed, please submit a [feature
request](https://github.com/livepeer/ai-worker/issues/new?assignees=\&labels=enhancement%2Cmodel\&projects=\&template=model_request.yml)
on GitHub to get the model verified and added to the list.
* [stable-video-diffusion-img2vid-xt](https://huggingface.co/stabilityai/stable-video-diffusion-img2vid-xt):
A model by Stability AI designed for stable video diffusion from images ([limited-commercial use license](https://stability.ai/license)).
* [stabilityai/stable-video-diffusion-img2vid-xt-1-1](https://huggingface.co/stabilityai/stable-video-diffusion-img2vid-xt-1-1):
An updated version of the stable-video-diffusion-img2vid-xt model with enhanced performance ([limited-commercial use license](https://stability.ai/license)).
## Basic Usage Instructions
For a detailed understanding of the `image-to-video` endpoint and to
experiment with the API, see the [Livepeer AI API
Reference](/ai/api-reference/image-to-video).
To generate a video with the `image-to-video` pipeline, send a `POST` request to
the Gateway's `image-to-video` API endpoint:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -X POST "https:///image-to-video" \
-F model_id=stabilityai/stable-video-diffusion-img2vid-xt-1-1 \
-F image=@
```
In this command:
* `` should be replaced with your AI Gateway's IP address.
* `model_id` is the diffusion model for video generation.
* The `image` field holds the **absolute** path to the image file to be
transformed.
For additional optional parameters, refer to the
[Livepeer AI API Reference](/ai/api-reference/image-to-video).
After execution, the Orchestrator processes the request and returns the response
to the Gateway:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"images": [
{
"nsfw": false,
"seed": 1914955328,
"url": "/stream/2b835716/01c0e9a6.mp4"
}
]
}
```
The `url` in the response is the URL of the generated video. Download the video
with:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -O "https:///stream/2b835716/01c0e9a6.mp4"
```
## Orchestrator Configuration
To configure your Orchestrator to serve the `image-to-video` pipeline, refer to
the [Orchestrator Configuration](/ai/orchestrators/get-started) guide.
### System Requirements
The following system requirements are recommended for optimal performance:
* [NVIDIA GPU](https://developer.nvidia.com/cuda-gpus) with **at least 24GB** of
VRAM.
## Recommended Pipeline Pricing
We are planning to simplify the pricing in the future so orchestrators can set
one AI price per compute unit and have the system automatically scale based on
the model's compute requirements.
The pricing for the `image-to-video` pipeline is based on competitor pricing.
However, we strongly encourage orchestrators to set their own pricing based on
their costs and requirements. Setting a competitive price will help attract more
jobs, as Gateways can set their maximum price for a job. The current recommended
pricing for this pipeline is `1.3563368e-08 USD` per **output pixel**
(`height * width * frames`).
## API Reference
Explore the `image-to-video` endpoint and experiment with the API in the
Livepeer AI API Reference.
# LLM
Source: https://docs.livepeer.org/v1/ai/pipelines/llm
## Overview
The `llm` pipeline provides an OpenAI-compatible interface for text generation,
designed to integrate seamlessly into media workflows.
## Models
The `llm` pipeline supports **any Hugging Face-compatible LLM model**. Since
models evolve quickly, the set of warm (preloaded) models on Orchestrators
changes regularly.
To see which models are currently available, check the
[Network Capabilities dashboard](https://tools.livepeer.cloud/ai/network-capabilities).\
At the time of writing, the most commonly available model is
[meta-llama/Meta-Llama-3.1-8B-Instruct](https://huggingface.co/meta-llama/Llama-3.1-8B-Instruct).
For faster responses with different
[LLM](https://huggingface.co/models?pipeline_tag=text-generation) models, ask
Orchestrators to load it on their GPU via the `ai-research` channel in
[Discord Server](https://discord.gg/livepeer).
## Basic Usage Instructions
For a detailed understanding of the `llm` endpoint and to experiment with the
API, see the [Livepeer AI API Reference](/ai/api-reference/llm).
To generate text with the `llm` pipeline, send a `POST` request to the Gateway's
`llm` API endpoint:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -X POST "https:///llm" \
-H "Authorization: Bearer " \
-H "Content-Type: application/json" \
-d '{
"model": "meta-llama/Meta-Llama-3.1-8B-Instruct",
"messages": [
{ "role": "user", "content": "Tell a robot story." }
]
}'
```
In this command:
* `` should be replaced with your AI Gateway's IP address.
* `` should be replaced with your API token if required by the AI
Gateway.
* `model` is the LLM model to use for generation.
* `messages` is the conversation or prompt input for the model.
For additional optional parameters such as `temperature`, `max_tokens`, or
`stream`, refer to the [Livepeer AI API Reference](/ai/api-reference/llm).
After execution, the Orchestrator processes the request and returns the response
to the Gateway which forwards the response in response to the request.
Example partial non-streaming response below:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"id": "chatcmpl-abc123",
"model": "meta-llama/Meta-Llama-3.1-8B-Instruct",
"choices": [
{
"message": {
"role": "assistant",
"content": "Once upon a time, in a gleaming city of circuits..."
}
}
]
}
```
By default, responses are returned as a single JSON object. To stream output
token-by-token using **Server-Sent Events (SSE)**, set `"stream": true` in the
request body.
## Orchestrator Configuration
To configure your Orchestrator to serve the `llm` pipeline, refer to the
[Orchestrator Configuration](/ai/orchestrators/get-started) guide.
### Tuning Environment Variables
The `llm` pipeline supports several environment variables that can be adjusted
to optimize performance based on your hardware and workload. These are
particularly helpful for managing memory usage and parallelism when running
large models.
Enables 8-bit quantization using `bitsandbytes` for lower memory usage. Set to
`true` to enable. Defaults to `false`.
Number of pipeline parallel stages. Defaults to `1`.
Number of tensor parallel units. Must divide evenly into the number of
attention heads in the model. Defaults to `1`.
Maximum number of tokens per input sequence. Defaults to `8192`.
Maximum number of tokens processed in a single batch. Should be greater than
or equal to `MAX_MODEL_LEN`. Defaults to `8192`.
Maximum number of sequences processed per batch. Defaults to `128`.
Target GPU memory utilization as a float between `0` and `1`. Higher values
make fuller use of GPU memory. Defaults to `0.85`.
### System Requirements
The following system requirements are recommended for optimal performance:
* [NVIDIA GPU](https://developer.nvidia.com/cuda-gpus) with **at least 16GB** of
VRAM.
## Recommended Pipeline Pricing
We are planning to simplify the pricing in the future so orchestrators can set
one AI price per compute unit and have the system automatically scale based on
the model's compute requirements.
The `/llm` pipeline is currently priced based on the **maximum output tokens**
specified in the request — not actual usage — due to current payment system
limitations. We're actively working to support usage-based pricing to better
align with industry standards.
The LLM pricing landscape is highly competitive and rapidly evolving.
Orchestrators should set prices based on their infrastructure costs and
[market positioning](https://llmpricecheck.com/). As a reference, inference on
`llama-3-8b-instruct` is currently around `0.08 USD` per 1 million **output
tokens**.
## API Reference
Explore the `llm` endpoint and experiment with the API in the Livepeer AI API
Reference.
# Overview
Source: https://docs.livepeer.org/v1/ai/pipelines/overview
The Livepeer AI network offers a variety of **generative AI pipelines** that
applications can use to request AI inference jobs on the Livepeer network.
Currently, the focus is on Diffusion models developed using Huggingface's
[Diffusers library](https://huggingface.co/docs/diffusers/en/index), but future
updates will extend support to other model types. This section introduces the
available pipelines, the models they support, and provides a basic usage
example. For a comprehensive guide on integrating the Livepeer AI network into
your application, refer to the
[Building on Livepeer AI](/ai/builders/get-started) section.
## Models on the Livepeer AI network
### Warm Models
During the **Beta** phase of the Livepeer AI network, Orchestrators are
encouraged to keep at least **one model** per pipeline active on their GPUs
("warm models"). This approach ensures quicker response times for **early
builders**. We're optimizing GPU model loading/unloading to relax this
requirement. The current warm models for each pipeline are listed on their
respective pages.
For faster responses with different [Diffusion
models](https://huggingface.co/docs/diffusers/en/index), request Orchestrators
to load it on their GPU via the `ai-video` channel in [Discord
Server](https://discord.gg/livepeer).
### On-Demand Models
Orchestrators can theoretically load **any**
[diffusion model](https://huggingface.co/docs/diffusers/en/index) from
[Hugging Face](https://huggingface.co/models) on-demand, optimizing GPU
resources by loading models only when needed. However, during the **Beta**
phase, Orchestrators need to pre-download a model.
If a specific model you wish to use is not listed on the respective pipeline
page, submit a [feature
request](https://github.com/livepeer/ai-worker/issues/new?assignees=\&labels=enhancement%2Cmodel\&projects=\&template=model_request.yml)
on GitHub to get the model verified and added to the list.
## Generative AI Pipelines
The Livepeer AI network currently supports the following generative AI
pipelines:
The audio-to-text pipeline uses automatic speech recognition (ASR) to
translate audio to text with timestamps
The image-to-image pipeline enables advanced image manipulations, including
style transfer, image enhancement, and more
The image-to-text pipeline generates captions for input images, with an
optional prompt to guide the process.
The image-to-video pipeline creates animated high-quality videos from images
The segment-anything-2 pipeline offers promptable visual segmentation for
images and videos.
The text-to-image pipeline generates high-quality images from text
descriptions
The text-to-speech pipeline generates high-quality, natural sounding speech
in the style of a given speaker (gender, pitch, speaking style, etc).
The upscale pipeline transforms low-resolution images into high-quality ones
without distortion
The LLM pipeline provides an OpenAI-compatible interface for text
generation, enabling seamless integration into media workflows.
# Segment-Anything-2
Source: https://docs.livepeer.org/v1/ai/pipelines/segment-anything-2
## Overview
The `segment-anything-2` pipeline provides direct access to the
[Segment Anything 2 pipeline](https://ai.meta.com/sam2/) developed by
[Meta AI Research](https://research.facebook.com/). In its current version, it
supports only image segmentation, enabling it to segment any object in an image.
Future versions will also support direct video input, allowing the object to be
consistently tracked across all frames of a video in real-time. This advancement
will unlock new possibilities for video editing and enhance experiences in mixed
reality. The pipeline is powered by the latest diffusion models from
HuggingFace's
[facebook/sam2-hiera-large](https://huggingface.co/facebook/sam2-hiera-large).
## Models
### Warm Models
The current warm model requested for the `segment-anything-2` pipeline is:
* [facebook/sam2-hiera-large](https://huggingface.co/facebook/sam2-hiera-large):
The largest model in the Segment Anything 2 model suite, designed for the most
accurate image segmentation.
For faster responses with different
[segment-anything-2](https://github.com/facebookresearch/segment-anything-2)
diffusion models, ask Orchestrators to load it on their GPU via the `ai-video`
channel in [Discord Server](https://discord.gg/livepeer).
### On-Demand Models
The following models have been tested and verified for the `segment-anything-2`
pipeline:
If a specific model you wish to use is not listed, please submit a [feature
request](https://github.com/livepeer/ai-worker/issues/new?assignees=\&labels=enhancement%2Cmodel\&projects=\&template=model_request.yml)
on GitHub to get the model verified and added to the list.
* [facebook/sam2-hiera-base-plus](https://huggingface.co/facebook/sam2-hiera-base-plus): The second largest model in the Segment Anything 2 model suite, providing a balance between speed and accuracy.
* [facebook/sam2-hiera-small](https://huggingface.co/facebook/sam2-hiera-small): A smaller model in the Segment Anything 2 model suite, designed for faster image segmentation.
* [facebook/sam2-hiera-tiny](https://huggingface.co/facebook/sam2-hiera-tiny): The smallest model in the Segment Anything 2 model suite, optimized for real-time image segmentation.
## Basic Usage Instructions
For a detailed understanding of the `segment-anything-2` endpoint and to
experiment with the API, see the [Livepeer AI API
Reference](/ai/api-reference/segment-anything-2).
To generate an image with the `segment-anything-2` pipeline, send a `POST`
request to the Gateway's `segment-anything-2` API endpoint:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -X POST http:///segment-anything-2 \
-F model_id="facebook/sam2-hiera-large" \
-F point_coords="[[120,100],[120,50]]" \
-F point_labels="[1,0]" \
-F image=@/cool-cat.png
```
In this command:
* `` should be replaced with your AI Gateway's IP address.
* `model_id` is the diffusion model for image segmentation.
* The `point_coords` field holds the coordinates of the points to be segmented.
* The `point_labels` field holds the labels for the points to be segmented.
* The `image` field holds the **absolute** path to the image file to be
transformed.
For additional optional parameters, refer to the
[Livepeer AI API Reference](/ai/api-reference/segment-anything-2).
After execution, the Orchestrator processes the request and returns the response
to the Gateway:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"masks": "[[[2.84, 2.83, ...], [2.92, 2.91, ...], [3.22, 3.56, ...], ...]]",
"scores": "[0.50, 0.37, ...]",
"logits": "[[[2.84, 2.66, ...], [3.59, 5.20, ...], [5.07, 5.68, ...], ...]]"
}
```
## Orchestrator Configuration
To configure your Orchestrator to serve the `segment-anything-2` pipeline, refer
to the [Orchestrator Configuration](/ai/orchestrators/get-started) guide.
### System Requirements
The following system requirements are recommended for optimal performance:
* [NVIDIA GPU](https://developer.nvidia.com/cuda-gpus) with **at least 6GB** of
VRAM.
## Recommended Pipeline Pricing
We are planning to simplify the pricing in the future so orchestrators can set
one AI price per compute unit and have the system automatically scale based on
the model's compute requirements.
The pricing for the `segment-anything-2` pipeline is based on competitor
pricing. However, we strongly encourage orchestrators to set their own pricing
based on their costs and requirements. Setting a competitive price will help
attract more jobs, as Gateways can set their maximum price for a job. The
current recommended pricing for this pipeline is `3.22e-11 USD` per **input
pixel** (`height * width`).
### Pipeline-Specific Image
To serve the `segment-anything-2` pipeline, you must use a pipeline specific AI
Runner container. Pull the required container from
[Docker Hub](https://hub.docker.com/r/livepeer/ai-runner/tags?name=segment-anything-2-latest)
using the following command:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
docker pull livepeer/ai-runner:segment-anything-2
```
## API Reference
Explore the `segment-anything-2` endpoint and experiment with the API in
Livepeer AI API Reference.
# Text-to-Image
Source: https://docs.livepeer.org/v1/ai/pipelines/text-to-image
## Overview
The `text-to-image` pipeline of the Livepeer AI network allows you to generate
**high-quality** images from text descriptions. This pipeline is powered by the
latest diffusion models in the HuggingFace
[text-to-image](https://huggingface.co/models?pipeline_tag=text-to-image)
pipeline.
```mermaid theme={"theme":{"light":"github-light","dark":"dark-plus"}}
graph LR
A["A cool cat on the beach"] --> B[Gateway]
B --> C[Orchestrator]
C --> B
B --> D[
]
```
## Models
### Warm Models
The current warm model requested for the `text-to-image` pipeline is:
* [SG161222/RealVisXL\_V4.0\_Lightning](https://huggingface.co/SG161222/RealVisXL_V4.0_Lightning):
A streamlined version of RealVisXL\_V4.0, designed for faster inference while
still aiming for photorealism.
Furthermore, several Orchestrators are currently maintaining the following model
in a ready state:
* [ByteDance/SDXL-Lightning](https://huggingface.co/ByteDance/SDXL-Lightning): A
high-performance diffusion model developed by ByteDance.
For faster responses with different
[text-to-image](https://huggingface.co/models?pipeline_tag=text-to-image)
diffusion models, ask Orchestrators to load it on their GPU via the `ai-video`
channel in [Discord Server](https://discord.gg/livepeer).
### On-Demand Models
The following models have been tested and verified for the `text-to-image`
pipeline:
If a specific model you wish to use is not listed, please submit a [feature
request](https://github.com/livepeer/ai-worker/issues/new?assignees=\&labels=enhancement%2Cmodel\&projects=\&template=model_request.yml)
on GitHub to get the model verified and added to the list.
* [SG161222/Realistic\_Vision\_V6.0\_B1\_noVAE](https://huggingface.co/SG161222/Realistic_Vision_V6.0_B1_noVAE): Latest (experimental) release of the Realistic Vision model specialized in creating photorealistic portraits.
* [stabilityai/stable-diffusion-xl-base-1.0](https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0): A base model for stable diffusion by Stability AI.
* [runwayml/stable-diffusion-v1-5](https://huggingface.co/runwayml/stable-diffusion-v1-5): A stable diffusion model by Runway ML.
* [prompthero/openjourney-v4](https://huggingface.co/prompthero/openjourney-v4): A model by Prompthero for open-ended journey generation.
* [ByteDance/SDXL-Lightning](https://huggingface.co/ByteDance/SDXL-Lightning): A lightning-fast diffusion model by ByteDance.
* [SG161222/RealVisXL\_V4.0](https://huggingface.co/SG161222/RealVisXL_V4.0): A diffusion model that excels in generating high-quality, photorealistic images.
* [SG161222/RealVisXL\_V4.0\_Lightning](https://huggingface.co/SG161222/RealVisXL_V4.0_Lightning): A streamlined version of RealVisXL\_V4.0, designed for faster inference while still aiming for photorealism.
* [stabilityai/sd-turbo](https://huggingface.co/stabilityai/sd-turbo): A high-performance diffusion model by Stability AI ([limited-commercial use license](https://stability.ai/license)).
* [stabilityai/sdxl-turbo](https://huggingface.co/stabilityai/sdxl-turbo): An extended version of sd-turbo with enhanced capabilities ([limited-commercial use license](https://stability.ai/license)).
* [stabilityai/stable-diffusion-3-medium-diffusers](https://huggingface.co/stabilityai/stable-diffusion-3-medium-diffusers/): A Multimodal Diffusion Transformer (MMDiT) model with superior image quality, advanced typography, and enhanced prompt comprehension ([limited-commercial use license](https://stability.ai/license)).
## Basic Usage Instructions
For a detailed understanding of the `text-to-image` endpoint and to experiment
with the API, see the [Livepeer AI API
Reference](/ai/api-reference/text-to-image). For examples of effective
prompts, visit [PromptHero](https://prompthero.com/).
To generate an image with the `text-to-image` pipeline, send a `POST` request to
the Gateway's `text-to-image` API endpoint:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -X POST "https:///text-to-image" \
-H "Content-Type: application/json" \
-d '{
"model_id":"ByteDance/SDXL-Lightning",
"prompt":"A cool cat on the beach",
"width": 1024,
"height": 1024
}'
```
In this command:
* `` should be replaced with your AI Gateway's IP address.
* `model_id` is the diffusion model for image generation.
* `prompt` is the text description for the image.
For additional optional parameters, refer to the
[Livepeer AI API Reference](/ai/api-reference/text-to-image).
After execution, the Orchestrator processes the request and returns the response
to the Gateway:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"images": [
{
"nsfw": false,
"seed": 2562822894,
"url": "https:///stream/d0fc1fc6/8fdf5a94.png"
}
]
}
```
The `url` in the response is the URL of the generated image. Download the image
with:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -O "https:///stream/d0fc1fc6/8fdf5a94.png"
```
## Applying LoRa Models
To apply LoRa filters to an image, include the `loras` field in your request:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -X POST "https:///text-to-image" \
-H "Content-Type: application/json" \
-d '{
"model_id":"stabilityai/stable-diffusion-xl-base-1.0",
"prompt":"A cool cat on the beach",
"width": 1024,
"height": 1024,
"loras": "{ \"latent-consistency/lcm-lora-sdxl\": 1.0, \"nerijs/pixel-art-xl\": 1.2}"
}'
```
You can find a list of available LoRa models for various models on
[lora-studio](https://huggingface.co/spaces/enzostvs/lora-studio).
## Orchestrator Configuration
To configure your Orchestrator to serve the `text-to-image` pipeline, refer to
the [Orchestrator Configuration](/ai/orchestrators/get-started) guide.
### System Requirements
The following system requirements are recommended for optimal performance:
* [NVIDIA GPU](https://developer.nvidia.com/cuda-gpus) with **at least 24GB** of
VRAM.
## Recommended Pipeline Pricing
We are planning to simplify the pricing in the future so orchestrators can set
one AI price per compute unit and have the system automatically scale based on
the model's compute requirements.
The pricing for the `text-to-image` pipeline is based on competitor pricing.
However, we strongly encourage orchestrators to set their own pricing based on
their costs and requirements. Setting a competitive price will help attract more
jobs, as Gateways can set their maximum price for a job. The current recommended
pricing for this pipeline is `1.9073484e-08 USD` per **output pixel**
(`height * width * output images`).
## API Reference
Explore the `text-to-image` endpoint and experiment with the API in the
Livepeer AI API Reference.
# Text-to-Speech
Source: https://docs.livepeer.org/v1/ai/pipelines/text-to-speech
## Overview
The text-to-speech endpoint in Livepeer utilizes
[Parler-TTS](https://github.com/huggingface/parler-tts), specifically
`parler-tts/parler-tts-large-v1`. This model can generate speech with
customizable characteristics such as voice type, speaking style, and audio
quality.
## Basic Usage Instructions
For a detailed understanding of the `text-to-speech` endpoint and to
experiment with the API, see the [Livepeer AI API
Reference](/ai/api-reference/text-to-speech).
To use the text-to-speech feature, submit a POST request to the
`/text-to-speech` endpoint. Here's an example of how to structure your request:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -X POST "http:///text-to-speech" \
-H "Content-Type: application/json" \
-d '{
"model_id": "parler-tts/parler-tts-large-v1",
"text": "A cool cat on the beach",
"description": "Jon his voice is monotone yet slightly fast in delivery, with a very close recording that almost has no background noise."
}'
```
### Request Parameters
* `model_id`: The ID of the text-to-speech model to use. Currently, this should
be set to `"parler-tts/parler-tts-large-v1"`.
* `text`: The text you want to convert to speech.
* `description`: A description of the desired voice characteristics. This can
include details about the speaker's voice, speaking style, and audio quality.
### Voice Customization
You can customize the generated voice by adjusting the `description` parameter.
Some aspects you can control include:
* Speaker identity (e.g., "Jon's voice")
* Speaking style (e.g., "monotone", "expressive")
* Speaking speed (e.g., "slightly fast")
* Audio quality (e.g., "very close recording", "no background noise")
The checkpoint was trained on 34 speakers. The full list of available speakers
includes: Laura, Gary, Jon, Lea, Karen, Rick, Brenda, David, Eileen, Jordan,
Mike, Yann, Joy, James, Eric, Lauren, Rose, Will, Jason, Aaron, Naomie, Alisa,
Patrick, Jerry, Tina, Jenna, Bill, Tom, Carol, Barbara, Rebecca, Anna, Bruce,
and Emily.
However, the models performed better with certain speakers. A list of the top 20
speakers for each model variant, ranked by their average speaker similarity
scores can be found
[here](https://github.com/huggingface/parler-tts/blob/main/INFERENCE.md#speaker-consistency)
## Limitations and Considerations
* The maximum length of the input text may be limited. For long-form content,
you will need to split your text into smaller chunks. The training default
configuration in parler-tts is max 30sec, max text length 600 characters.
[https://github.com/huggingface/parler-tts/blob/main/training/README.md#3-training](https://github.com/huggingface/parler-tts/blob/main/training/README.md#3-training)
* While the model supports various voice characteristics, the exact replication
of a specific speaker's voice is not guaranteed.
* The quality of the generated speech can vary based on the complexity of the
input text and the specificity of the voice description.
## Orchestrator Configuration
To configure your Orchestrator to serve the `text-to-speech` pipeline, refer to
the [Orchestrator Configuration](/ai/orchestrators/get-started) guide.
### System Requirements
The following system requirements are recommended for optimal performance:
* [NVIDIA GPU](https://developer.nvidia.com/cuda-gpus) with **at least 12GB** of
VRAM.
## Recommended Pipeline Pricing
We are planning to simplify the pricing in the future so orchestrators can set
one AI price per compute unit and have the system automatically scale based on
the model's compute requirements.
The pricing for the `text-to-speech` pipeline is based on competitor pricing.
However, we strongly encourage orchestrators to set their own pricing based on
their costs and requirements. Setting a competitive price will help attract more
jobs, as Gateways can set their maximum price for a job. The current recommended
pricing for this pipeline is `1.5e-6 USD` per **character**.
### Pipeline-Specific Image
To serve the `text-to-speech` pipeline, you must use a pipeline specific AI
Runner container. Pull the required container from
[Docker Hub](https://hub.docker.com/r/livepeer/ai-runner/tags?name=text-to-speech-latest)
using the following command:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
docker pull livepeer/ai-runner:text-to-speech
```
## API Reference
Explore the `text-to-speech` endpoint and experiment with the API in the
Livepeer AI API Reference.
# Upscale
Source: https://docs.livepeer.org/v1/ai/pipelines/upscale
## Overview
The Livepeer AI network's `upscale` pipeline provides **advanced image
upscaling**. Powered by the latest diffusion models in HuggingFace's
[super-resolution](https://huggingface.co/docs/diffusers/en/api/pipelines/stable_diffusion/upscale)
pipeline, it enhances the resolution of input images by a factor of 4.
```mermaid theme={"theme":{"light":"github-light","dark":"dark-plus"}}
graph LR
A[
] --> B[Gateway]
P[A white cat wearing sunglasses on the beach] --> B
B --> C[Orchestrator]
C --> B
B --> D[
]
```
## Models
### Warm Models
The current warm model requested for the `upscale` pipeline is:
* [stabilityai/stable-diffusion-x4-upscaler](https://huggingface.co/stabilityai/stable-diffusion-x4-upscaler):
A text-guided upscaling diffusion model trained on large LAION images,
offering enhanced resolution and controlled noise addition.
For faster responses with different
[upscale](https://huggingface.co/docs/diffusers/en/api/pipelines/stable_diffusion/upscale)
compatible diffusion models, ask Orchestrators to load it on their GPU via the
`ai-video` channel in [Discord Server](https://discord.gg/livepeer).
### On-Demand Models
The following models have been tested and verified for the `upscale` pipeline:
If a specific model you wish to use is not listed, please submit a [feature
request](https://github.com/livepeer/ai-worker/issues/new?assignees=\&labels=enhancement%2Cmodel\&projects=\&template=model_request.yml)
on GitHub to get the model verified and added to the list.
* [stabilityai/stable-diffusion-x4-upscaler](https://huggingface.co/stabilityai/stable-diffusion-x4-upscaler):
A text-guided upscaling diffusion model trained on large LAION images,
offering enhanced resolution and controlled noise addition.
## Basic Usage Instructions
For a detailed understanding of the `upscale` endpoint and to experiment with
the API, see the [Livepeer AI API Reference](/ai/api-reference/upscale).
To generate an image with the `upscale` pipeline, send a `POST` request to the
Gateway's `upscale` API endpoint:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -X POST https:///upscale \
-F model_id="stabilityai/stable-diffusion-x4-upscaler" \
-F image=@/low_res_cat.png \
-F prompt="A white cat"
```
In this command:
* `` should be replaced with your AI Gateway's IP address.
* `model_id` is the diffusion model for image generation.
* The `image` field holds the **absolute** path to the image file to be
upscaled.
* `prompt` is a descriptive text that provides context about the content of the
image.
For additional optional parameters, refer to the
[Livepeer AI API Reference](/ai/api-reference/upscale).
After execution, the Orchestrator processes the request and returns the response
to the Gateway:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"images": [
{
"nsfw": false,
"seed": 3197613440,
"url": "https:///stream/dd5ad78d/7adde483.png"
}
]
}
```
The `url` in the response is the URL of the generated image. Download the image
with:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -O "https:///stream/dd5ad78d/7adde483.png"
```
## Orchestrator Configuration
To configure your Orchestrator to serve the `upscale` pipeline, refer to the
[Orchestrator Configuration](/ai/orchestrators/get-started) guide.
### System Requirements
The following system requirements are recommended for optimal performance:
* [NVIDIA GPU](https://developer.nvidia.com/cuda-gpus) with **at least 24GB** of
VRAM.
## Recommended Pipeline Pricing
We are planning to simplify the pricing in the future so orchestrators can set
one AI price per compute unit and have the system automatically scale based on
the model's compute requirements.
The pricing for the `upscale` pipeline is based on competitor pricing. However,
we strongly encourage orchestrators to set their own pricing based on their
costs and requirements. Setting a competitive price will help attract more jobs,
as Gateways can set their maximum price for a job. The current recommended
pricing for this pipeline is `1.9073484e-08 USD` per **input pixel**
(`height * width`).
## API Reference
Explore the `upscale` endpoint and experiment with the API in the Livepeer AI
API Reference.
# Go
Source: https://docs.livepeer.org/v1/ai/sdks/go
Learn how to run your first AI inference job using the Livepeer AI Go SDK.
To get the most out of this guide, you’ll need to:
* [Choose an AI Gateway](/ai/builders/gateways)
* **Optional**: Get an API key (required for some gateways).
Get the Livepeer AI Golang SDK.
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
go get github.com/livepeer/livepeer-ai-go
```
The first step is to initialize the SDK (with your API key if required).
```go theme={"theme":{"light":"github-light","dark":"dark-plus"}}
package main
import (
"context"
livepeeraigo "github.com/livepeer/livepeer-ai-go"
"github.com/livepeer/livepeer-ai-go/models/components"
"log"
)
func main() {
s := livepeeraigo.New(
livepeeraigo.WithSecurity(""),
)
}
```
Now that you have the SDK installed and initialized, you can use it to request one of the [available AI services](/ai/pipelines/overview).
```go theme={"theme":{"light":"github-light","dark":"dark-plus"}}
package main
import (
"context"
livepeeraigo "github.com/livepeer/livepeer-ai-go"
"github.com/livepeer/livepeer-ai-go/models/components"
"log"
)
func main() {
s := livepeeraigo.New(
livepeeraigo.WithSecurity(""),
)
ctx := context.Background()
res, err := s.Generate.TextToImage(ctx, components.TextToImageParams{
Prompt: "",
})
if err != nil {
log.Fatal(err)
}
if res.ImageResponse != nil {
// handle response
}
}
```
See the examples on GitHub.
## Next steps
Checkout Livepeer AI [API Reference](/ai/api-reference) to learn more about the
Livepeer AI API and the Golang SDK.
# JavaScript
Source: https://docs.livepeer.org/v1/ai/sdks/javascript
Learn how to run your first AI inference job using the Livepeer AI JS SDK.
To get the most out of this guide, you’ll need to:
* [Choose an AI Gateway](/ai/builders/gateways)
* **Optional**: Get an API key (required for some gateways).
Get the Livepeer AI JavaScript SDK.
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
npm add @livepeer/ai
```
The first step is to initialize the SDK (with your API key if required).
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Livepeer } from "@livepeer/ai";
const livepeer = new Livepeer({
httpBearer: "",
});
```
Now that you have the SDK installed and initialized, you can use it to request one of the [available AI services](/ai/pipelines/overview).
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Livepeer } from "@livepeer/ai";
const livepeer = new Livepeer({
httpBearer: "",
});
async function run() {
const result = await livepeer.generate.textToImage({
prompt: "",
});
// Handle the result
console.log(result);
}
run();
```
See the examples on GitHub.
## Next steps
Checkout Livepeer AI [API Reference](/ai/api-reference) to learn more about the
Livepeer AI API and the Javascript SDK.
# AI SDKs
Source: https://docs.livepeer.org/v1/ai/sdks/overview
Explore developer SDKs for interacting with the Livepeer AI API.
## Client-side SDKs
Client-side SDKs simplify the process of using the Livepeer AI API. Just install
a language-specific SDK into your application, choose a
[AI Gateway](/ai/builders/gateways), and get started with only 2 lines of code.
For some gateways, initialisation with an API key is optional.
# Python
Source: https://docs.livepeer.org/v1/ai/sdks/python
Learn how to run your first AI inference job using the Livepeer AI Python SDK.
To get the most out of this guide, you’ll need to:
* [Choose an AI Gateway](/ai/builders/gateways)
* **Optional**: Get an API key (required for some gateways).
Get the Livepeer AI Python SDK.
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
pip install livepeer-ai
```
The first step is to initialize the SDK (with your API key if required).
```python theme={"theme":{"light":"github-light","dark":"dark-plus"}}
from livepeer_ai import Livepeer
s = Livepeer(
http_bearer="",
)
```
Now that you have the SDK installed and initialized, you can use it to request one of the [available AI services](/ai/pipelines/overview).
```python theme={"theme":{"light":"github-light","dark":"dark-plus"}}
from livepeer_ai import Livepeer
s = Livepeer(
http_bearer="",
)
res = s.generate.text_to_image(request={
"prompt": "",
})
if res.image_response is not None:
# handle response
pass
```
See the examples on GitHub.
## Next steps
Checkout Livepeer AI [API Reference](/ai/api-reference) to learn more about the
Livepeer AI API and the Python SDK.
# What's New
Source: https://docs.livepeer.org/v1/ai/whats-new
# Reward Calls
Source: https://docs.livepeer.org/v1/orchestrators/guides/configure-reward-calling
This guide provides instructions and recommendations on the ways to call reward
once you've activated your orchestrator on the Livepeer network.
# About Calling Reward
By default, an active orchestrator will automatically call reward in each round,
submitting an Arbitrum transaction that distributes newly minted LPT rewards to
itself and its delegators.
The amount of LPT rewards distributed by the reward call depends on the
orchestrator's stake, i.e. its own stake and that of its delegators. It is
important to note that for orchestrators with very low stake, the ETH
transaction cost of calling reward may exceed the amount of LPT rewards
distributed. The threshold to profitably call reward depends on several factors,
including but not limited to the market price of LPT and the current inflation
rate.
## Getting Started with Reward Calls
When you first initiate reward calls, it may make economic sense for you to
[disable automatic reward calls](/orchestrators/guides/configure-reward-calling#disable-automatic-reward-calls)
and then
[manually call reward](/orchestrators/guides/configure-reward-calling#manually-call-reward)
in each round instead.
You then can
[enable automatic reward calls](/orchestrators/guides/configure-reward-calling#enable-automatic-reward-calls)
when you are confident that the distribution of LPT relative to the ETH
transaction cost makes economic sense.
## Disable automatic reward calls
Disable automatic reward calls with the `-reward=false` flag:
**For example:**
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
livepeer \
-network arbitrum-one-mainnet \
-reward=false
```
> **Note:** for the purposes of this example above, all other flags are omitted.
## Manually call reward
Use `livepeer_cli` to manually call reward:
1. Estimate the current ETH transaction cost for calling reward and ensure you
have enough ETH in your wallet to execute the transaction.
* The gas cost for a reward call is typically 350k-450k.
* Get the required gas price from [ethgasstation](https://ethgasstation.info/)
or [gasnow](https://www.gasnow.org/).
* The ETH transaction cost will be the gas cost multiplied by the gas price.
2. Make sure `livepeer` is running.
3. Run `livepeer_cli`
4. Enter the number corresponding to the `Invoke "reward"` option
5. Wait for the transaction to confirm.
You can view this in the logs of your orchestrator, which will indicate a
transaction has been submitted and confirmed on-chain.
## Enable automatic reward calls
* To enable automatic reward calls omit the `-reward=false` flag (enabled by
default).
# Connect to Arbitrum
Source: https://docs.livepeer.org/v1/orchestrators/guides/connect-to-arbitrum
`go-livepeer` requires access to the [Arbitrum](https://arbitrum.io/) network
for typical usage.
There are two ways you can connect to the Arbitrum network: via a hosted API
service or via your own self-hosted node. Connecting to a hosted API service is
recommended for users that are getting started and you always have the option to
switch to your own node later on.
### Hosted API services
Hosted API services run Arbitrum nodes on behalf of their users. Popular
services include [Infura](https://infura.io/) and
[Alchemy](https://alchemyapi.io/). Be aware that these services have their own
pricing plans. That being said, the latest versions of `livepeer` should be able
to stay within the request limit for Infura's free tier at least for a single
node.
The following examples describe the required flags to connect to an
EVM-compatible network via Infura (all other flags omitted):
To connect to Arbitrum mainnet:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
livepeer \
-network arbitrum-one-mainnet
-ethUrl https://arbitrum-mainnet.infura.io/v3/ # Visit https://infura.io to obtain a PROJECT_ID
```
### Self-hosted Arbitrum nodes
If you want to run your own Arbitrum node, set one up using the
[instructions from Offchain Labs](https://developer.offchainlabs.com/docs/running_node).
Once your node is synced, connect `livepeer` to the node with the following
flags (all other flags omitted):
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
livepeer \
-network mainnet \
-ethUrl http://localhost:8545 # Assumes that your node is running on the same machine as livepeer
```
## Supported networks
`livepeer` supports the networks listed below. The required flags for connecting
to a network are described (all other flags are omitted).
### Arbitrum One
Arbitrum One is the production public network.
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
livepeer \
-network arbitrum-one-mainnet
-ethUrl # URL for Arbitrum mainnet provider
```
### Private Network
Custom private networks where the Livepeer smart contracts are deployed can be
used for development purposes.
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
livepeer \
-network # Name of network
-ethUrl # URL for private network provider
-ethController # Address of the Controller smart contract deployed on the private network
```
### Offchain
Offchain networks that do not require interaction with the Livepeer smart
contracts can be used for development purposes.
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
livepeer \
-network offchain
```
# Get started
Source: https://docs.livepeer.org/v1/orchestrators/guides/get-started
This guide provides instructions on how to run an orchestrator using the
`Go Livepeer` client. In order to use `Go Livepeer`, the software must first be
installed. There are several ways `Go Livepeer` can be installed depending on
the operating system and the user's choice of installation method, for example
using a container or building from source. Instructions for installing
`Go Livepeer` can be found on the
["Install" guide](/orchestrators/guides/install-go-livepeer). The instructions
on this page assumes `Go Livepeer` and its associated binaries have been
installed successfully.
## Prerequisites
* How to work with a command-line interface
* `wget` is recommended (alternatively, `cURL` can be used)
* [grpcurl](https://github.com/fullstorydev/grpcurl#grpcurl) for interacting
with gRPC servers for testing and monitoring
* Basic familiarity with installing binaries directly or with Docker
* Familiarity with networking concepts and configuration (URLs, ports and port
forwarding, static IPs, etc)
* Access to a
[hosted or self-hosted Arbitrum node](/orchestrators/guides/connect-to-arbitrum)
* Decent bandwidth. Low bandwidth will result in poor performance on the network
* `Go Livepeer` and its associated binaries have been
[installed](/orchestrators/guides/install-go-livepeer) successfully
## Run the Go Livepeer client in orchestrator mode.
### Get a list of your accessible GPUs
Before running the Go Livepeer client in orchestrator mode you must first get a
list of your accessible GPUs. Once you have checked your
[Nvidia driver](https://www.nvidia.com/Download/index.aspx) is installed, your
Nvidia GPUs on your machine should be accessible.
**Note:** Instructions for non-Nvidia GPUs will be added in the future.
* Use the `nvidia-smi` (installed with the Nvidia driver) to print a list of
GPUs:
**For example:**
The following output indicates that there are 5 GPUs accessible on the machine
with IDs from 0 through 4.
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
nvidia-smi -L
GPU 0: GeForce GTX 1070 Ti (UUID: GPU-fcbaffa0-38ae-02d0-5c47-f8fd9922eb75)
GPU 1: GeForce GTX 1070 Ti (UUID: GPU-d46a085e-0d66-0214-34d3-96860a5c778f)
GPU 2: GeForce GTX 1070 Ti (UUID: GPU-32b7c120-c2c9-0069-6130-cb67afd89642)
GPU 3: GeForce GTX 1070 Ti (UUID: GPU-9e4163c3-a120-3cbb-7869-1223b322eab2)
GPU 4: GeForce GTX 1070 Ti (UUID: GPU-3370975a-f669-e108-6428-602be9eba7d4)
```
### Run the `livepeer` command
You're now ready to run `Go Livepeer` in orchestrator mode.
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
livepeer \
-network arbitrum-one-mainnet \
-ethUrl \
-ethAcctAddr \ # Only required if you already have an ETH account you want to use
-orchestrator \
-transcoder \
-nvidia \ # Only required for transcoding with Nvidia GPUs
-pricePerUnit \
-serviceAddr # Hostname/IP:port
```
#### Flags
* Use the `-ethUrl` flag to
[connect to the arbitrum network](/orchestrators/guides/connect-to-arbitrum)
using a hosted or self hosted Arbitrum node.
* Use the `-ethAcctAddr` flag to specify the ETH account address that you want
the node to use.
> **Note:** This flag is only required if you already have an account that you
> want to use.
* Be sure the private key for the account address is stored in the keystore
directory.
> This defaults to `~/.lpData/arbitrum-one-mainnet/keystore`.
> **Note:** It is paramount that you securely manage the private key, as it
> controls your wallet and funds.
* Use both the `-orchestrator` and `-transcoder` flags to run the binary in
orchestrator mode transcoding video.
* `-nvidia` is used to specify a comma delimited string of Nvidia GPU IDs. The
flag is only required when transcoding with Nvidia GPUs
* `-pricePerUnit` is used to specify the price (wei per pixel) for transcoding.
The flag is required on startup, but the value can be changed later.
* `-serviceAddr` is used to specify the publicly accessible address that the
orchestrator should receive requests at. Changing this requires a blockchain
transaction, so it's preferable to use a hostname for a domain you own, not an
IP address that may change.
### Automatic ETH account creation
If you did not use the `-ethAcctAddr` flag, an ETH account will automatically be
created and you will be prompted for a passphrase:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
I0302 15:26:06.886115 25387 accountmanager.go:49] No Ethereum account found. Creating a new account
I0302 15:26:06.886134 25387 accountmanager.go:50] This process will create a new Ethereum account for this Livepeer node
I0302 15:26:06.886138 25387 accountmanager.go:51] Please enter a passphrase to encrypt the Private Keystore file for the Ethereum account.
I0302 15:26:06.886143 25387 accountmanager.go:52] This process will ask for this passphrase every time it is launched
I0302 15:26:06.886147 25387 accountmanager.go:53] (no characters will appear in Terminal when the passphrase is entered)
Passphrase:
```
This account will be used to identify your orchestrator on the network. **By
default**, the private key for the account will be stored under:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
~/.lpData/arbitrum-one-mainnet/keystore
```
> **Note:** It is **very important** to safeguard both the private key and the
> passphrase because together they allow someone to sign messages and send
> transactions using the account.
### Check the node is accessible
Once your node completes the start up process, you should see the following logs
indicating that the node is publicly accessible:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
I0302 15:27:26.456804 25418 rpc.go:167] Listening for RPC on :8935
I0302 15:27:28.463151 25418 rpc.go:207] Received Ping request
```
## Fund your account with ETH and LPT
In order to activate on Livepeer, your account should have:
* arbETH to pay for transaction fees
* Recommendation: Start with a small amount and add more when needed.
`livepeer` and `livepeer_cli` will inform you if your account's ETH balance
is insufficient to pay for transaction fees when attempting to submit the
transactions
* LPT to stake in order to activate
* Recommendation: Check the [explorer](https://explorer.livepeer.org/) and
find the 100th orchestrator with the most stake. This is the amount of stake
required for you to activate. Note that more stake will help you receive
more work.
If your orchestrator drops out of the active set (top 100 in stake), it will
not be reactivated by the protocol unless (1) you re-register or (2) your
stake amount (delegated or self-stake) changes such that you are in the top
100 again. If you are inactive and your stake amount places you in the top 100
but your stake does not change, your orchestrator will not be automatically
added to the active set.
## Activate
The active orchestrator set consists of the top 100 orchestrators with the most
LPT stake on the network. You can check this on the
[Livepeer Explorer](https://explorer.livepeer.org/).
### Activate using `livepeer_cli`
Once the orchestrator has been started and is connected to Arbitrum you can
activate the orchestrator:
1. Run `livepeer_cli`
2. Enter the number corresponding to the
`Invoke multi-step "become an orchestrator"` option.
3. Set the percentage of LPT rewards that you will keep (the rest will be shared
with your delegators):
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
Enter block reward cut percentage (current=0 default=10) - >
```
4. Set the percentage of ETH fees that you will keep (the rest will be shared
with your delegators):
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
Enter fee cut percentage (current=100 default=95) - >
```
5. Set the number of pixels in a single unit of work you will charge a price for
(You can use the default (1) and change this later if needed):
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
Enter amount of pixels that make up a single unit (default: 1 pixel) >
```
6. Set the price (in `Wei`) that you will charge per unit of work. This can be
the same as or different from the value used with the `-pricePerUnit` flag
when starting your orchestrator:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
Enter the price for 1 pixels in Wei (required) >
```
7. Set the publicly accessible service address that your orchestrator will
receive requests. This should be the same as the value used with the
`-serviceAddr` flag when starting your orchestrator, i.e.:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
Enter the public host:port of node (default: 1.1.1.1:8935)>
```
8. Set the amount of LPTU (1 LPT = 1e18 LPTU) that you want to stake. It is
important this amount is denominated in LPTU; if you want to bond 5 LPT, you
would enter 5000000000000000000.
**For example:**
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
You must bond to yourself in order to become a orchestrator
Enter bond amount - >
```
> **Note:** If the active orchestrator set is full (i.e. at 100 orchestrators),
> the minimum stake you need to stake to activate is the lowest total stake of
> an orchestrator in the active set found on the
> [Livepeer Explorer](https://explorer.livepeer.org/).
9. Wait for transactions to confirm. You should see the logs of your
orchestrator indicating transactions are submitted and confirmed on-chain.
Once the transactions have confirmed, your orchestrator will join the active
set in the following round.
### Navigate to the Livepeer Explorer on Arbitrum Mainnet
Once you have activated your orchestrator on the Arbitrum Mainnet, you should be
able to see it on the
[Livepeer Explorer](https://explorer.livepeer.org/leaderboard).
# Install Go Livepeer
Source: https://docs.livepeer.org/v1/orchestrators/guides/install-go-livepeer
Learn how to install go-livepeer and become an orchestrator
Depending on your workflow, you may prefer to install `go-livepeer` using a
binary release, a Docker image, or from source.
## Install using a Binary Release
### Dependencies
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
# For ubuntu
apt install curl coreutils gnupg2
# For macOS
brew install curl coreutils gnupg
```
### Darwin (macOS)
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
# is the release version, e.g. v0.5.35
# is the chip architecture (use arm64 for M1 and amd64 for Intel)
wget https://github.com/livepeer/go-livepeer/releases/download//livepeer-darwin-.tar.gz
# Next, extract it
tar -zxvf livepeer-darwin-.tar.gz
# Finally, move it to the appropriate directory
mv livepeer-darwin-/* /usr/local/bin/
```
### Linux
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
# is the release version, e.g. v0.5.35
# is the chip architecture (use arm64 or amd64)
# Fetch the latest release
wget https://github.com/livepeer/go-livepeer/releases/download//livepeer-linux-.tar.gz
# Next, extract it
tar -zxvf livepeer-linux-amd64.tar.gz
# Finally, move it to the appropriate directory
mv livepeer-linux-amd64/* /usr/local/bin/
```
### Linux GPU
There is a separate binary which supports transcoding on the NVIDIA GPU. The
requirement for this binary is to have version 12 of the
[CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) installed on your
machine.
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
# is the release version, e.g. v0.5.35
# is the chip architecture (use arm64 or amd64)
# Fetch the latest release
wget https://github.com/livepeer/go-livepeer/releases/download//livepeer-linux-gpu-.tar.gz
# Next, extract it
tar -zxvf livepeer-linux-gpu-.tar.gz
# Finally, move it to the appropriate directory
mv livepeer-linux-gpu-/* /usr/local/bin/
```
### Windows
```shell theme={"theme":{"light":"github-light","dark":"dark-plus"}}
# is the release version, e.g. v0.5.35
# Fetch the latest release .zip
wget https://github.com/livepeer/go-livepeer/releases/download//livepeer-windows-amd64.zip
# Next, extract it
unzip livepeer-windows-amd64.zip
# Finally, move it to the appropriate directory, e.g. C:\Users\UserName\livepeer-folder
move livepeer-windows-amd64 e.g. C:\Users\UserName\livepeer-folder
```
At this time Livepeer does not provide automatic updates. You can perform a
manual update or use a script. A community-created [Bash script to update
Livepeer is available on the livepeer
Forum](https://forum.livepeer.org/t/bash-script-to-update-livepeer/1513).
### Third-party packages
Packages for different Linux distributions are maintained by Livepeer community
members. Before using these packages, please verify that they have been updated
to use the
[latest builds of go-livepeer](https://github.com/livepeer/go-livepeer/releases).
This list will be updated as a best-effort, but we cannot guarantee if
individual packages are up to date or verify their integrity.
In the future, Livepeer core contributors may publish official packages for the
distributions below.
| Platform | Installation | Source |
| ---------- | ---------------------- | ---------------------------------------------------------------------------------------------------------- |
| Arch Linux | `paru go-livepeer-bin` | [https://aur.archlinux.org/packages/go-livepeer-bin/](https://aur.archlinux.org/packages/go-livepeer-bin/) |
## Install using a Docker image
### Prerequisites
If you do not have Docker installed, you will need to install it using the guide
[here](https://docs.docker.com/get-docker/) before running the commands below.
### Installation
With every release, Docker images are pushed to
[DockerHub](https://hub.docker.com/r/livepeer/go-livepeer).
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
# is the release version i.e. 0.5.14
docker pull livepeer/go-livepeer:
```
### Running livepeer-cli with Docker
Once you've pulled the image, retrieve the image id and start the container.
**Any flags you provide will be passed to the binary**, so you can pass
[your configuration flags](/references/go-livepeer/cli-reference) here.
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
docker run
# GPU support (Transcoder-only)
docker run --gpus all
```
Once you've started the container, retrieve the name and start the CLI
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
docker exec -it livepeer_cli
```
### Installing pre-releases with Docker
To pull the latest pre-release version:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
docker pull livepeer/go-livepeer:master
```
## Build from source
### System dependencies
Building `livepeer` requires some system dependencies.
#### Linux (Ubuntu: 16.04 or 18.04)
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
apt-get update && apt-get -y install build-essential pkg-config autoconf git curl yasm
```
#### Linux (Ubuntu: 20.04 or newer)
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
apt-get -y install protobuf-compiler-grpc golang-goprotobuf-dev yasm pkg-config
```
#### Linux GPU support
To enable transcoding using Nvidia GPUs on Linux systems
* [CUDA Toolkit](https://developer.nvidia.com/cuda-toolkit) must be installed on
the system and available on the `LIBRARY_PATH`
* `clang` must be installed as well. The script that will install `ffmpeg`
dependencies uses `which clang` command to determine whether `clang` is
installed or not. Please check this on your system. If the path is empty,
please install `clang`. For example on the Ubuntu machine one can do
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
apt-get -y install clang clang-tools
export LIBRARY_PATH="/usr/local/cuda/lib64:${LIBRARY_PATH}"
```
#### Darwin (macOS)
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
brew update && brew install pkg-config autoconf
```
### Go
Building `livepeer` requires Go. Follow the
[official Go installation instructions](https://golang.org/doc/install).
### Build and install
1. Clone the repository:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
git clone https://github.com/livepeer/go-livepeer.git
cd go-livepeer
```
2. Install `ffmpeg` dependencies:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
./install_ffmpeg.sh
```
3. Set build environment variables.
Set the `PKG_CONFIG_PATH` variable so that `pkg-config` can find the `ffmpeg`
dependency files installed in step 2:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
# install_ffmpeg.sh stores ffmpeg dependency files in this directory by default
export PKG_CONFIG_PATH=~/compiled/lib/pkgconfig
```
Set the `BUILD_TAGS` variable to enable mainnet support:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
export BUILD_TAGS=mainnet
# To build with support for only development networks and the Rinkeby test network
# export BUILD_TAGS=rinkeby
# To build with support for only development networks
# export BUILD_TAGS=dev
```
4. Build and install `livepeer`:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
make
cp livepeer* /usr/local/bin
```
## Troubleshooting
### Error while loading shared libraries
You may encounter the following issue when running the `livepeer` binary.
```
error while loading shared libraries: libnppig.so.11: cannot open shared object file: No such file or directory.
```
This means that you have installed the Livepeer GPU binary but it is unable to
access your CUDA Toolkit libraries. If you do not intend to use GPU transcoding,
please download `livepeer` instead of `livepeer-gpu`. However, if you wish to
use GPU transcoding, please ensure that the CUDA Toolkit is installed and add
its path to the shared libraries path.
```
export LD_LIBRARY_PATH=${HOME}/compiled/lib:/usr/local/cuda/lib64:${LD_LIBRARY_PATH}
```
# Introduction
Source: https://docs.livepeer.org/v1/orchestrators/introduction
Explore APIs, guides, and examples
If you're looking for documentation on Livepeer's hosted realtime
StreamDiffusion AI platform "Daydream", please navigate
[here](https://pipelines.livepeer.org/docs)
Learn how to add live and on-demand video experience to your app using Livepeer
Studio. Effortlessly manage livestreams, video uploads, API keys, network usage,
billing, and more.
Get started with Livepeer Studio in less than 5 minutes.
Learn how to add live or on-demand video experiences to your app.
Explore the Livepeer Studio API
Get up and running with SDKs and pre-built UI components
## Explore the Livepeer Studio SDKs
Explore developer SDKs, pre-built UI components, and tools for interacting with
the Livepeer Studio API.
### Server-side SDKs
### React Components
Fully customizable video player component for seamless playback
Full-featured broadcast component with controls, settings, and device
selection
[View all developer tools](/sdks/introduction)
# CLI
Source: https://docs.livepeer.org/v1/orchestrators/livepeer-studio-cli
Generate a new Livepeer app.
The Livepeer Studio CLI is a command line tool that helps you generate a new
Livepeer app in just a few seconds.
## Getting Started
First, create a Livepeer API key
[here](https://livepeer.studio/dashboard/developers/api-keys). Next, use the CLI
to generate a new project.
```sh theme={"theme":{"light":"github-light","dark":"dark-plus"}}
npx @livepeer/create
```
When prompted, enter your Livepeer **API key** and **Stream ID**.
Once the app has been created, `cd` into the new directory and run the start
command:
```sh theme={"theme":{"light":"github-light","dark":"dark-plus"}}
npm run dev
```
# Quickstart
Source: https://docs.livepeer.org/v1/orchestrators/quick-start
Learn how to create an API key and start adding live and on-demand video to your app or website!
First, go to [Livepeer Studio](https://livepeer.studio), if you haven't already,
and create an account. Once you've created an account, you'll be able to create
an API key by clicking on the "Create API Key" button on Developers page.
We do not recommend using ["CORS-enabled" API
keys](/api-reference/overview/authentication) - they will be deprecated in an
upcoming release. We recommend making requests from your backend to the
Livepeer Studio API.
You can now use this API key in Livepeer SDKs and APIs in order to authenticate
your requests and start building.
We recommend creating separate accounts for your development and production
environments. This will allow you to easily isolate your environments. We will
be shipping a solution for multi-environment management soon.
In this exampe, we will use Javascript anld React to upload a video. Make sure
to set up a React app first.
## Install the JS SDK and Livepeer React
We install both the NodeJS SDK (which works in all JS environments with `fetch`)
and the Livepeer React library, which provides composable React primitives for
building video apps.
```
npm install livepeer @livepeer/react
```
## Set up the SDK
Add an API key to the environment variables, and construct a new Livepeer SDK
client.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import Livepeer from "livepeer";
const livepeer = new Livepeer({
apiKey: process.env.YOUR_PRIVATE_API_KEY,
});
```
## Retrieve playback info
We can now use the SDK on the backend to fetch the playback info for our asset.
This asset was uploaded using the dashboard, but this can also be an asset
created from an application.
```ts theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { getSrc } from "@livepeer/react/external";
const playbackId = "f5eese9wwl88k4g8";
export const getPlaybackSource = () => {
const playbackInfo = await livepeer.playback.get(playbackId);
const src = getSrc(playbackInfo.playbackInfo);
return src;
};
```
## Play the asset
We can now use Player component from the SDK to play a video. In the below
example, we style the elements with Tailwind, but you can use any styling
solution:
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { PauseIcon, PlayIcon } from "@livepeer/react/assets";
import { getSrc } from "@livepeer/react/external";
import * as Player from "@livepeer/react/player";
import { vodSource } from "./source";
export const DemoPlayer = ({ src }: { src: Src[] | null }) => {
return (
);
};
```
## Start building
Check out the [SDKs](/sdks/introduction) and
[API Reference](/api-reference/overview/introduction) pages to learn more about
how to use the SDKs and API to build your application.
You can also refer to the [Guides](/developers/guides/overview) section for more
in-depth tutorials on how to use the SDKs and API to build specific
applications.
Don't know where to start? Check out these four tutorials:
* [Learn how to create a livestream](/developers/guides/create-livestream)
* [Learn how to listen to asset events](/developers/guides/listen-to-asset-events)
# Broadcast
Source: https://docs.livepeer.org/v1/sdks/react/Broadcast
A comprehensive example showcasing the integration of various `@livepeer/react/broadcast` components to create a full-featured broadcast interface with controls, settings, and device selection.
This comprehensive example includes broadcasting controls like audio and video
toggles, screenshare capabilities, fullscreen and picture-in-picture modes,
along with advanced settings for device selection and error handling.
It uses Tailwind CSS for styling, but this can be replaced with any styling
solution.
## Broadcast
### Usage
Here's how a full Broadcast experience can be built with the primitives:
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { cn } from "@/lib/utils";
import {
DisableAudioIcon,
DisableVideoIcon,
EnableAudioIcon,
EnableVideoIcon,
EnterFullscreenIcon,
ExitFullscreenIcon,
LoadingIcon,
OfflineErrorIcon,
PictureInPictureIcon,
SettingsIcon,
StartScreenshareIcon,
StopIcon,
StopScreenshareIcon,
} from "@livepeer/react/assets";
import * as Broadcast from "@livepeer/react/broadcast";
import * as Popover from "@radix-ui/react-popover";
import { CheckIcon, ChevronDownIcon, XIcon } from "lucide-react";
import React from "react";
import { toast } from "sonner";
export function BroadcastWithControls({
streamKey,
}: {
streamKey: string | null;
}) {
const ingestUrl = getIngest(streamKey);
return !ingestUrl ? (
) : (
<>
error?.type === "permissions"
? toast.error(
"You must accept permissions to broadcast. Please try again."
)
: null
}
aspectRatio={16 / 9}
ingestUrl={ingestUrl}
>
Broadcast failed
There was an error with broadcasting - it is retrying in the
background.
);
}
);
export const SourceSelectComposed = React.forwardRef(
(
{
name,
type,
className,
}: { name: string; type: "audioinput" | "videoinput"; className?: string },
ref: React.Ref | undefined
) => (
{(devices) =>
devices ? (
<>
{devices?.map((device) => (
{device.friendlyName}
))}
>
) : (
There was an error fetching the available devices.
)
}
)
);
const RateSelectItem = React.forwardRef<
HTMLDivElement,
Broadcast.SelectItemProps
>(({ children, className, ...props }, forwardedRef) => {
return (
{children}
);
});
```
# Player
Source: https://docs.livepeer.org/v1/sdks/react/Player
A comprehensive example showcasing the integration of various `@livepeer/react/player` components to create a full-featured player interface with controls and settings.
This comprehensive example includes broadcasting controls like fullscreen and
picture-in-picture modes, play/pause, etc.
It uses Tailwind CSS for styling, but this can be replaced with any styling
solution.
## Player
### Usage
Here's how a full Player experience can be built with the primitives:
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { cn } from "@/lib/utils";
import {
ClipIcon,
EnterFullscreenIcon,
ExitFullscreenIcon,
LoadingIcon,
MuteIcon,
PauseIcon,
PictureInPictureIcon,
PlayIcon,
SettingsIcon,
UnmuteIcon,
} from "@livepeer/react/assets";
import * as Player from "@livepeer/react/player";
import * as Popover from "@radix-ui/react-popover";
import { ClipPayload } from "livepeer/dist/models/components";
import { CheckIcon, ChevronDownIcon, XIcon } from "lucide-react";
import React, { useCallback, useTransition } from "react";
import { toast } from "sonner";
import { Src } from "@livepeer/react";
import { createClip } from "./actions";
export function PlayerWithControls(props: { src: Src[] | null }) {
if (!props.src) {
return (
);
}
return (
Stream is offline
Playback will start automatically once the stream has started
Stream is private
It looks like you don't have permission to view this content
);
function Clip({ className }: { className?: string }) {
const [isPending, startTransition] = useTransition();
const createClipComposed = useCallback((opts: ClipPayload) => {
startTransition(async () => {
const result = await createClip(opts);
if (result.success) {
toast.success(
{
"You have created a new clip - in a few minutes, you will be able to view it at "
}
this link
{"."}
);
} else {
toast.error(
"Failed to create a clip. Please try again in a few seconds."
);
}
});
}, []);
return (
{isPending ? (
) : (
)}
);
}
const Settings = React.forwardRef(
(
{ className }: { className?: string },
ref: React.Ref | undefined
) => {
return (
e.stopPropagation()}
>
Settings
0.5x0.75x1x (normal)1.25x1.5x1.75x2x
Auto (HD+)
1080p (HD)
720p
480p
360p
);
}
);
const RateSelectItem = React.forwardRef<
HTMLDivElement,
Player.RateSelectItemProps
>(({ children, className, ...props }, forwardedRef) => {
return (
{children}
);
});
const VideoQualitySelectItem = React.forwardRef<
HTMLDivElement,
Player.VideoQualitySelectItemProps
>(({ children, className, ...props }, forwardedRef) => {
return (
{children}
);
});
```
# Audio
Source: https://docs.livepeer.org/v1/sdks/react/broadcast/Audio
The `AudioEnabledTrigger` and `AudioEnabledIndicator` components provide controls and visual cues for audio input state during media broadcast.
`AudioEnabledTrigger` and `AudioEnabledIndicator` integrate together to form
the typical microphone on/off interaction for broadcasts. They do not have to
be used together and can combine with other components.
## Features
* Controls the audio input state and conditionally renders based on audio input
on/off status, customizable with the `matcher` pattern
* Keyboard hotkeys and adheres to [WAI-ARIA](https://w3c.github.io/aria/) design
patterns
* Handles all common browser APIs, and old WebKit/Firefox APIs (see
[caniuse](https://caniuse.com/mdn-api_mediadevices_getusermedia))
The `getUserMedia` browser API used to get the audio is only available in
secure contexts (HTTPS).
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Broadcast from "@livepeer/react/broadcast";
export default () => (
);
```
## Props
### `AudioEnabledTrigger`
Accepts all props for a typical button element.
### `AudioEnabledIndicator`
##### `forceMount`
A boolean that, when true, ensures the component is always mounted. This is
particularly useful for managing animations with external animation libraries.
##### `matcher`
A prop intended to define the circumstances under which the
`AudioEnabledIndicator` should be visible. It can be a boolean that corresponds
directly to the audio state or a function that provides custom logic for
visibility determination based on the audio state.
## Data Attributes
### `AudioEnabledTrigger`
#### `data-livepeer-controls-audio-enabled-trigger`
Serves to identify the component's role within the broadcast interface.
#### `data-enabled`
Indicates the current audio state, `"true"` when audio is enabled and `"false"`
when it is disabled.
### `AudioEnabledIndicator`
#### `data-livepeer-controls-audio-enabled-indicator`
Identifies the component's role as a visual indicator of the audio state within
the broadcast interface.
#### `data-enabled`
Shows the current audio state, `"true"` when audio is enabled and `"false"` when
it is disabled.
#### `data-visible`
Reflects the visibility status of the indicator, with `"true"` meaning it's
currently visible based on the `matcher` or audio state and `"false"` denoting
it's not visible.
This is often used for dynamically applying enter/exit CSS animations.
# Camera
Source: https://docs.livepeer.org/v1/sdks/react/broadcast/Camera
The `VideoEnabledTrigger` and `VideoEnabledIndicator` components provide gateways with interactive controls and visual cues to manage the video enabled state during a broadcast.
`VideoEnabledTrigger` and `VideoEnabledIndicator` integrate together to form
the typical video on/off interaction for broadcasts. They do not have to be
used together and can combine with other components.
## Features
* Controls the video input state and conditionally renders based on video input
on/off status, customizable with the `matcher` pattern
* Keyboard hotkeys and adheres to [WAI-ARIA](https://w3c.github.io/aria/) design
patterns
* Handles all common browser APIs, and old WebKit/Firefox APIs (see
[caniuse](https://caniuse.com/mdn-api_mediadevices_getusermedia))
The `getUserMedia` browser API used to get the video is only available in
secure contexts (HTTPS).
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Broadcast from "@livepeer/react/broadcast";
export default () => (
);
```
## Props
### `VideoEnabledTrigger`
Accepts all props for a typical button element.
### `VideoEnabledIndicator`
##### `forceMount`
A boolean that, when true, ensures the component is always mounted. This is
particularly useful for managing animations with external animation libraries.
##### `matcher`
A prop intended to define the circumstances under which the
`VideoEnabledIndicator` should be visible. It can be a boolean that corresponds
directly to the audio state or a function that provides custom logic for
visibility determination based on the audio state.
## Data Attributes
### `VideoEnabledTrigger`
#### `data-livepeer-controls-video-enabled-trigger`
Serves to identify the component's role within the broadcast interface.
#### `data-enabled`
Indicates the current video state, `"true"` when video is enabled and `"false"`
when it is disabled.
### `VideoEnabledIndicator`
#### `data-livepeer-controls-video-enabled-indicator`
Identifies the component's role as a visual indicator of the video state within
the broadcast interface.
#### `data-enabled`
Shows the current video enabled state, `"true"` when video is enabled and
`"false"` when it is disabled.
#### `data-visible`
Reflects the visibility status of the indicator, with `"true"` meaning it's
currently visible based on the `matcher` or video state and `"false"` denoting
it's not visible.
This is often used for dynamically applying enter/exit CSS animations.
# Container
Source: https://docs.livepeer.org/v1/sdks/react/broadcast/Container
The `Container` component is the container element for Broadcast. It wraps all other elements and acts as an aspect ratio container by default.
The `Container` component acts as the container div element for the Broadcast,
using either
[@radix-ui/react-aspect-ratio](https://www.radix-ui.com/primitives/docs/components/aspect-ratio)
or a standard div element. It selectively renders one of these based on the
presence of an `aspectRatio` prop. We show above how to disable the aspect
ratio element.
## Features
* Provides an aspect ratio container to reduce
[Cumulative Layout Shift](https://web.dev/cls/)
* Dynamic data attributes for custom styling based on the current media state
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Broadcast from "@livepeer/react/broadcast";
export default () => (
{/* Place child elements here, like Video and Controls */}
{/* Or place other controls outside of here, to not be bound by the aspect ratio Container */}
);
```
## Data Attributes
These attributes are dynamically updated based on the current state.
### `data-livepeer-aspect-ratio` or `data-livepeer-wrapper`
Indicates the container type. It's present if the container is an aspect ratio
container (with `data-livepeer-aspect-ratio`) or a regular div (with
`data-livepeer-wrapper`).
When `aspectRatio` is set to `null` on the Root component, then it will be a
regular div wrapper with `position: relative`.
### `data-fullscreen`
Reflects whether the content is in fullscreen mode.
* `"true"`: The content is in fullscreen mode.
* `"false"`: The content is not in fullscreen mode.
### `data-playing`
Indicates if the content is currently playing.
* `"true"`: The content is playing.
* `"false"`: The content is not playing.
### `data-can-play`
Shows if the content can be played.
* `"true"`: The content can be played.
* `"false"`: The content cannot be played due to some restrictions or lack of
data.
### `data-playback-rate`
Displays the current playback rate.
* `"normal"`: The playback is at normal speed.
* `"fast"`: The playback is at a speed faster than normal.
* `"slow"`: The playback is at a speed slower than normal.
* `"constant"`: The playback rate is constant (neither fast nor slow).
### `data-error`
Indicates if there is an error in the content.
* `"true"`: There is an error in the content.
* `"false"`: There are no errors in the content.
### `data-loading`
Shows if the content is loading.
* `"true"`: The content is loading.
* `"false"`: The content is not loading.
### `data-live`
Indicates if the content is live.
* `"true"`: The content is live.
* `"false"`: The content is not live.
### `data-has-played`
Reflects if the content has been played.
* `"true"`: The content has been played at least once.
* `"false"`: The content has not been played yet.
### `data-controls-hidden`
Shows if the controls are hidden.
* `"true"`: The controls are hidden.
* `"false"`: The controls are visible.
### `data-picture-in-picture`
Indicates if the picture-in-picture mode is active.
* `"true"`: The picture-in-picture mode is active.
* `"false"`: The picture-in-picture mode is not active.
### `data-video-quality`
Displays the current video quality, directly reflecting the `videoQuality` value
from the state. It can be a string indicating the quality level (e.g., `"720p"`,
`"1080p"`).
# Controls
Source: https://docs.livepeer.org/v1/sdks/react/broadcast/Controls
The `Controls` component provides an interactive container for all other broadcast control elements such as `AudioTrigger`, `Fullscreen`, etc.
`Controls` serves as the interactive layer for broadcast control actions, dynamically displayed based on the broadcast state, loading state, or presence of an error. It is designed to automatically show upon user interaction with the Container element and hides based on the `Root` component's `autohide` property.
By default, controls are shown during hover or interaction.
## Features
* Automatic conditional rendering based on user interactions
* Compatible with CSS animations for dynamic enter/exit animations
The visibility of `Controls` is managed automatically, relying on the
`autohide` property of the `Root` component to determine how long after a user
interaction to wait before hiding.
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Broadcast from "@livepeer/react/broadcast";
export default () => (
{/* Place interactive control elements here, like enable/disable broadcast, screenshare toggle, etc. */}
);
```
## Props
### `forceMount`
Ensures the component is always in the DOM, useful for animation controls.
### `autoHide`
Defines the auto-hide delay in milliseconds after user interaction. Default is
3000ms. Set to 0 to disable auto-hide.
## Data Attributes
### `data-livepeer-controls`
Serves to identify the component's role within the broadcast interface.
### `data-visible`
Reflects the visibility status of the controls. It's `"true"` when the controls
are currently visible (not hidden, not loading, no error present, and WebRTC is
supported), and `"false"` when they're not visible.
This is often used for dynamically applying enter/exit CSS animations.
# Enable
Source: https://docs.livepeer.org/v1/sdks/react/broadcast/Enabled
The `EnabledTrigger` and `EnabledIndicator` components provide gateways with interactive controls and visual cues to manage the "enabled" state of the broadcast.
The `Enabled` components are used to generally start and stop the broadcast.
The broadcast, by default, starts disabled so the user can preview their video
before going live.
## Features
* Conditional rendering based on the enabled state, customizable with the
`matcher` pattern
* Dynamic data attributes for custom styling based on the current enabled state
Toggling "enabled" turns WHIP WebRTC ingest on or off, which when "on" the
Broadcast component will make a POST request with an SDP payload to the WHIP
endpoint. When "off", it will stop sending data to the WebRTC ingest.
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Broadcast from "@livepeer/react/broadcast";
export default () => (
);
```
## Props
### `EnabledTrigger`
The component accepts all props suitable for a button element.
### `EnabledIndicator`
The component accepts all props for a span element.
##### `forceMount`
A boolean that, when true, ensures the component is always mounted. This is
particularly useful for managing animations with external animation libraries
and ensuring visibility during dynamic broadcast scenarios.
##### `matcher`
A prop intended to define the circumstances under which the `EnabledIndicator`
should be visible. It can be a boolean that directly corresponds to the enabled
state or a function providing custom logic for visibility determination based on
the enabled state.
## Data Attributes
### `EnabledTrigger`
#### `data-livepeer-controls-enabled-trigger`
Serves to identify the component's role within the broadcast interface.
#### `data-enabled`
Indicates the current broadcast state, `"true"` when broadcasting is enabled and
`"false"` when it is disabled.
### `EnabledIndicator`
#### `data-livepeer-controls-enabled-indicator`
Identifies the component's role as a visual indicator of the broadcast state
within the broadcast interface.
#### `data-enabled`
Shows the current broadcast state, `"true"` when broadcasting is enabled and
`"false"` when it is disabled.
#### `data-visible`
Reflects the visibility status of the indicator, with `"true"` meaning it's
currently visible based on the `matcher` or broadcast state and `"false"`
denoting it's not visible.
This is often used for dynamically applying enter/exit CSS animations.
# Error
Source: https://docs.livepeer.org/v1/sdks/react/broadcast/Error
The `ErrorIndicator` component is a visual representation of error states in broadcast based on error types.
The `Error` component can be shown for all error types, or a subset of them.
It is usually recommended to be more granular in the error types, since some
errors are more "fatal" and some cannot be recovered from.
## Features
* Conditional rendering based on the error state, customizable with the
`matcher` pattern
* Dynamic data attributes for custom styling based on the current error state
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Broadcast from "@livepeer/react/broadcast";
export default () => (
);
```
## Props
The component accepts all props suitable for a div element, in addition to the
following specific props:
### `forceMount`
A boolean to force the component's presence in the DOM, useful for controlling
animations with external libraries.
### `matcher`
A prop to define the condition under which the `ErrorIndicator` should be
visible. It can be a string indicating a broad category of errors (like `"all"`
or `"not-permissions"`) or a more specific error type. Alternatively, it can be
a function for custom logic, receiving the PlaybackError type and returning a
boolean for whether it should be shown.
## Data Attributes
### `data-livepeer-error-indicator`
Always present to indicate the component's role.
### `data-error-state`
Indicates whether there is an error (`"true"` or `"false"`).
### `data-error-type`
Specifies the type of the current error or `"none"` if no error is present.
Could be one of:
`"offline" | "access-control" | "fallback" | "permissions" | "unknown" | "none"`
### `data-visible`
Reflects whether the indicator is currently visible (`"true"` or `"false"`).
This is often used for dynamically applying enter/exit CSS animations.
# Fullscreen
Source: https://docs.livepeer.org/v1/sdks/react/broadcast/Fullscreen
The `FullscreenIndicator` and `FullscreenTrigger` components provide visual cues and interactive elements for fullscreen functionality.
## Features
* Automatic conditional rendering based on fullscreen status and browser API
availability, customizable with the `matcher` pattern
* Handles all browser APIs back to IE11, with special handling for iOS
* Compatible with CSS animations for dynamic enter/exit animations
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Broadcast from "@livepeer/react/broadcast";
export default () => (
);
```
## Props
### `FullscreenIndicator`
#### `forceMount`
A boolean that, when true, keeps the component mounted at all times, useful for
controlling animations with external libraries.
#### `matcher`
A prop to define the condition under which the `FullscreenIndicator` should be
visible. It can be a boolean directly matching the fullscreen state or a
function providing custom logic to determine visibility.
### `FullscreenIndicator`
#### `forceMount`
A boolean that, when true, keeps the component mounted at all times, useful for
controlling animations with external libraries.
#### `matcher`
A prop to define the condition under which the `FullscreenIndicator` should be
visible. It can be a boolean directly matching the fullscreen state or a
function providing custom logic to determine visibility.
## Data Attributes
### `FullscreenIndicator`
#### `data-livepeer-controls-fullscreen-indicator`
Indicates the component's role.
#### `data-fullscreen`
Shows the current fullscreen state (`"true"` or `"false"`).
#### `data-visible`
Reflects whether the indicator is currently visible (`"true"` or `"false"`).
This is often used for dynamically applying enter/exit CSS animations.
### `FullscreenTrigger`
#### `data-livepeer-controls-fullscreen-trigger`
Indicates the component's role.
#### `data-fullscreen-state`
Shows the current fullscreen state (`"true"` or `"false"`). lscreen state
(`"true"` or `"false"`).
# Loading
Source: https://docs.livepeer.org/v1/sdks/react/broadcast/Loading
The `LoadingIndicator` component is a visual indicator of the loading state of the media.
The `Loading` component can be composed with any other elements. Typically it
is combined with Poster
## Features
* Conditional rendering based on the error state, customizable with the
`matcher` pattern
* Dynamic data attributes for custom styling based on the current error state
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Broadcast from "@livepeer/react/broadcast";
export default () => (
);
```
## Props
The component accepts all props suitable for a div element, in addition to the
following specific props:
### `forceMount`
A boolean value that, when set to true, ensures the component is always mounted.
This is particularly useful for managing animations with external animation
libraries.
### `matcher`
A prop intended to define the circumstances under which the `LoadingIndicator`
should be visible. It can be a direct boolean comparison with the loading state
or a function that provides custom logic for visibility determination.
## Data Attributes
### `data-livepeer-loading-indicator`
Serves to identify the component's role.
### `data-loading`
Displays the current loading state, `"true"` when media is loading and `"false"`
when it's not.
### `data-visible`
Indicates the visibility status of the indicator, with `"true"` meaning it's
currently visible and `"false"` denoting it's not.
This is often used for dynamically applying enter/exit CSS animations.
# Picture in Picture
Source: https://docs.livepeer.org/v1/sdks/react/broadcast/PictureInPicture
The `PictureInPictureTrigger` component toggles the picture-in-picture mode.
## Features
* Automatic conditional rendering based on browser API availability,
customizable with the `matcher` pattern
* Supports both the [w3c](https://w3c.github.io/picture-in-picture/) standard
(which most modern browsers support), as well as the
[older Safari/iOS spec](https://developer.apple.com/documentation/webkitjs/adding_picture_in_picture_to_your_safari_media_controls)
(see the browsers which support Picture-in-Picture on
[caniuse](https://caniuse.com/picture-in-picture))
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Broadcast from "@livepeer/react/broadcast";
export default () => (
);
```
## Props
The component accepts all props suitable for a button element.
## Data Attributes
### `data-livepeer-controls-picture-in-picture-trigger`
Serves to identify the component's role.
### `data-picture-in-picture`
Indicates the current picture-in-picture state, `"true"` when the feature is
active and `"false"` otherwise.
### `data-visible`
Reflects the visibility status of the trigger, with `"true"` meaning it's
currently visible (i.e., picture-in-picture is supported and the media is not in
fullscreen mode) and `"false"` denoting it's not visible.
This is often used for dynamically applying enter/exit CSS animations.
# Portal
Source: https://docs.livepeer.org/v1/sdks/react/broadcast/Portal
The `Portal` component allows projection of content into different parts of the DOM.
The `Portal` component is a simple wrapper over
[@radix-ui/react-portal](https://www.radix-ui.com/primitives/docs/utilities/portal#portal).
It inherits all of the documentation for the component.
## Features
* Provides an easy way to portal controls out of the Root components
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Broadcast from "@livepeer/react/broadcast";
export default () => (
{/* Place portalled elements here, which can still
consume the React Context from the Root, but are
appended to the document */}
);
```
## Props
### `children`
React nodes that are to be rendered inside the portal.
### `container`
An optional prop specifying a container element where the portal's children
should be rendered. If not provided, the children are appended to the body of
the document by default.
# Root
Source: https://docs.livepeer.org/v1/sdks/react/broadcast/Root
The `Broadcast.Root` component is the React Context wrapper for Broadcast.
This is a comprehensive example of how the Broadcast elements can fit together
to build an advanced in-browser streaming experience. This does not only show
the Root Broadcast, but how the Root can be used to provide a state store to
all of its children.
## Features
* Pure React Context provider to pass the broadcast and media state store to all
components
* Automatic SDP negotiation with a
[WebRTC WHIP](https://www.ietf.org/archive/id/draft-ietf-wish-whip-01.html)
endpoint
The Broadcast component utilizes WebRTC for streaming and consistently employs
STUN/TURN servers for the WebRTC connection. This setup facilitates
broadcasting despite corporate firewalls or port restrictions. The component
adheres to WHIP/WHEP standards for ingest/egress SDP negotiation, making it
compatible with any WHIP/WHEP ingest endpoint.
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Broadcast from "@livepeer/react/broadcast";
export default () => (
{/* All child components which use the state store. */}
);
```
## Usage
The `Player.Root` component is a React Context wrapper which passes the player
state store down to all of the child components. It is responsible for creating
the [Zustand](https://github.com/pmndrs/zustand) state store which is consumed
by the children, and listens for media/browser events and keeps state in sync.
The Player automatically handles different source types, such as WebRTC, MP4, and HLS.
These are seamlessly integrated so that playback has low latency under all
network conditions.
It is compatible with WebRTC WHEP endpoints, HLS (and low latency HLS), or
typical media file playable by an HTML5 video element (MP4, WebM).
## Props
### `ingestUrl`
Configures the WHIP WebRTC ingest URL for the `Broadcast` component. You can
create the `ingestUrl` by passing
[`getIngest`](/sdks/react/broadcast/get-ingest) a string (interpreted as a
Livepeer Studio stream key or URL), Livepeer Studio stream data, or Cloudflare
stream data. `Broadcast` is compatible with all WHIP playback endpoints.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{...}
```
### `aspectRatio`
Specifies the aspect ratio of the content. Recommended for an optimal
broadcasting experience to minimize
[Cumulative Layout Shift](https://web.dev/cls/). The default value is `16 / 9`.
Set to `null` to disable the aspect ratio container (see `Container`).
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{...}
```
### `forceEnabled`
Determines whether the WebRTC stream should start immediately after the user
allows access to their video/audio input. The default is `false`, which previews
the video first, then streams media to the server upon activation.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{...}
```
### `audio`
Controls whether audio is enabled initially for the broadcast. The default is
`true`. Set to `false` to start the broadcast without requesting an audio track.
This can be an object that adheres to the structure of
[`MediaTrackConstraints`](https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints),
which will constrain the audio track used in the broadcast.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{...}
```
### `video`
Controls whether video is enabled initially for the broadcast. The default is
`true`. Set to `false` to start the broadcast without requesting a video track.
This can be an object that adheres to the structure of
[`MediaTrackConstraints`](https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints),
which will constrain the video track used in the broadcast. This is usually used
to limit the resolution of the video and improve bandwidth usage.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{...}
```
### `hotkeys`
Enables keyboard hotkeys for controlling the broadcast. Enabled by default
(`true`). It's recommended to follow ARIA guidelines by keeping this enabled
unless you're implementing custom hotkeys or there's a conflict with existing
ones.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{...}
```
### `creatorId`
Sets the creator ID for the broadcast, useful for metrics and viewership API
integration.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{...}
```
### `onError`
An optional callback for handling broadcasting errors. It's called with `null`
when the previous error is resolved. The callback receives the parameter:
```ts theme={"theme":{"light":"github-light","dark":"dark-plus"}}
type PlaybackError = {
type: "offline" | "access-control" | "fallback" | "permissions" | "unknown";
message: string;
};
```
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
console.log(error)}>{...}
```
### `timeout`
Sets the timeout duration for playback before switching to the next source,
including SDP negotiation for WebRTC, waiting for WebRTC to play, and server
responses. The default is 10000 milliseconds.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{...}
```
### `storage`
Configures the storage option for saving persistent states like volume and video
quality. The default is `localStorage` in the browser. Set to `null` to disable
storage.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{...}
```
# Screenshare
Source: https://docs.livepeer.org/v1/sdks/react/broadcast/Screenshare
The `ScreenshareTrigger` and `ScreenshareIndicator` components provide gateways with controls for managing the screenshare state.
## Features
* Automatic conditional rendering based on
[`getDisplayMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia)
status and browser API availability, customizable with the `matcher` pattern
* Handles all common browser APIs, and old WebKit APIs (see
[caniuse](https://caniuse.com/mdn-api_mediadevices_getdisplaymedia))
* Compatible with CSS animations for dynamic enter/exit animations
The `getDisplayMedia` API is only available in secure contexts (HTTPS).
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Broadcast from "@livepeer/react/broadcast";
export default () => (
);
```
## Props
### `ScreenshareTrigger`
Accepts all props for a typical button HTML element.
### `ScreenshareIndicator`
#### `forceMount`
A boolean that, when true, keeps the component mounted at all times, useful for
controlling animations with external libraries.
#### `matcher`
A prop to define the condition under which the `ScreenshareIndicator` should be
visible. It can be a boolean directly matching the screenshare state or a
function providing custom logic to determine visibility.
## Data Attributes
### `ScreenshareTrigger`
#### `data-livepeer-controls-screenshare-trigger`
Serves to identify the component's role within the broadcast interface.
#### `data-active`
Indicates the current screenshare state, `"true"` when screensharing is active
and `"false"` when it is not.
#### `data-visible`
Reflects the visibility status of the trigger, with `"true"` meaning it's
currently visible (i.e., screensharing is supported) and `"false"` denoting it's
not visible.
### `ScreenshareIndicator`
#### `data-livepeer-controls-screenshare-indicator`
Identifies the component's role as a visual indicator of the screenshare state
within the broadcast interface.
#### `data-active`
Shows the current screenshare state, `"true"` when screensharing is active and
`"false"` when it is not.
#### `data-visible`
Reflects the visibility status of the indicator, with `"true"` meaning it's
currently visible based on the `matcher` or screenshare state and `"false"`
denoting it's not visible.
This is often used for dynamically applying enter/exit CSS animations.
# Source
Source: https://docs.livepeer.org/v1/sdks/react/broadcast/Source
The `SourceSelect` component provides gateways with a dropdown interface to choose between different media source devices like cameras and microphones.
All of the `SourceSelect` components extend from
[`@radix-ui/react-select`](https://www.radix-ui.com/primitives/docs/components/select),
and inherits all of the documentation for those components.
## Features
* Synchronizes state with the user media and the broadcast
* Adheres to [WAI-ARIA](https://w3c.github.io/aria/) design patterns
* Persists to `localStorage` by default (with storage overrides customizable in
`Root`)
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Broadcast from "@livepeer/react/broadcast";
export default () => (
);
```
## Props
### `SourceSelect`
Takes all props of the
[Radix Select Root](https://www.radix-ui.com/primitives/docs/components/select)
component.
#### `forceMount`
A boolean that, when set to true, ensures the component is always mounted. If
this is not specified, it will only be shown when sources are detected.
#### `type`
A string indicating the type of media devices to list in the dropdown, either
`"audioinput"` for microphones or `"videoinput"` for cameras.
#### `children`
A function that takes the available media devices as input and returns the React
nodes (options) to be rendered inside the dropdown. This enables dynamic
population of the dropdown based on the available devices. ™
The device ID must be used for the `SelectItem` value.
## Data Attributes
### `data-livepeer-source-select`
Serves to identify the component's role within the broadcast interface.
### `data-type`
Indicates the type of media source device the dropdown is currently displaying,
either `"audioinput"` for microphones or `"videoinput"` for cameras.
### `data-visible`
Reflects the visibility status of the dropdown, with `"true"` meaning it's
currently visible (i.e., device support is available) and `"false"` denoting
it's not visible.
# Status
Source: https://docs.livepeer.org/v1/sdks/react/broadcast/Status
The `StatusIndicator` component provides visual cues for the broadcast status.
## Features
* Synchronizes broadcast status with a visual indicator
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Broadcast from "@livepeer/react/broadcast";
export default () => (
);
```
## Props
### `forceMount`
A boolean that, when true, ensures the component is always mounted. This is
particularly useful for managing animations with external animation libraries.
### `matcher`
A prop required to define the conditions under which the `StatusIndicator`
should be visible. It can be a specific `BroadcastStatus` value or a function
that provides custom logic for visibility determination based on the broadcast
status.
The status can be of the type: `"live" | "pending" | "idle"`
## Data Attributes
### `data-livepeer-controls-status-indicator`
Serves to identify the component's role within the broadcast interface.
### `data-status`
Shows the current broadcast status as a string.
The status can be of the type: `"live" | "pending" | "idle"`
### `data-visible`
Reflects the visibility status of the indicator, with `"true"` meaning it's
currently visible based on the `matcher` or broadcast status and `"false"`
denoting it's not visible.
# Video
Source: https://docs.livepeer.org/v1/sdks/react/broadcast/Video
The `Video` component is a container for previewing broadcast video content.
As you can see in the above example, the component will request permissions
for video/audio input - so it prompts the user for access to their microphone
and camera **upon component mount**.
The `getUserMedia` browser API used to get the video/audio is only available in
secure contexts (HTTPS).
#### Features
* Synchronizes state with the HTML5 video element
* Keyboard hotkeys (`B` to toggle whether the broadcast is enabled, `L` to
toggle audio, `V` to toggle video, `D` to broadcast display media, `C` for
next video source, `M` for next audio source)
* Adheres to [WAI-ARIA](https://w3c.github.io/aria/) design patterns
* Handles all common browser APIs, and old WebKit/Firefox APIs (see
[caniuse](https://caniuse.com/mdn-api_mediadevices_getusermedia))
The Broadcast above will work with only keyboard shortcuts, without any custom
controls.
### Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Broadcast from "@livepeer/react/broadcast";
export default () => (
);
```
## Props
The component accepts most props suitable for a HTML5 `video` tag, except for
`src` and `poster` which are managed internally or provided explicitly through
props.
## Data Attributes
### `data-livepeer-video`
Serves to identify the component's role within the Broadcast.
### `data-enabled`
Indicates the enabled state of the broadcast, `"true"` when broadcasting is
enabled and `"false"` when it is not.
# getIngest
Source: https://docs.livepeer.org/v1/sdks/react/broadcast/get-ingest
`getIngest` is a utility function for converting various types of ingest information into a standardized WHIP URL format suitable for broadcasting.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Broadcast from "@livepeer/react/broadcast";
import { getIngest } from "@livepeer/react";
// Usage with a stream key
const streamKey = "your-stream-key-here";
const whipUrl = getIngest(streamKey, {
baseUrl: "https://playback.livepeer.studio/webrtc",
});
// Usage with Livepeer stream data
const livepeerStreamData = {
id: "stream-id",
streamKey: "your-stream-key-here",
// Other unused Livepeer stream data...
};
// This is either a string or null, depending on whether
// the input was parsed successfully
const whipUrlFromLivepeer = getIngest(livepeerStreamData);
export default () => (
{/* All child components. */}
);
```
### Functionality
`getIngest` simplifies the process of preparing ingest sources for broadcasting
by standardizing them into WHIP URLs.
#### Input Types
The function supports a variety of input types to accommodate different
broadcasting setups:
* **String**: Directly returns the string if it's a valid URL. Constructs a WHIP
URL using a base URL for stream keys.
* **LivepeerStream**: Uses the `streamKey` from Livepeer stream data to generate
a WHIP URL.
* **CloudflareStreamData**: Extracts the URL from Cloudflare stream data
objects.
Optional parameters (`opts`) include:
* **baseUrl**: The base URL for constructing WHIP URLs. Essential when the input
is a stream key.
#### Output Format
The function outputs a WHIP URL string suitable for use in broadcasting setups,
or `null` if the input can't be processed into a valid WHIP URL.
# useBroadcastContext
Source: https://docs.livepeer.org/v1/sdks/react/broadcast/useBroadcastContext
The `useBroadcastContext` hook lets you build custom components which interact directly with the Broadcast state store.
The `useStore` hook is from
[`zustand`](https://github.com/pmndrs/zustand?tab=readme-ov-file#using-zustand-without-react),
and inherits all of the documentation for Zustand stores.
## Features
* Flexible interaction with the broadcast state store
* Based on Zustand's `useStore` hooks
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Broadcast from "@livepeer/react/broadcast";
import { useBroadcastContext, useStore } from "@livepeer/react/broadcast";
export default () => (
{/** The `useBroadcastContext` hook can be used in any component,
as long as it's inside the Broadcast.Root React Context provider */}
);
function CustomComponent({
style,
__scopeBroadcast,
}: Broadcast.BroadcastScopedProps<{}>) {
const context = useBroadcastContext("CustomComponent", __scopeBroadcast);
// use selectors with the Zustand store, to make sure your component doesn't render
// on every store state change
const { status } = useStore(context.store, ({ status }) => ({
status,
}));
return status;
}
```
## State
The `useBroadcastContext` hook returns a Zustand store, which contains the
`BroadcastState`.
### `aria`
The ARIA text for the controls given the current state.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
type BroadcastAriaText = {
audioTrigger: string;
start: string;
screenshareTrigger: string;
videoTrigger: string;
};
```
### `audio`
Indicates whether the broadcast's audio track is turned on.
### `enabled`
Specifies whether the broadcast is currently active or in "preview" mode.
### `hydrated`
Reflects whether the broadcast store is hydrated, indicating if initial data has
been loaded into the state.
### `mediaDevices`
A list of the current media devices (based on
[MediaDeviceInfo](https://developer.mozilla.org/en-US/docs/Web/API/MediaDeviceInfo)),
which changes based on permissions or when a user starts sharing their display.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
type MediaDeviceInfoExtended = Omit & {
/**
* This is a convenience field added to MediaDeviceInfo to help easily add a device picker.
*
* For security reasons, the label field will blank unless an active media stream exists
* or the user has granted persistent permission for media device access. The set of device labels
* could otherwise be used as part of a fingerprinting mechanism to identify a user.
*
* When the label field is not blank, these are the same value. Otherwise, the value is a friendly default.
*/
friendlyName: string;
/**
* For security reasons, the label field is blank unless an active media stream exists
* or the user has granted persistent permission for media device access. The set of device labels
* could otherwise be used as part of a fingerprinting mechanism to identify a user.
*
* We override it here to be null when it is blank, for easier developer usage.
*/
label: string | null;
};
mediaDevices: MediaDeviceInfoExtended[] | null;
```
### `mediaStream`
The [MediaStream](https://developer.mozilla.org/en-US/docs/Web/API/MediaStream)
for the current broadcast, containing the audio and video tracks.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
mediaStream: MediaStream | null;
```
### `mounted`
Whether the broadcast component is currently mounted in the DOM.
### `peerConnection`
The
[RTCPeerConnection](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection)
object for the broadcast, managing the connection between the local and remote
peers.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
peerConnection: RTCPeerConnection | null;
```
### `status`
The current status of the broadcast, which can be "live", "pending", or "idle".
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
status: "live" | "pending" | "idle";
```
### `ingestUrl`
The WHIP ingest URL used for the broadcast.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
ingestUrl: string | null;
```
### `video`
Indicates if the broadcast's video track is turned on.
### `mediaDeviceIds`
The IDs of the currently selected media devices.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
mediaDeviceIds: MediaDeviceIds;
```
### `__initialProps`
The initial properties passed into the broadcast component. This is an internal
object used by Broadcast.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
__initialProps: InitialBroadcastProps;
```
### `__device`
Information about the broadcast device's capabilities and support. This is an
internal object used by Broadcast, but can be used for detecting device
capabilities.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
type BroadcastDeviceInformation = {
version: string;
/** If the environment supports mediaDevices */
isMediaDevicesSupported: boolean;
/** If the environment supports RTCPeerConnection */
isRTCPeerConnectionSupported: boolean;
/** If the environment supports sharing display media */
isDisplayMediaSupported: boolean;
};
__device: BroadcastDeviceInformation;
```
### `__controls`
The current state of broadcast controls. This is an internal object used by
Broadcast.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
__controls: BroadcastControlsState;
```
### `__controlsFunctions`
An object containing functions to manipulate the broadcast's state, such as
toggling audio/video, updating the media stream, and setting the peer
connection.
These functions are internal - please refer to the UI Kit source code before
interacting with these functions.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
__controlsFunctions: {
requestDeviceListInfo: () => void;
requestForceRenegotiate: () => void;
requestMediaDeviceId: (deviceId: AudioDeviceId, type: keyof MediaDeviceIds) => void;
rotateAudioSource: () => void;
rotateVideoSource: () => void;
setIngestUrl: (ingestUrl: string) => void;
setInitialState: (ids: MediaDeviceIds, audio: boolean, video: boolean) => void;
setPeerConnection: (peerConnection: RTCPeerConnection) => void;
setStatus: (status: BroadcastStatus) => void;
setMediaDeviceIds: (mediaDevices: Partial) => void;
toggleAudio: () => void;
toggleDisplayMedia: () => void;
toggleEnabled: () => void;
toggleVideo: () => void;
updateDeviceList: (mediaDevices: MediaDeviceInfo[]) => void;
updateMediaStream: (mediaStream: MediaStream) => void;
};
```
# Broadcast
Source: https://docs.livepeer.org/v1/sdks/react/migration/3.x/Broadcast
The Broadcast component provides an easy way to livestream video or audio.
The `Broadcast` component provides an easy way to livestream video or audio,
including camera and screen sources.
It automatically handles WebRTC connection and allows extremely low latency
livestreaming.
## Usage
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Broadcast } from '@livepeer/react';
```
The following example assumes a stream was created via `useCreateStream`, and
the `streamKey` was passed to the Broadcast component.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Broadcast } from '@livepeer/react';
function BroadcastComponent() {
return (
);
};
```
React Native is not supported yet.
## Configuration
### streamKey
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function BroadcastComponent() {
return ;
}
```
The `streamKey` passed to the `Broadcast` component is used to connect to the
WebRTC ingest URL.
### title
The `title` for the content. This is highly recommended, since it is used for
[accessibility labels](https://web.dev/semantics-aria/) in the Broadcast. If you
do not want to show the title visually, see [`showTitle`](#showtitle).
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function BroadcastComponent() {
return ;
}
```
### showTitle
Enables/disables the title component.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function BroadcastComponent() {
return (
);
}
```
### displayMediaOptions
The display media stream options to use when requesting screen share. This is
usually a set of audio and video
[`MediaTrackConstraints`](https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints)
which are passed to the browser to limit the sources available to the user.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function BroadcastComponent() {
return (
);
}
```
### aspectRatio
Sets the aspect ratio for the content. Highly recommended for a great
broadcasting experience (for more information, see
[Cumulative Layout Shift](https://web.dev/cls/)). Defaults to `16to9`.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function BroadcastComponent() {
return (
);
}
```
### controls
Configures the timeout for autohiding controls, default volume, and (only on
web) if keyboard hotkeys for controlling the broadcast are enabled.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function BroadcastComponent() {
return (
);
}
```
### muted
Sets the video to muted when the broadcast started.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function BroadcastComponent() {
return ;
}
```
### objectFit
Sets the video's
[object fit](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit)
property. Defaults to `contain`. `cover` is usually used when there is a
guarantee that the `aspectRatio` matches the content displayed in the Broadcast.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function BroadcastComponent() {
return (
);
}
```
### showPipButton
Shows the Picture-in-Picture button to the left of the fullscreen button.
Defaults to `false`. See [children](#children) for an example on how to use the
underlying ``.
We support both the [w3c](https://w3c.github.io/picture-in-picture/) standard
(which most modern browsers support), as well as the [older Safari/iOS
spec](https://developer.apple.com/documentation/webkitjs/adding_picture_in_picture_to_your_safari_media_controls).
See the browsers which support Picture-in-Picture on
[caniuse](https://caniuse.com/picture-in-picture).
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Player } from "@livepeer/react";
function BroadcastComponent() {
return (
);
}
```
### theme
Sets the Player-specific theme overrides. It is recommended to use
[`LivepeerConfig`](/sdks/react/migration/3.x/LivepeerConfig) for any global app
styles, and the `theme` prop to override those styles on a per-Broadcast basis.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function BroadcastComponent() {
return (
);
}
```
### children
Overrides the custom controls for the Player. See the
[`Broadcast` default controls](https://github.com/livepeer/react/blob/main/packages/react/src/components/media/Broadcast.tsx)
for more details on how the `ControlsContainer` component is used.
This can be used alongside `renderChildrenOutsideContainer` to render the
children outside of the aspect ratio container. This is used for custom
controls, so children of the Player can use `useMediaController` without any
parent elements.
### mediaElementRef
Sets the React
[callback `ref`](https://reactjs.org/docs/refs-and-the-dom.html#callback-refs)
passed to the underlying media element. Useful when integrating with third party
tools, or when access to the underlying video element is needed (usually it
isn't!). Simple refs are not supported - only callback refs (which will be
called when the underlying media element is set/updated on initial render).
### onPlaybackStatusUpdate
Callback called when the Broadcast store status updates. **This should be used
with `playbackStatusSelector` to limit state updates.** This allows developers
to use the underlying state of the Broadcast component in their UI.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function BroadcastComponent() {
return (
console.log(muted)}
playbackStatusSelector={(state) => state.muted}
/>
);
}
```
## Technical Details
### WebRTC Broadcasting
The Broadcast component uses WebRTC for broadcasting. This always uses STUN/TURN
servers for the WebRTC connection, to allow the broadcast to circumvent
corporate firewalls and other port blocks. We use the WHIP/WHEP standards for
ingest/egress SDP negotiation, so this means that the Broadcast component can be
used with *any* WHIP/WHEP ingest endpoint - not only the providers we have.
# LivepeerConfig
Source: https://docs.livepeer.org/v1/sdks/react/migration/3.x/LivepeerConfig
The LivepeerConfig component manages configuration for all hooks using React Context.
The `LivepeerConfig` component manages configuration for all hooks using
[React Context](https://reactjs.org/docs/context.html).
## Usage
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { LivepeerConfig } from '@livepeer/react';
```
The `LivepeerConfig` should wrap all of your pages, so every page can use hooks provided by Livepeer React.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const client = createReactClient({
provider: studioProvider({ apiKey: 'yourStudioApiKey' }),
});
function App() {
return (
);
}
```
If you are using an SSR framework (like Next.js), see [SSR](#ssr) for specific instructions on how to configure
the `head` of the document, to ensure hydration happens correctly.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { LivepeerConfig } from '@livepeer/react-native';
```
The `LivepeerConfig` should wrap all of your screens, so every screen can use hooks provided by Livepeer React.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const client = createReactClient({
provider: studioProvider({ apiKey: 'yourStudioApiKey' }),
});
function App() {
return (
);
}
```
## Configuration
### client
A livepeer [`Client`](/sdks/react/migration/3.x/client) instance that consists
of configuration options. Required to connect to a provider.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const client = createReactClient({
provider: studioProvider({ apiKey: "yourStudioApiKey" }),
});
function App() {
return (
);
}
```
### theme
Sets the global theme overrides. It is recommended to use this for any global
app styles. This is optional and every value has a default. See the source code
for more information.
```tsx {5-16,20} theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const client = createReactClient({
provider: studioProvider({ apiKey: "yourStudioApiKey" }),
});
const theme: ThemeConfig = {
colors: {
accent: "rgb(0, 145, 255)",
containerBorderColor: "rgba(0, 145, 255, 0.9)",
},
fonts: {
display: "Inter",
},
radii: {
slider: "4px",
},
};
function App() {
return (
);
}
```
## SSR
The following section only applies to web-based use-cases - React Native has
no concept of SSR.
You can get access to the CSS string by using the `getCssText` function. This
function is made available by the createStitches function. This will give you
all the CSS you need to server-side render it.
For a better hydration strategy, we highly recommend adding an `id="stitches"`
to your style tag.
Here's an example of SSR with Next.js:
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import NextDocument, { Html, Head, Main, NextScript } from "next/document";
import { getCssText } from "@livepeer/react";
export default class Document extends NextDocument {
render() {
return (
);
}
}
```
See the [Stitches](https://stitches.dev/docs/server-side-rendering)
documentation for further information.
# Player
Source: https://docs.livepeer.org/v1/sdks/react/migration/3.x/Player
The Player component provides an easy way to display video or audio.
The `Player` component provides an easy way to display video or audio.
It automatically handles different source types from a Livepeer provider, such
as WebRTC, MP4, and HLS. These are seamlessly integrated so that playback has
low latency under all network conditions.
## Usage
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Player } from '@livepeer/react';
```
The following example assumes a stream or asset was created via `useCreateAsset`
or `useCreateStream`, and the `playbackId` was passed to the viewer.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Player } from '@livepeer/react';
import Image from 'next/image';
import blenderPoster from '../../../public/images/blender-poster.png';
const PosterImage = () => {
return (
);
};
function PlayerComponent() {
return (
}
showPipButton
objectFit="cover"
priority
/>
);
};
```
Here we also introduce a custom `PosterImage` React component, which is
described in more detail below in [`poster`](#poster) configuration.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Player } from '@livepeer/react-native';
```
The following example assumes a stream or asset was created via `useCreateAsset`
or `useCreateStream`, and the `playbackId` was passed to the viewer.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Player } from '@livepeer/react-native';
import blenderPoster from './assets/images/blender-poster.png';
function PlayerComponent() {
return (
);
};
```
## Compatibility
| Browser | Version |
| ------------------ | ------- |
| Chrome | 102+ |
| Chrome for Android | 105+ |
| iOS Safari | 12.2+ |
| Edge | 103+ |
| Safari | 13.1+ |
| Firefox | 103+ |
| Opera | 89+ |
| Samsung Internet | 17+ |
| UC Browser | 13.4+ |
| Firefox Android | 104+ |
| Opera Mini | all |
We aim to support
[\~93%](https://browsersl.ist/#q=last+2+versions%2C%3E+0.2%25%2Cnot+dead) of
browsers tracked on [caniuse](https://caniuse.com/). We use
[browserslist](https://browsersl.ist/) to track compatibility and
[core-js](https://github.com/zloirock/core-js) for polyfills.
| Framework | Version |
| ------------ | ------- |
| React Native | 0.64.0+ |
| Expo | 43+ |
| React | 17+ |
We aim to support the latest versions of React Native and Expo. If you are
using an older version of Expo or React Native, we highly recommend upgrading
to ensure compatibility.
## Configuration
### playbackId or src
A `playbackId` for an
[asset](https://github.com/livepeer/react/blob/main/packages/core/src/types/provider.ts)
or
[Stream](https://github.com/livepeer/react/blob/main/packages/core/src/types/provider.ts),
or `src`, a media source URL. One of these is required.
#### playbackId
If a playback ID is provided, the playback URL corresponding to the playback
ID will be automatically fetched.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
The `playbackId` passed to the `Player` can be either a short playback ID which
is created on asset/stream creation, or, for an asset, an IPFS CID. If the
provided IPFS CID or IPFS/Arweave URL has not been uploaded yet, it can be
auto-uploaded and played back - see [`autoUrlUpload`](#autourlupload) for more
details.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// only after the asset has been persisted to IPFS
// equivalent to the above example
function PlayerComponent() {
return (
);
}
```
#### src
Using an arbitrary `src` that is not from a provider will not be transcoded
(unless [`autoUrlUpload`](#autourlupload) is used), and will take up
significant network bandwidth. It's highly recommended to upload media to a
provider, and serve content to viewers with a `playbackId`.
The Player also supports an arbitrary `src` URL which can correspond to any
common video or audio which most browsers support. See
[caniuse video format](https://caniuse.com/?search=video%20format) for more
details on browser support.
Metrics reporting **will not work** with an arbitrary `src` (e.g. not a Studio
playback URL).
If the `src` is an IPFS/Arweave URL, it can be auto-uploaded and played back -
see [`autoUrlUpload`](#autourlupload) for more details.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const src =
"https://ipfs.livepeer.studio/ipfs/QmURv3J5BGsz23GaCUm7oXncm2M9SCj8RQDuFPGzAFSJw8";
function PlayerComponent() {
return ;
}
```
### jwt or accessKey
This section defines ways to play back a video which has a playback policy
applied to it. Your application can prevent playback unless the user meets
application-specific requirements (this can be done either with JWTs or
webhooks, and solves use-cases like restricting viewership to users who own an
NFT, have created an account on your platform, are part of a multisig, etc).
#### jwt
The JSON Web Token (JWT) used to access media gated by a `jwt` playback policy.
Alternatively, `accessKey` can be used for a `webhook` playback policy. See the
[Access Control example](/developers/guides/access-control-jwt) for more
details.
Access control is now supported for both streams and assets!
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
#### accessKey
The access key used to access media behind a `webhook` playback policy.
Alternatively, `onAccessKeyRequest` can be used to return this access key in a
callback. See the
[Access Control example](/developers/guides/access-control-webhooks) for more
details.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
#### onAccessKeyRequest
A callback which returns the access key used to gate access to media. Similar to
`accessKey` above, this is used to gate content based on a `webhook` playback
policy. This is used instead of the `accessKey` prop, and can be asynchronous
and accepts any Promise or simple callback which returns a string. See the
[Access Control example](/developers/guides/access-control-webhooks) for more
details.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
{
return "access-key";
}}
/>
);
}
```
### priority
When true, the media will be considered high priority and preload. Lazy loading
is automatically disabled for media using `priority`. You should use the
priority property on any media detected as the
[Largest Contentful Paint (LCP)](https://web.dev/lcp/) element. It may be
appropriate to have multiple, as different content may be the LCP element for
different viewport sizes.
Should only be used when the media is visible above the fold. Defaults to false.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
### lowLatency
When enabled, the Player will play back **live streams** with low-latency
WebRTC. Defaults to `true`. If this does not succeed in playing back (commonly
due to a slow network or connectivity issues), the Player will automatically
fall back to HLS playback. Also, if the stream contains B-frames (bidirectional
frames, which are common for users streaming with OBS or other streaming apps),
the Player will automatically switch to HLS, so that out-of-order frames are not
displayed.
OBS users should be instructed to use the Livepeer stream profile, or to
manually turn off B-frames in their stream. See our [Stream from
OBS](/developers/guides/stream-via-obs) docs for more information.
This only applies to video elements which are playing back livestreams - assets
will play back with MP4 or HLS.
You may also specify `"force"`, which forces WebRTC and disables fallback to
HLS. This is not a recommended default unless your application requires low
latency (and should not play if low latency is not available), due to the
possible connectivity issues which WebRTC can face, which HLS is not subject to.
We are planning on adding similar functionality to the React Native `Player` -
please reach out on Discord if you are interested.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
### clipLength
The clip length enables the "live clipping" feature - the value is in seconds,
and controls the length of the clip that is created when the clip button is
clicked by a viewer. This can be one of 90, 60, 45, 30, 15, or 10 seconds.
This allows for dynamic viewing experiences, along with the `onClipStarted`,
`onClipCreated`, and `onClipError` callbacks for clips.
You can use the `onClipStarted`, `onClipCreated`, and `onClipError` callbacks
to control UI outside of the Player, to show toasts or other loading
indicators, as well as track the status of the Asset which is created and
processed. See `useAsset` for how to poll the status of the asset.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
{
console.log("Clip API request is pending...");
}}
onClipCreated={(asset: Asset) => {
// poll the status of the asset for the
// download URL or playback ID
console.log(asset.id);
}}
onClipError={(error: Error) => {
console.error(error.message);
}}
/>
);
}
```
### playRecording
When allowed, the Player will include recording URLs in playback. This is the
HLS URL that allows users to watch the entire recording of a stream, without
requiring the user to play from the latest playhead (as is usually required in
stream playback). This can be used to create historical clipping experiences for
streams - users can watch a version of the stream that constantly appended with
the latest segments.
Keep in mind that latency for the latest segments will be higher when this
option is enabled, and is not recommended for low latency applications.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
### title
The `title` for the content. This is highly recommended, since it is used for
[accessibility labels](https://web.dev/semantics-aria/) in the Player. If you do
not want to show the title visually, see [`showTitle`](#showtitle).
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
### showTitle
Enables/disables the title component.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
### aspectRatio
Sets the aspect ratio for the content. Highly recommended for a great viewing
experience (for more information, see
[Cumulative Layout Shift](https://web.dev/cls/)). Defaults to `16to9`.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
### loop
Sets whether the content will loop when finished. Defaults to `false`.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
### poster
Sets the poster image. This can be either a string for an image URL, or a React
component.
The `poster` can be a simple image URL, and it will be rendered with a regular
`img` HTML tag.
It is recommended to use an optimized React image component for this (see
below), as opposed to passing a simple URL.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
If the poster is a React component, it will be rendered with similar CSS
attributes to the `img` above. In the below example, we show the use of
[Next.js Image](https://nextjs.org/docs/basic-features/image-optimization) to
render an optimized image, which will automatically handle slow network
conditions/different device sizes.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Player } from "@livepeer/react";
import Image from "next/image";
import blenderPoster from "./images/blender-poster.png";
const PosterImage = () => {
return (
);
};
function PlayerComponent() {
return (
}
/>
);
}
```
Sets the poster image. This can be either a remote URL or a local file resource.
It is recommended to use a local file resource, as opposed to passing a remote
URL. Since this image is used during a loading state, it will ensure a smooth
experience for users.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import posterImage from "./images/blender-poster.png";
function PlayerComponent() {
return (
);
}
```
### showLoadingSpinner
Shows/hides the loading spinner for the media content. Defaults to `true`.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
### hlsConfig
Sets the underlying HLS.js config used for playback. See the
[HLS.js docs](https://github.com/video-dev/hls.js/blob/8d75e45992a7139e7cf9b11a056c8474e9ef4546/docs/API.md)
for more details on the possible values.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
### webrtcConfig
Sets the underlying WebRTC config used for
[WHEP SDP negotiation](https://datatracker.ietf.org/doc/draft-murillo-whep/).
The possible config options are `constant` and `sdpTimeout`.
A `constant=true` boolean indicates that audio will not be distorted if the
playhead falls behind the livestream. This is usually used for music
applications, where audio quality and consistency is more important than
latency.
The `sdpTimeout` config sets the amount of time in milliseconds that the Player
will wait for a response from SDP negotiation before falling back to HLS.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
### controls
Configures the timeout for autohiding controls, default volume, and (only on
web) if keyboard hotkeys for controlling video are enabled.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
### autoPlay and muted
Sets the video to autoplay when the content comes into focus on the webpage. If
`autoPlay` is specified, `muted` will be forced to be `true`. This is
[enforced in many modern browsers](https://developer.chrome.com/blog/autoplay/).
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
### objectFit
Sets the video's
[object fit](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit)
property. Defaults to `contain`. `cover` is usually used when there is a
guarantee that the `aspectRatio` matches the content displayed in the Player.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
### showPipButton
Shows the Picture-in-Picture button to the left of the fullscreen button.
Defaults to `false`. See [children](#children) for an example on how to use the
underlying ``.
We support both the [w3c](https://w3c.github.io/picture-in-picture/) standard
(which most modern browsers support), as well as the [older Safari/iOS
spec](https://developer.apple.com/documentation/webkitjs/adding_picture_in_picture_to_your_safari_media_controls).
See the browsers which support Picture-in-Picture on
[caniuse](https://caniuse.com/picture-in-picture).
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Player } from "@livepeer/react";
function PlayerComponent() {
return (
);
}
```
Picture-in-Picture is not supported in React Native, due to lack of support in
`expo-av`.
### viewerId
Allows a wallet identifier to be passed to the backend which allows for querying
views by an identifier. This should be an wallet's public address.
We are planning on adding further features to the viewer ID, such as "verified
views" with a provable signature claim attached to these view counts. Reach
out to us on [Discord](https://discord.gg/livepeer) if you're interested!
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
### autoUrlUpload
Enables automatic upload and playback from decentralized storage providers.
Currently supports IPFS CIDs and IPFS/Arweave URLs. Defaults to `true`.
For IPFS HTTP gateway URLs, the player currently only supports “path style”
URLs and does not support “subdomain style” URLs. The player will support both
styles of URLs in a future update.
If `fallback` is specified, while the URL upload is being processed in the
background, the video will start non-transcoded playback immediately (defaulting
to `w3s.link` for IPFS and `arweave.net` for Arweave). Once this finishes, the
Player will switch to playing from the transcoded version from the Livepeer
provider. To show/hide the indicator of current upload progress, see
[`showUploadingIndicator`](#showuploadingindicator).
It is highly recommended for the best playback experience to upload from an
Arweave/IPFS URL using `useCreateAsset` (with the format `ipfs://` or
`ar://`) before presenting the content to the user - the first view with
automatic URL upload can take a few minutes, then it will be permanently cached
and play back quickly.
An IPFS [v0 or v1 CID](https://docs.ipfs.tech/concepts/content-addressing/) or
IPFS/Arweave URL (including directories) can be passed as the `src` or
`playbackID` to the Player, and it will automatically detect if it is a
dStorage identifier and attempt to play from a cached version. If the API does
not have a cached version with the corresponding ID, the Player will upload
the content using IPFS/Arweave, and then start playing the transcoded content
back. This may take a few minutes. If `fallback` is specified, it will attempt
to play back instantly from the provided gateway or default gateway.
For best performance, use a custom gateway URL, and ideally, use the same
gateway and pinning service, to avoid timeout errors.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
### showUploadingIndicator
Shows/hides the uploading indication for `autoUrlUpload`. Defaults to `true` -
only used with `autoUrlUpload`.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
### theme
Sets the Player-specific theme overrides. It is recommended to use
[`LivepeerConfig`](/sdks/react/migration/3.x/LivepeerConfig) for any global app
styles, and the `theme` prop to override those styles on a per-Player basis.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
### children
Overrides the custom controls for the Player. See the
[`Player` default controls](https://github.com/livepeer/react/blob/main/packages/react/src/components/media/Player.tsx)
for more details on how the `ControlsContainer` component is used.
This can be used alongside `renderChildrenOutsideContainer` to render the
children outside of the aspect ratio container. This is used for custom
controls, so children of the Player can use `useMediaController` without any
parent elements.
Overrides the custom controls for the Player. See the
[React Native `Player` default controls](https://github.com/livepeer/react/blob/main/packages/react-native/src/components/media/Player.tsx)
for more details on how the `ControlsContainer` component is used.
This can be used alongside `renderChildrenOutsideContainer` to render the
children outside of the aspect ratio container. This is used for custom
controls, so children of the Player can use `useMediaController` without any
parent elements.
### streamOfflineErrorComponent
Sets the error component that is shown when playback fails due to the stream
being offline. When this component is shown, the Player will retry playback in
the background. This will override the
[`OfflineStreamError` component](https://github.com/livepeer/react/blob/main/packages/react/src/components/media/controls/PlaybackDisplayError.tsx).
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
Stream is offline. Playback will start automatically once the stream
has started.
}
/>
);
}
```
### accessControlErrorComponent
Sets the error component that is shown when playback fails due to an access
control error. This will override the
[`PrivateStreamError` component](https://github.com/livepeer/react/blob/main/packages/react/src/components/media/controls/PlaybackDisplayError.tsx).
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
It looks like you don't have permission to view this content.
}
/>
);
}
```
### playbackFailedErrorComponent
Sets the error component that is shown when playback fails for a generic reason
(usually this is an intermittent network issue). When this component is shown,
the Player will be retrying playback in the background, with linear backoff.
This will override the
[`GenericError` component](https://github.com/livepeer/react/blob/main/packages/react/src/components/media/controls/PlaybackDisplayError.tsx).
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
Playback failed! Please wait while we retry in the background.
}
/>
);
}
```
### mediaElementRef
Sets the React
[callback `ref`](https://reactjs.org/docs/refs-and-the-dom.html#callback-refs)
passed to the underlying media element. Useful when integrating with third party
tools, or when access to the underlying video element is needed (usually it
isn't!). Simple refs are not supported - only callback refs (which will be
called when the underlying media element is set/updated on initial render).
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useCallback } from "react";
function PlayerComponent() {
const mediaElementRef = useCallback((ref: HTMLMediaElement) => {
console.log(ref.duration);
}, []);
return (
);
}
```
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useCallback } from "react";
function PlayerComponent() {
return (
{
await ref?.setVolumeAsync(0.5);
}}
/>
);
}
```
### onPlaybackStatusUpdate
Callback called when the Player store status updates. **This must be used with
`playbackStatusSelector` to limit state updates.** This allows developers to use
the underlying state of the Player component in their UI.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
console.log(muted)}
playbackStatusSelector={(state) => state.muted}
/>
);
}
```
## Hooks
### usePlayerList
`usePlayerList` is currently only available for React Native, since there are
List primitives which provide a standard API to hook into. We are working on a
React version.
The `usePlayerList` hook makes it easy to preload and display videos in a
[`FlatList`](https://reactnative.dev/docs/flatlist)-compatible list, by using
[`viewabilityConfigCallbackPairs`](https://reactnative.dev/docs/flatlist#viewabilityconfigcallbackpairs)
to trigger preloading on upcoming videos, and automatically playing/pausing
media when it is shown/hidden from the list.
See our
[Expo sample app](https://github.com/livepeer/react/tree/main/examples/expo) for
a real-world example.
#### Usage
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const videos = [
{
title: "Fountain",
playbackId: "6119i9hncfr7gopr",
},
{
title: "Happy Dog",
playbackId: "8cf0gfaqtuajakyf",
},
];
function SomeComponent() {
const { listProps } = usePlayerList({
data: videos,
itemVisibleMinimumViewTime: 100,
itemVisiblePercentThreshold: 60,
itemPreload: 2,
});
return (
(
)}
/>
);
}
```
#### Return Value
The return value extends the `data` array which is passed into the hook, to add
Player-specific props to it. The `viewabilityConfigCallbackPairs` prop is also
returned, which must be passed into the `FlatList`-compatible list to maintain
the correct preloading/playing states for the Player(s).
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
data: (
TInputArray & {
playerProps: {
_isCurrentlyShown: boolean;
priority: boolean;
};
}
)[];
viewabilityConfigCallbackPairs: ViewabilityConfigCallbackPairs;
}
```
#### Configuration
##### data
The data used in the list - required. This is extended to add Player-specific
props, which are passed into the Player using `item.playerProps`.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { listProps } = usePlayerList({
data: videos,
});
return (
(
)}
/>
);
}
```
##### itemPreload
The number of items to preload ahead of the currently-viewable Player. For
instance, if `itemPreload` is set to 8 and there are 30 items in the Player
list, when the user is currently viewing the 5th item, the 6th-14th Players will
actively preload in the background. Defaults to 3.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { listProps } = usePlayerList({
data: videos,
itemPreload: 8,
});
}
```
##### itemVisibleMinimumViewTime
The minimum amount of time in milliseconds that an item must be viewable before
it is considered "shown". This will also be the delay between when the item
becomes visible and when the autoPlay logic is triggered. Defaults to 100 ms,
use `null` to unset. See
[FlatList's `viewabilityConfig`](https://reactnative.dev/docs/flatlist#viewabilityconfig)
for more details.
```tsx {4} theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { listProps } = usePlayerList({
data: videos,
itemVisibleMinimumViewTime: 300,
});
}
```
##### itemVisiblePercentThreshold
The percent of the item that must be visible for the item to count as
"viewable", from 0-100. Defaults to 60%, use `null` to unset. See
[FlatList's `viewabilityConfig`](https://reactnative.dev/docs/flatlist#viewabilityconfig)
for more details.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { listProps } = usePlayerList({
data: videos,
itemVisiblePercentThreshold: 35,
});
}
```
##### itemVisibleViewAreaCoveragePercentThreshold
The percent of the viewport that must be covered for a partially occluded item
to count as "viewable", 0-100. No default value. See
[FlatList's `viewabilityConfig`](https://reactnative.dev/docs/flatlist#viewabilityconfig)
for more details.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { listProps } = usePlayerList({
data: videos,
itemVisiblePercentThreshold: null, // the default item percent can be unset, if needed
itemVisibleViewAreaCoveragePercentThreshold: 75,
});
}
```
##### itemVisibleWaitForInteraction
Indicates that the item is not considered viewable until the user scrolls or
`recordInteraction` is called after render. Defaults to false. See
[FlatList's `viewabilityConfig`](https://reactnative.dev/docs/flatlist#viewabilityconfig)
for more details.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { listProps } = usePlayerList({
data: videos,
itemVisibleWaitForInteraction: true,
});
}
```
## SSR
The following section only applies to web-based use-cases - React Native has
no concept of SSR.
### Next.js
The Player also comes with a
[Tanstack Query](https://tanstack.com/query/v4/docs/guides/ssr) prefetch query,
`prefetchPlayer`, which makes it easy to prefetch the data used internally for
the Player during server-side rendering.
First, you add a
[`getStaticProps`](https://nextjs.org/docs/basic-features/data-fetching/get-static-props)
function to the page which you want to prefetch data on. The props should match
the Player props to ensure that the correct data is prefetched.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { prefetchPlayer, studioProvider } from "@livepeer/react";
export const getStaticProps = async () => {
const dehydratedState = await prefetchPlayer(
{ playbackId },
{ provider: studioProvider({ apiKey: "yourStudioApiKey" }) }
);
return {
props: {
dehydratedState,
},
revalidate: 600,
};
};
```
We need to update the `_app.tsx` to pass the `dehydratedState` in `pageProps` to
the LivepeerConfig. We also move the `livepeerClient` into a useMemo hook so
that a new client is created on each request.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import {
LivepeerConfig,
createReactClient,
studioProvider,
} from "@livepeer/react";
import type { AppProps } from "next/app";
import { useMemo } from "react";
function App({ Component, pageProps }: AppProps<{ dehydratedState: string }>) {
// we create a new livepeer client on each request so data is
// not shared between users
const livepeerClient = useMemo(
() =>
createReactClient({
provider: studioProvider({
apiKey: process.env.NEXT_PUBLIC_STUDIO_API_KEY,
}),
}),
[]
);
return (
);
}
```
That's it! You now have data prefetching on the server, which is passed to the
browser and used to hydrate the initial query client.
### Other Frameworks
The process is very similar for other frameworks, with the exception that there
is a `clearClient` boolean which should be used to ensure that the client cache
is not reused across users.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { prefetchPlayer, studioProvider } from "@livepeer/react";
export const handleRequest = async (req, res) => {
const dehydratedState = await prefetchPlayer(
{
playbackId,
clearClient: true,
},
{ provider: studioProvider({ apiKey: "yourStudioApiKey" }) }
);
// sanitize the custom SSR generated data
// https://medium.com/node-security/the-most-common-xss-vulnerability-in-react-js-applications-2bdffbcc1fa0
res.send(`
${html}
`);
};
```
## Technical Details
The Player is opinionated about the ways it handles playback of media,
specifically regarding HLS reconnect and playback URL choices.
### HLS Reconnect
The Player will perform a linear backoff strategy when it encounters any
network/response errors. The reconnect will initially wait one second, and add
one second every retry. This ensures that if there are any intermittent
network/API errors, they are resolved as quickly as possible. Most open source
players do not do this automatically, which results in a poor playback
experience for the user.
### MP4 Playback URLs
When videos are uploaded which are shorter than two minutes, the Studio provider
will automatically generate MP4 renditions alongside the usual HLS playback URL.
This allows for rapid playback/caching at the CDN layer to enable your
application to load video instantly.
The MP4 renditions will be prioritized over HLS and are chosen with the
following algorithm: the device screen width is multiplied by a static
multiplier (currently set to `x2.5`). This value is then compared to the
rendition widths, and the renditions are prioritized based on the distance
between these values. This results in a choice of a rendition which is close to
the screen size without visual quality issues. For instance, a device with a
1280 pixel width would compute `1280px * 2.5 = 3200px`, and then sort the MP4
renditions by which are closest to this value.
# useAsset
Source: https://docs.livepeer.org/v1/sdks/react/migration/3.x/asset/useAsset
React Hook for retrieving an asset.
Hook for retrieving an
[asset](https://github.com/livepeer/react/blob/main/packages/core/src/types/provider.ts)
based on a unique identifier.
## Usage
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useAsset } from '@livepeer/react';
```
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useAsset } from '@livepeer/react-native';
```
The following examples assume an asset was created via `useCreateAsset` or
directly via a provider's API/dashboard. If a falsy asset ID is provided, the
query will be skipped.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function Component() {
const { data: asset } = useAsset(asset?.id);
}
```
## Return Value
The return value is partially based on
[Tanstack Query](https://tanstack.com/query/v4/docs/reference/useQuery), with
some return types aggregated for simplicity.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
data?: Asset,
error?: Error,
status: 'idle' | 'loading' | 'success' | 'error',
isError: boolean,
isFetched: boolean,
isFetching: boolean,
isIdle: boolean,
isLoading: boolean,
isRefetching: boolean,
isSuccess: boolean,
refetch: (options: RefetchOptions) => Promise,
}
```
## Configuration
### assetId
Asset identifier. Can also be a string passed as the only parameter.
```tsx {3} theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { data: asset } = useAsset({
assetId,
});
}
```
### UseQueryOptions
The `useAsset` hook also supports any
[Tanstack Query](https://tanstack.com/query/v4/docs/reference/useQuery)
`useQuery` options, such as `refetchInterval` or `enabled`. These override any
configs passed by default by the internal hook.
```tsx {4} theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { data: asset } = useAsset({
assetId,
refetchInterval: (asset) => (!asset?.playbackUrl ? 5000 : false),
});
}
```
## SSR
The following section only applies to web-based use-cases - React Native has
no concept of SSR.
### Next.js
The `useAsset` hook also comes with a
[Tanstack Query](https://tanstack.com/query/v4/docs/guides/ssr) prefetch query,
`prefetchAsset`, which makes it easy to prefetch data for server-side rendering.
First, you add a
[`getStaticProps`](https://nextjs.org/docs/basic-features/data-fetching/get-static-props)
function to the page which you want to prefetch data on. The props should match
the `useAsset` hook to ensure that the correct data is prefetched.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// pages/demo.tsx
import { prefetchAsset, studioProvider } from "@livepeer/react";
export const getStaticProps = async () => {
const dehydratedState = await prefetchAsset(
{ assetId },
{ provider: studioProvider({ apiKey: "yourStudioApiKey" }) }
);
return {
props: {
dehydratedState,
},
revalidate: 600,
};
};
```
We need to update the `_app.tsx` to pass the `dehydratedState` in `pageProps` to
the LivepeerConfig. We also move the `livepeerClient` into a useMemo hook so
that a new client is created on each request.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// pages/_app.tsx
import {
LivepeerConfig,
createReactClient,
studioProvider,
} from "@livepeer/react";
import type { AppProps } from "next/app";
import { useMemo } from "react";
function App({ Component, pageProps }: AppProps<{ dehydratedState: string }>) {
// we create a new livepeer client on each request so data is
// not shared between users
const livepeerClient = useMemo(
() =>
createReactClient({
provider: studioProvider({
apiKey: process.env.NEXT_PUBLIC_STUDIO_API_KEY,
}),
}),
[]
);
return (
);
}
```
That's it! You now have data prefetching on the server, which is passed to the
browser and used to hydrate the initial query client.
### Other Frameworks
The process is very similar for other frameworks, with the exception that there
is a `clearClient` boolean which should be used to ensure that the client cache
is not reused across users.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { prefetchAsset, studioProvider } from "@livepeer/react";
export const handleRequest = async (req, res) => {
const dehydratedState = await prefetchAsset(
{
assetId,
clearClient: true,
},
{ provider: studioProvider({ apiKey: "yourStudioApiKey" }) }
);
// sanitize the custom SSR generated data
// https://medium.com/node-security/the-most-common-xss-vulnerability-in-react-js-applications-2bdffbcc1fa0
res.send(`
${html}
`);
};
```
# useAssetMetrics
Source: https://docs.livepeer.org/v1/sdks/react/migration/3.x/asset/useAssetMetrics
React Hook for retrieving metrics for an asset.
Hook for retrieving metrics for an Asset.
## Usage
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useAssetMetrics } from '@livepeer/react';
```
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useAssetMetrics } from '@livepeer/react-native';
```
Metrics are currently only available if a user has the ID associated with an
asset. This should only be the user(s) with write access to the asset -
viewers are not able to use this hook.
The following examples assume an ID has been created for an asset, and the
[`Player`](/sdks/react/Player) is used for playback (with its built-in metrics
reporting).
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { data: metrics } = useAssetMetrics({ assetId });
}
```
If a falsy asset ID is provided, the query will be skipped.
## Return Value
The return value is partially based on
[Tanstack Query](https://tanstack.com/query/v4/docs/reference/useQuery), with
some return types aggregated for simplicity.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
data?: ViewsMetrics,
error?: Error,
status: 'idle' | 'loading' | 'success' | 'error',
isError: boolean,
isFetched: boolean,
isFetching: boolean,
isIdle: boolean,
isLoading: boolean,
isRefetching: boolean,
isSuccess: boolean,
refetch: (options: RefetchOptions) => Promise,
}
```
## Configuration
### assetId
Asset identifier.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { data: metrics } = useAssetMetrics({
assetId,
});
}
```
### UseQueryOptions
The `useAssetMetrics` hook also supports any
[Tanstack Query](https://tanstack.com/query/v4/docs/reference/useQuery)
`useQuery` options, such as `refetchInterval` or `enabled`. These override any
configs passed by default by the internal hook.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { data: metrics } = useAssetMetrics({
assetId,
refetchInterval: 30000,
});
}
```
## SSR
The following section only applies to web-based use-cases - React Native has
no concept of SSR.
### Next.js
The `useAssetMetrics` hook also comes with a
[Tanstack Query](https://tanstack.com/query/v4/docs/guides/ssr) prefetch query,
`prefetchAssetMetrics`, which makes it easy to prefetch data for server-side
rendering.
First, you add a
[`getStaticProps`](https://nextjs.org/docs/basic-features/data-fetching/get-static-props)
function to the page which you want to prefetch data on. The props should match
the `useAsset` hook to ensure that the correct data is prefetched.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// pages/demo.tsx
import { prefetchAssetMetrics, studioProvider } from "@livepeer/react";
export const getStaticProps = async () => {
const dehydratedState = await prefetchAssetMetrics(
{ assetId },
{ provider: studioProvider({ apiKey: "yourStudioApiKey" }) }
);
return {
props: {
dehydratedState,
},
revalidate: 600,
};
};
```
We need to update the `_app.tsx` to pass the `dehydratedState` in `pageProps` to
the LivepeerConfig. We also move the `livepeerClient` into a useMemo hook so
that a new client is created on each request.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// pages/_app.tsx
import {
LivepeerConfig,
createReactClient,
studioProvider,
} from "@livepeer/react";
import type { AppProps } from "next/app";
import { useMemo } from "react";
function App({ Component, pageProps }: AppProps<{ dehydratedState: string }>) {
// we create a new livepeer client on each request so data is
// not shared between users
const livepeerClient = useMemo(
() =>
createReactClient({
provider: studioProvider({
apiKey: process.env.NEXT_PUBLIC_STUDIO_API_KEY,
}),
}),
[]
);
return (
);
}
```
That's it! You now have data prefetching on the server, which is passed to the
browser and used to hydrate the initial query client.
### Other Frameworks
The process is very similar for other frameworks, with the exception that there
is a `clearClient` boolean which should be used to ensure that the client cache
is not reused across users.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { prefetchAssetMetrics, studioProvider } from "@livepeer/react";
export const handleRequest = async (req, res) => {
const dehydratedState = await prefetchAssetMetrics(
{
assetId,
clearClient: true,
},
{ provider: studioProvider({ apiKey: "yourStudioApiKey" }) }
);
// sanitize the custom SSR generated data
// https://medium.com/node-security/the-most-common-xss-vulnerability-in-react-js-applications-2bdffbcc1fa0
res.send(`
${html}
`);
};
```
# useCreateAsset
Source: https://docs.livepeer.org/v1/sdks/react/migration/3.x/asset/useCreateAsset
React Hook for creating a new asset.
useCreateAsset is a React Hook for creating a new asset. It returns a `mutate`
function that can be called to create an asset. Multiple assets can be created
at once by passing in an array of `sources`.
## Usage
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useCreateAsset } from '@livepeer/react';
```
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useCreateAsset } from '@livepeer/react-native';
```
The asset ID should only be passed to users who are allowed to modify the
asset. **Ensure viewers are only provided with the `playbackId`,** which is a
limited identifier that provides only the ability to stream media using the
[`Player`](/sdks/react/Player).
The following example shows how an asset can be created with the `mutate`
function. The variables are passed into the `useCreateAsset` hook, and
`createAsset` return type is defined when the variables are truthy.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const [video, setVideo] = useState(undefined);
const {
mutate: createAsset,
data: assets,
status,
progress,
error,
} = useCreateAsset(
// we use a `const` assertion here to provide better Typescript types
// for the returned data
video
? {
sources: [
{
name: video.name,
file: video,
storage: {
ipfs: true,
metadata: {
name: "interesting video",
description: "a great description of the video",
},
},
},
] as const,
}
: null
);
return (
);
}
```
## Mutation
## Return Value
The return value is partially based on
[Tanstack Query](https://tanstack.com/query/v4/docs/reference/useMutation), with
some return types aggregated for simplicity.
The value `progress` is an array of progress values which contains the upload
progress from [tus](https://github.com/tus/tus-js-client), as well as the
processing progress of the asset from the provider. These values are polled
consistently until the asset succeeds or fails to be processed by the provider.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
data?: Asset[],
progress?: CreateAssetProgress,
error?: Error,
isError: boolean,
isIdle: boolean,
isLoading: boolean,
isSuccess: boolean,
status: 'idle' | 'loading' | 'success' | 'error',
mutate: () => void,
mutateAsync: () => Promise,
variables?: CreateAssetArgs
}
```
## Configuration
### sources
The `sources` used for the asset creation can be an array of either a URL or a
local File/ReadStream/object with a `uri` string. *It is highly recommended to
use
[const assertions](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-4.html#const-assertions)
to infer types properly from the `sources` parameter - please see below for an
example.*
```tsx " theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useCreateAsset } from "@livepeer/react";
function SomeComponent() {
const { mutate: createAsset, status } = useCreateAsset({
sources: [
{
name: video.name,
file: video,
creatorId: "0xabcd000000000000000000000000000000001234",
storage: {
ipfs: true,
metadata: {
name: "interesting video",
description: "a great description of the video",
},
},
},
] as const,
});
}
```
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useCreateAsset } from "@livepeer/react";
function SomeComponent() {
// get the URI from a file picker
// then pass the URI into the source
const { mutate: createAsset, status } = useCreateAsset({
sources: [
{
name: video.name,
file: { uri },
creatorId: "0xabcd000000000000000000000000000000001234",
storage: {
ipfs: true,
metadata: {
name: "interesting video",
description: "a great description of the video",
},
},
},
] as const,
});
}
```
The `useCreateAsset` hook uses [tus](https://github.com/tus/tus-js-client) for
resumable uploads and checks for existing uploads by default, before starting
a new upload. **It also automatically polls the livepeer provider's API to
update `status` until the import job is complete.**
The `sources` type can be either a URL or a File/ReadStream:
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
type CreateAssetSourceUrl = {
/** Name for the new asset */
name: string;
/** External URL to be imported */
url: string;
/** The storage configs for the new asset (e.g. IPFS) */
storage?: Storage;
/**
* Sets the playback policy for the asset created.
*/
playbackPolicy?: PlaybackPolicy;
/**
* Sets the creator ID for the asset that is created.
* This should be an wallet's public address.
*/
creatorId?: CreateAssetCreatorId;
};
/** React Native file type */
type NativeFile = File & {
uri: string;
};
type CreateAssetSourceFile = {
/** Name for the new asset */
name: string;
/** Content to be uploaded or streamed */
file: File | ReadStream | NativeFile;
/** The storage configs for the new asset (e.g. IPFS) */
storage?: Storage;
/**
* Sets the playback policy for the asset created.
*/
playbackPolicy?: PlaybackPolicy;
/**
* Sets the creator ID for the asset that is created.
* This should be an wallet's public address.
*/
creatorId?: CreateAssetCreatorId;
};
/** Source(s) to upload - can be a file or URL source */
type Sources = CreateAssetSourceFile[] | CreateAssetSourceUrl[];
```
We are planning on adding further features to the creator ID such as provable
claims. Reach out to us on [Discord](https://discord.gg/livepeer) if you're
interested!
If `CreateAssetSourceFile` is passed in the array, the `useCreateAsset` hook
uses [tus](https://github.com/tus/tus-js-client) for resumable uploads and
checks for existing uploads by default, before starting a new upload.
If `CreateAssetSourceUrl` is passed in the array, the hook will make a request
to the background to start an import. This can also be an IPFS URL
(`ipfs://`) or Arweave URL (`ar://`). **Either a URL or file must be
provided.**
#### storage
The `storage` configs can be applied on asset creation. See `useUpdateAsset` for
more details on these configs. If the `storage` parameter is omitted, the asset
will not be stored in decentralized storage.
If you would like to use Arweave as storage, we recommend you upload to
Arweave first and then import the video.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
type Storage = {
/**
* If the asset should be stored on IPFS.
*/
ipfs?: boolean;
/**
* Metadata exported to the storage provider. This will be deep merged with the default
* metadata from the livepeer provider. This should ideally be EIP-721/EIP-1155 compatible.
*
* @see {@link https://eips.ethereum.org/EIPS/eip-721}
*/
metadata?: Partial & {
[k: string]: unknown;
};
/**
* The metadata template to use. `player` will embed the Livepeer Player's IPFS CID while `file`
* will reference only the immutable media files.
*/
metadataTemplate?: "player" | "file";
};
```
The metadata can be overridden when the Asset and its metadata are exported to
IPFS - we provide some helper types for metadata best practices based on ERC-721
and ERC-1155:
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
type Metadata = {
/** Name of the Asset */
name?: string;
/** Description of the Asset */
description?: string;
/** Image URL for the Asset */
image?: string;
/** Properties of the Asset */
properties?: {
[k: string]: unknown;
};
/**
* Background color for the Asset (OpenSea Standard)
*
* @see {@link https://docs.opensea.io/docs/metadata-standards}
*/
background_color?: string;
/**
* Attributes for the Asset (OpenSea Standard)
*
* @see {@link https://docs.opensea.io/docs/metadata-standards}
*/
attributes?: {
[k: string]: unknown;
};
};
```
### noWait
The `noWait` config option skips the polling mechanism which waits for the Asset
upload to succeed or fail. It will immediately return after the file upload is
complete, or in the case of a URL upload, it will return after the URL is
`POST`ed to the backend.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useCreateAsset } from "@livepeer/react";
function SomeComponent() {
const { mutate: createAsset } = useCreateAsset({
sources: [{ name: video.name, file: video }] as const,
noWait,
});
}
```
### mutationConfig
The `mutationConfig` parameter allows for any
[Tanstack Query](https://tanstack.com/query/v4/docs/reference/useMutation)
`useMutation` options, such as `cacheTime` or `retry`. These override any
configs passed by default by the internal hook.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useCreateAsset } from "@livepeer/react";
function SomeComponent() {
const { mutate: createAsset } = useCreateAsset({
sources: [{ name: video.name, file: video }] as const,
mutationConfig: { retry: 5 },
});
}
```
# useUpdateAsset
Source: https://docs.livepeer.org/v1/sdks/react/migration/3.x/asset/useUpdateAsset
React Hook for updating an asset.
Hook for updating an existing
[Asset](https://github.com/livepeer/react/blob/main/packages/core/src/types/provider.ts).
## Usage
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useUpdateAsset } from '@livepeer/react';
```
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useUpdateAsset } from '@livepeer/react-native';
```
The following example shows how an asset can be updated.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const assetId = "7ce29561-91ae-42cf-b9c0-6e46dbc1cc2d";
function SomeComponent() {
const { data: asset } = useAsset({
assetId,
refetchInterval: 10000,
});
const {
mutate: updateAsset,
status,
error,
} = useUpdateAsset({
assetId,
storage: { ipfs: true },
});
return (
{asset && (
<>
Asset Name: {asset?.name}
IPFS CID: {asset?.storage?.ipfs?.cid ?? "None"}
>
)}
{error &&
{error.message}
}
);
}
```
## Return Value
The return value is partially based on
[Tanstack Query](https://tanstack.com/query/v4/docs/reference/useMutation), with
some return types aggregated for simplicity.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
data?: Asset,
error?: Error,
isError: boolean,
isIdle: boolean,
isLoading: boolean,
isSuccess: boolean,
status: 'idle' | 'loading' | 'success' | 'error',
mutate: () => void,
mutateAsync: () => Promise,
variables?: UpdateAssetArgs
}
```
## Configuration
### assetId
The asset ID to update - required.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useUpdateAsset } from "@livepeer/react";
function SomeComponent() {
const { mutate: updateAsset } = useUpdateAsset({
assetId,
name: "New Name",
});
}
```
### name
The updated name for the asset.
### storage
The storage configs to use for the asset. This is preferably EIP-721 or EIP-1155
compatible metadata configs.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
type Storage = {
/**
* If the asset should be stored on IPFS.
*/
ipfs?: boolean;
/**
* Metadata exported to the storage provider. This will be deep merged with the default
* metadata from the livepeer provider. This should ideally be EIP-721/EIP-1155 compatible.
*
* @see {@link https://eips.ethereum.org/EIPS/eip-721}
*/
metadata?: Partial & {
[k: string]: unknown;
};
/**
* The metadata template to use. `player` will embed the Livepeer Player's IPFS CID while `file`
* will reference only the immutable media files.
*/
metadataTemplate?: "player" | "file";
};
```
The metadata can be overridden when the Asset and its metadata are exported to
IPFS - we provide some helper types for metadata best practices based on ERC-721
and ERC-1155:
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
type Metadata = {
/** Name of the Asset */
name?: string;
/** Description of the Asset */
description?: string;
/** Image URL for the Asset */
image?: string;
/** Properties of the Asset */
properties?: {
[k: string]: unknown;
};
/**
* Background color for the Asset (OpenSea Standard)
*
* @see {@link https://docs.opensea.io/docs/metadata-standards}
*/
background_color?: string;
/**
* Attributes for the Asset (OpenSea Standard)
*
* @see {@link https://docs.opensea.io/docs/metadata-standards}
*/
attributes?: {
[k: string]: unknown;
};
};
```
### mutationConfig
The `mutationConfig` parameter allows for any
[Tanstack Query](https://tanstack.com/query/v4/docs/reference/useMutation)
`useMutation` options, such as `cacheTime` or `retry`. These override any
configs passed by default by the internal hook.
```tsx {7} theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useUpdateAsset } from "@livepeer/react";
function SomeComponent() {
const { mutate: updateAsset } = useUpdateAsset({
assetId,
name: "New Name",
mutationConfig: { retry: 3 },
});
}
```
# Client
Source: https://docs.livepeer.org/v1/sdks/react/migration/3.x/client
The livepeer Client is a framework agnostic client that manages wallet connection state and configuration, such as: auto-connection, connectors, and ethers providers.
The livepeer `Client` is a framework agnostic client that manages state and
connection to a Livepeer provider. The `createReactClient` function wraps the
`Client` with a React-specific caching layer for faster queries.
## Usage
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { createReactClient } from '@livepeer/react';
```
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { createReactClient } from '@livepeer/react-native';
```
The client can be created using `createReactClient`.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const client = createReactClient({
provider: studioProvider({ apiKey: "yourStudioApiKey" }),
});
```
## Configuration
### provider
Livepeer provider interface for connecting to the network.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const client = createReactClient({
provider: studioProvider({ apiKey: "yourStudioApiKey" }),
});
```
### storage (optional)
The default strategy to persist and cache data. Used for both state management
and query caching. Defaults to `window.localStorage`.
To disable the use of localStorage, we provide a convenient "no-op" storage
option:
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import {
createReactClient,
studioProvider,
noopStorage,
createStorage,
} from "@livepeer/react";
const client = createReactClient({
provider: studioProvider({ apiKey: 'yourStudioApiKey' }),
storage: createStorage({
storage: noopStorage,
}),
});
```
The default strategy to persist and cache data. Used for both state management
and query caching. Defaults to no storage.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import AsyncStorage from '@react-native-async-storage/async-storage';
const client = createReactClient({
provider: studioProvider({ apiKey: 'yourStudioApiKey' }),
storage: createStorage({ storage: AsyncStorage }),
});
```
### queryClient (optional)
The react-query
[QueryClient](https://tanstack.com/query/v4/docs/reference/QueryClient) used to
cache/deduplicate queries. Defaults to caching for 24 hours and no retries.
```ts theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const client = createReactClient({
provider: studioProvider({ apiKey: "yourStudioApiKey" }),
queryClient: new QueryClient({
defaultOptions: {
queries: {
cacheTime: 1_000 * 60 * 60, // 1 hour
retry: 100,
},
},
}),
});
```
# Application Binary Interface
Source: https://docs.livepeer.org/v1/sdks/react/migration/3.x/constants/abis
All Livepeer ABIs available via import.
All Livepeer ABIs are available via import.
## Protocol
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import {
BondingManagerABI,
ControllerABI,
LivepeerTokenABI,
LivepeerTokenFaucetABI,
MerkleSnapshotABI,
MinterABI,
PollABI,
PollCreatorABI,
RoundsManagerABI,
ServiceRegistryABI,
TicketBrokerABI,
} from '@livepeer/react';
```
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import {
BondingManagerABI,
ControllerABI,
LivepeerTokenABI,
LivepeerTokenFaucetABI,
MerkleSnapshotABI,
MinterABI,
PollABI,
PollCreatorABI,
RoundsManagerABI,
ServiceRegistryABI,
TicketBrokerABI,
} from '@livepeer/react-native';
```
## Bridging
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import {
ArbRetryableTxABI,
InboxABI,
L1BondingManagerABI,
L1MigratorABI,
L2LPTGatewayABI,
L2MigratorABI,
NodeInterfaceABI,
} from '@livepeer/react';
```
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import {
ArbRetryableTxABI,
InboxABI,
L1BondingManagerABI,
L1MigratorABI,
L2LPTGatewayABI,
L2MigratorABI,
NodeInterfaceABI,
} from '@livepeer/react-native';
```
# Contract Addresses
Source: https://docs.livepeer.org/v1/sdks/react/migration/3.x/constants/contract-addresses
All contract addresses for the Livepeer protocol.
**This page documents a deprecated SDK version.** For current contract addresses, see:
**[Livepeer Contract Addresses](/v2/about/resources/livepeer-contract-addresses)**
All contract addresses for the Livepeer protocol.
## Addresses
The addresses for the protocol contracts are provided in a simple import with
types.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import {
arbitrumOneAddress,
arbitrumRinkebyAddress,
mainnetAddress,
rinkebyAddress,
} from '@livepeer/react';
```
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import {
arbitrumOneAddress,
arbitrumRinkebyAddress,
mainnetAddress,
rinkebyAddress,
} from '@livepeer/react-native';
```
These addresses will be expanded upon in a future version of Livepeer React to
include more in-depth contract interaction.
## Chain IDs
There are exports for the chain IDs the Livepeer protocol is currently deployed
on. This includes both Arbitrum One/mainnet and testnet chains.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import {
allChainId, mainnetChainId, testnetChainId
} from '@livepeer/react';
```
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import {
allChainId, mainnetChainId, testnetChainId
} from '@livepeer/react-native';
```
# Getting Started
Source: https://docs.livepeer.org/v1/sdks/react/migration/3.x/getting-started
Get started building with Livepeer UI Kit!
These docs are written for a React or React Native developer building on
`@livepeer/react` or `@livepeer/react-native`.
## Installation
Install Livepeer React using your favorite package manager.
```
npm i @livepeer/react
```
React Native also requires some peer dependencies (used in the `Player`
component). We rely on `expo` for pod installation/linking. You must ensure that
the
[correct version of `react-native-svg`](https://github.com/software-mansion/react-native-svg#supported-react-native-versions)
is installed.
If you're installing this in a
[bare React Native app](https://docs.expo.dev/introduction/managed-vs-bare/#bare-workflow),
you should also follow the
[extra `expo-av` installation instructions](https://github.com/expo/expo/tree/sdk-47/packages/expo-av).
```bash React Native theme={"theme":{"light":"github-light","dark":"dark-plus"}}
expo install @livepeer/react-native expo-av react-native-svg
```
## Create a livepeer client
First, create a livepeer `Client` instance using
[`createReactClient`](/sdks/react/migration/3.x/client), and pass a provider to
it.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { createReactClient, studioProvider } from '@livepeer/react';
const client = createReactClient({
provider: studioProvider({ apiKey: 'yourStudioApiKey' }),
});
```
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { createReactClient, studioProvider } from '@livepeer/react-native';
const client = createReactClient({
provider: studioProvider({ apiKey: 'yourStudioApiKey' }),
});
```
Note: If you choose to use Studio as a provider, you will need to configure an
API key for the `studioProvider` which is
[CORS-protected API key](/sdks/react/migration/3.x/providers/studio#apikey).
[Read more about client configuration](/sdks/react/migration/3.x/client)
## Wrap app with `LivepeerConfig`
Next, wrap the app with the
[`LivepeerConfig`](/sdks/react/migration/3.x/LivepeerConfig) component, passing
the `client` to it.
This is added to `_app.js` for Next.js or `App.js` with Create React App, so that the
`LivepeerConfig` React Context is available across every component.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import {
LivepeerConfig,
createReactClient,
studioProvider,
} from '@livepeer/react';
const client = createReactClient({
provider: studioProvider({ apiKey: 'yourStudioApiKey' }),
});
function App() {
return (
);
}
```
This is added to `App.js`, so that the `LivepeerConfig` React Context is available across every component.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import {
LivepeerConfig,
createReactClient,
studioProvider,
} from '@livepeer/react-native';
const client = createReactClient({
provider: studioProvider({ apiKey: 'yourStudioApiKey' }),
});
function App() {
return (
);
}
```
## Enjoy!
Use hooks! Every component inside the `LivepeerConfig` is now set up to use the
livepeer hooks.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useAsset } from '@livepeer/react';
function SomeComponent() {
const asset = useAsset({ assetId: 'd8e8b87d-6774-4083-a2d7-4e85872d18cd' });
return
;
}
```
Want to learn more? Continue reading the documentation for more details.
# usePlaybackInfo
Source: https://docs.livepeer.org/v1/sdks/react/migration/3.x/playback/usePlaybackInfo
React Hook for retrieving playback details for a playback ID.
Hook for retrieving playback information related to a playback ID. Used
internally in the [`Player`](/sdks/react/Player) to fetch the playback URL for a
playback ID.
## Usage
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { usePlaybackInfo } from '@livepeer/react';
```
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { usePlaybackInfo } from '@livepeer/react-native';
```
The following examples assume a playback ID has been created for an asset or
stream.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { data: playbackInfo } = usePlaybackInfo(playbackId);
}
```
If a falsy playback ID is provided, the query will be skipped.
## Return Value
The return value is partially based on
[Tanstack Query](https://tanstack.com/query/v4/docs/reference/useQuery), with
some return types aggregated for simplicity.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
data?: PlaybackInfo,
error?: Error,
status: 'idle' | 'loading' | 'success' | 'error',
isError: boolean,
isFetched: boolean,
isFetching: boolean,
isIdle: boolean,
isLoading: boolean,
isRefetching: boolean,
isSuccess: boolean,
refetch: (options: RefetchOptions) => Promise,
}
```
## Configuration
### playbackId
Playback identifier. Can also be a string passed as the only parameter.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { data: playbackInfo } = usePlaybackInfo({
playbackId,
});
}
```
### UseQueryOptions
The `usePlaybackInfo` hook also supports any
[Tanstack Query](https://tanstack.com/query/v4/docs/reference/useQuery)
`useQuery` options, such as `refetchInterval` or `enabled`. These override any
configs passed by default by the internal hook.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { data: playbackInfo } = usePlaybackInfo({
playbackId,
refetchInterval: 30000,
});
}
```
## SSR
The following section only applies to web-based use-cases - React Native has
no concept of SSR.
### Next.js
The `usePlaybackInfo` hook also comes with a
[Tanstack Query](https://tanstack.com/query/v4/docs/guides/ssr) prefetch query,
`prefetchPlaybackInfo`, which makes it easy to prefetch data for server-side
rendering.
First, you add a
[`getStaticProps`](https://nextjs.org/docs/basic-features/data-fetching/get-static-props)
function to the page which you want to prefetch data on. The props should match
the `usePlaybackInfo` hook to ensure that the correct data is prefetched.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// pages/demo.tsx
import { prefetchPlaybackInfo, studioProvider } from "@livepeer/react";
export const getStaticProps = async () => {
const dehydratedState = await prefetchPlaybackInfo(
{ playbackId },
{ provider: studioProvider({ apiKey: "yourStudioApiKey" }) }
);
return {
props: {
dehydratedState,
},
revalidate: 600,
};
};
```
We need to update the `_app.tsx` to pass the `dehydratedState` in `pageProps` to
the LivepeerConfig. We also move the `livepeerClient` into a useMemo hook so
that a new client is created on each request.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// pages/_app.tsx
import {
LivepeerConfig,
createReactClient,
studioProvider,
} from "@livepeer/react";
import type { AppProps } from "next/app";
import { useMemo } from "react";
function App({ Component, pageProps }: AppProps<{ dehydratedState: string }>) {
// we create a new livepeer client on each request so data is
// not shared between users
const livepeerClient = useMemo(
() =>
createReactClient({
provider: studioProvider({
apiKey: process.env.NEXT_PUBLIC_STUDIO_API_KEY,
}),
}),
[]
);
return (
);
}
```
That's it! You now have data prefetching on the server, which is passed to the
browser and used to hydrate the initial query client.
### Other Frameworks
The process is very similar for other frameworks, with the exception that there
is a `clearClient` boolean which should be used to ensure that the client cache
is not reused across users.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { prefetchPlaybackInfo, studioProvider } from "@livepeer/react";
export const handleRequest = async (req, res) => {
const dehydratedState = await prefetchPlaybackInfo(
{
playbackId,
clearClient: true,
},
{ provider: studioProvider({ apiKey: "yourStudioApiKey" }) }
);
// sanitize the custom SSR generated data
// https://medium.com/node-security/the-most-common-xss-vulnerability-in-react-js-applications-2bdffbcc1fa0
res.send(`
${html}
`);
};
```
# useCreateStream
Source: https://docs.livepeer.org/v1/sdks/react/migration/3.x/stream/useCreateStream
React Hook for creating a new stream.
Hook for creating a new
[Stream](https://github.com/livepeer/react/blob/main/packages/core/src/types/provider.ts).
## Usage
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useCreateStream } from '@livepeer/react';
```
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useCreateStream } from '@livepeer/react-native';
```
The stream ID should only be passed to users who are allowed to modify the
stream. **Ensure viewers are only provided with the `playbackId`,** which is a
limited identifier that provides only the ability to stream media using the
[`Player`](/sdks/react/Player).
The following example shows how a stream can be created.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const streamName = `New Stream`;
function SomeComponent() {
const {
mutate: createStream,
data: stream,
status,
} = useCreateStream({ name: streamName });
return (
{stream &&
Stream Key: {stream.streamKey}
}
);
}
```
## Return Value
The return value is partially based on
[Tanstack Query](https://tanstack.com/query/v4/docs/reference/useMutation), with
some return types aggregated for simplicity.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
data?: Stream,
error?: Error,
isError: boolean,
isIdle: boolean,
isLoading: boolean,
isSuccess: boolean,
status: 'idle' | 'loading' | 'success' | 'error',
mutate: () => void,
mutateAsync: () => Promise,
variables?: CreateStreamArgs
}
```
## Configuration
### name
The name for the new stream. Required to create a stream.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { mutate: createStream } = useCreateStream({
name: "My new stream",
});
}
```
### profiles
Transcoding profiles to use for the stream for ABR playback. When this is not
defined, the `defaultTranscodingProfiles` are used (720p, 480p, and 360p).
### record
Whether to create recordings of the stream sessions. Defaults to `false`.
### multistream
The configuration for multistreaming (AKA "restream" or "simulcast") - allows
configuration of targets where this stream should be simultaneously streamed to.
### playbackPolicy
Configuration for stream playback access-control policy. Defaults to `public`.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
type PlaybackPolicy = {
/**
* The type of playback policy to apply. `jwt` requires a signed JWT for
* playback. `webhook` requires that a webhook is configured and passed during the
* creation of the asset. `public` indicates no
* access control will be applied (anyone with the `playbackId` can
* view without a JWT or webhook).
*/
type: "webhook" | "jwt" | "public";
};
type WebhookPlaybackPolicy = PlaybackPolicy & {
type: "webhook";
/** The ID of the webhook which has already been created. */
webhookId: string;
/** The context which is passed to the webhook when it is called on playback. */
webhookContext: TContext;
};
```
### mutationConfig
The `mutationConfig` parameter allows for any
[Tanstack Query](https://tanstack.com/query/v4/docs/reference/useMutation)
`useMutation` options, such as `cacheTime` or `retry`. These override any
configs passed by default by the internal hook.
```tsx {4} theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { mutate: createStream } = useCreateStream({
name: "My new stream",
mutationConfig: { retry: 3 },
});
}
```
# useStream
Source: https://docs.livepeer.org/v1/sdks/react/migration/3.x/stream/useStream
React Hook for retrieving a stream.
Hook for retrieving a
[Stream](https://github.com/livepeer/react/blob/main/packages/core/src/types/provider.ts)
based on a unique identifier.
## Usage
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useStream } from '@livepeer/react';
```
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useStream } from '@livepeer/react-native';
```
The following examples assume a stream was created via `useCreateStream` or
directly via a provider's API/dashboard. If a falsy stream ID is provided, the
query will be skipped.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { data: stream } = useStream(stream?.id);
}
```
## Return Value
The return value is partially based on
[Tanstack Query](https://tanstack.com/query/v4/docs/reference/useQuery), with
some return types aggregated for simplicity.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
data?: Stream,
error?: Error,
status: 'idle' | 'loading' | 'success' | 'error',
isError: boolean,
isFetched: boolean,
isFetching: boolean,
isIdle: boolean,
isLoading: boolean,
isRefetching: boolean,
isSuccess: boolean,
refetch: (options: RefetchOptions) => Promise,
}
```
## Configuration
### streamId
Stream identifier. Can also be a string passed as the only parameter.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { data: stream } = useStream({
streamId,
});
}
```
### UseQueryOptions
The `useStream` hook also supports any
[Tanstack Query](https://tanstack.com/query/v4/docs/reference/useQuery)
`useQuery` options, such as `refetchInterval` or `enabled`. These override any
configs passed by default by the internal hook.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { data: stream } = useStream({
streamId,
refetchInterval: (stream) => (!stream?.isActive ? 5000 : false),
});
}
```
## SSR
The following section only applies to web-based use-cases - React Native has
no concept of SSR.
### Next.js
The `useStream` hook also comes with a
[Tanstack Query](https://tanstack.com/query/v4/docs/guides/ssr) prefetch query,
`prefetchStream`, which makes it easy to prefetch data for server-side
rendering.
First, you add a
[`getStaticProps`](https://nextjs.org/docs/basic-features/data-fetching/get-static-props)
function to the page which you want to prefetch data on. The props should match
the `useStream` hook to ensure that the correct data is prefetched.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// pages/demo.tsx
import { prefetchStream, studioProvider } from "@livepeer/react";
export const getStaticProps = async () => {
const dehydratedState = await prefetchStream(
{ streamId },
{ provider: studioProvider({ apiKey: "yourStudioApiKey" }) }
);
return {
props: {
dehydratedState,
},
revalidate: 600,
};
};
```
We need to update the `_app.tsx` to pass the `dehydratedState` in `pageProps` to
the LivepeerConfig. We also move the `livepeerClient` into a useMemo hook so
that a new client is created on each request.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// pages/_app.tsx
import {
LivepeerConfig,
createReactClient,
studioProvider,
} from "@livepeer/react";
import type { AppProps } from "next/app";
import { useMemo } from "react";
function App({ Component, pageProps }: AppProps<{ dehydratedState: string }>) {
// we create a new livepeer client on each request so data is
// not shared between users
const livepeerClient = useMemo(
() =>
createReactClient({
provider: studioProvider({
apiKey: process.env.NEXT_PUBLIC_STUDIO_API_KEY,
}),
}),
[]
);
return (
);
}
```
That's it! You now have data prefetching on the server, which is passed to the
browser and used to hydrate the initial query client.
### Other Frameworks
The process is very similar for other frameworks, with the exception that there
is a `clearClient` boolean which should be used to ensure that the client cache
is not reused across users.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { prefetchStream, studioProvider } from "@livepeer/react";
export const handleRequest = async (req, res) => {
const dehydratedState = await prefetchStream(
{
streamId,
clearClient: true,
},
{ provider: studioProvider({ apiKey: "yourStudioApiKey" }) }
);
// sanitize the custom SSR generated data
// https://medium.com/node-security/the-most-common-xss-vulnerability-in-react-js-applications-2bdffbcc1fa0
res.send(`
${html}
`);
};
```
# useStreamSession
Source: https://docs.livepeer.org/v1/sdks/react/migration/3.x/stream/useStreamSession
React Hook for retrieving a stream session.
Hook for retrieving a
[Stream Session](https://github.com/livepeer/react/blob/main/packages/core/src/types/provider.ts)
based on a unique identifier.
## Usage
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useStreamSession } from '@livepeer/react';
```
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useStreamSession } from '@livepeer/react-native';
```
The following examples assume a stream session was created via streaming to an
existing Stream. If a falsy stream session ID is provided, the query will be
skipped.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { data: streamSession } = useStreamSession(streamSession?.id);
}
```
## Return Value
The return value is partially based on
[Tanstack Query](https://tanstack.com/query/v4/docs/reference/useQuery), with
some return types aggregated for simplicity.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
data?: StreamSession,
error?: Error,
status: 'idle' | 'loading' | 'success' | 'error',
isError: boolean,
isFetched: boolean,
isFetching: boolean,
isIdle: boolean,
isLoading: boolean,
isRefetching: boolean,
isSuccess: boolean,
refetch: (options: RefetchOptions) => Promise,
}
```
## Configuration
### streamSessionId
Stream session identifier. Can also be a string passed as the only parameter.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { data: streamSession } = useStreamSession({
streamSessionId,
});
}
```
### UseQueryOptions
The `useStreamSession` hook also supports any
[Tanstack Query](https://tanstack.com/query/v4/docs/reference/useQuery)
`useQuery` options, such as `refetchInterval` or `enabled`. These override any
configs passed by default by the internal hook.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { data: streamSession } = useStreamSession({
streamSessionId,
refetchInterval: (streamSession) =>
streamSession?.recordingStatus !== "ready" ? 5000 : false,
});
}
```
## SSR
The following section only applies to web-based use-cases - React Native has
no concept of SSR.
### Next.js
The `useStreamSession` hook also comes with a
[Tanstack Query](https://tanstack.com/query/v4/docs/guides/ssr) prefetch query,
`prefetchStreamSession`, which makes it easy to prefetch data for server-side
rendering.
First, you add a
[`getStaticProps`](https://nextjs.org/docs/basic-features/data-fetching/get-static-props)
function to the page which you want to prefetch data on. The props should match
the `useStreamSession` hook to ensure that the correct data is prefetched.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// pages/demo.tsx
import { prefetchStreamSession, studioProvider } from "@livepeer/react";
export const getStaticProps = async () => {
const dehydratedState = await prefetchStreamSession(
{ streamSessionId },
{ provider: studioProvider({ apiKey: "yourStudioApiKey" }) }
);
return {
props: {
dehydratedState,
},
revalidate: 600,
};
};
```
We need to update the `_app.tsx` to pass the `dehydratedState` in `pageProps` to
the LivepeerConfig. We also move the `livepeerClient` into a useMemo hook so
that a new client is created on each request.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// pages/_app.tsx
import {
LivepeerConfig,
createReactClient,
studioProvider,
} from "@livepeer/react";
import type { AppProps } from "next/app";
import { useMemo } from "react";
function App({ Component, pageProps }: AppProps<{ dehydratedState: string }>) {
// we create a new livepeer client on each request so data is
// not shared between users
const livepeerClient = useMemo(
() =>
createReactClient({
provider: studioProvider({
apiKey: process.env.NEXT_PUBLIC_STUDIO_API_KEY,
}),
}),
[]
);
return (
);
}
```
That's it! You now have data prefetching on the server, which is passed to the
browser and used to hydrate the initial query client.
### Other Frameworks
The process is very similar for other frameworks, with the exception that there
is a `clearClient` boolean which should be used to ensure that the client cache
is not reused across users.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { prefetchStreamSession, studioProvider } from "@livepeer/react";
export const handleRequest = async (req, res) => {
const dehydratedState = await prefetchStreamSession(
{
streamSessionId,
clearClient: true,
},
{ provider: studioProvider({ apiKey: "yourStudioApiKey" }) }
);
// sanitize the custom SSR generated data
// https://medium.com/node-security/the-most-common-xss-vulnerability-in-react-js-applications-2bdffbcc1fa0
res.send(`
${html}
`);
};
```
# useStreamSessions
Source: https://docs.livepeer.org/v1/sdks/react/migration/3.x/stream/useStreamSessions
React Hook for retrieving the stream sessions associated with a stream ID.
Hook for retrieving
[Stream Sessions](https://github.com/livepeer/react/blob/main/packages/core/src/types/provider.ts)
based on the parent stream's unique identifier.
## Usage
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useStreamSessions } from '@livepeer/react';
```
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useStreamSessions } from '@livepeer/react-native';
```
The following examples assume a Stream was created via via `useCreateStream` or
directly via a provider's API/dashboard. If a falsy stream ID is provided, the
query will be skipped.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { data: streamSessions } = useStreamSessions(stream?.id);
}
```
## Return Value
The return value is partially based on
[Tanstack Query](https://tanstack.com/query/v4/docs/reference/useQuery), with
some return types aggregated for simplicity.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
data?: StreamSession[],
error?: Error,
status: 'idle' | 'loading' | 'success' | 'error',
isError: boolean,
isFetched: boolean,
isFetching: boolean,
isIdle: boolean,
isLoading: boolean,
isRefetching: boolean,
isSuccess: boolean,
refetch: (options: RefetchOptions) => Promise,
}
```
## Configuration
### streamId
The stream identifier for the parent stream. Can also be a string passed as the
only parameter.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { data: streamSessions } = useStreamSessions({
streamId,
});
}
```
### UseQueryOptions
The `useStreamSessions` hook also supports any
[Tanstack Query](https://tanstack.com/query/v4/docs/reference/useQuery)
`useQuery` options, such as `refetchInterval` or `enabled`. These override any
configs passed by default by the internal hook.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { data: streamSessions } = useStreamSessions({
streamId,
refetchInterval: (streamSessions) =>
(streamSessions?.length ?? 0) === 0 ? 5000 : false,
});
}
```
## SSR
The following section only applies to web-based use-cases - React Native has
no concept of SSR.
### Next.js
The `useStreamSessions` hook also comes with a
[Tanstack Query](https://tanstack.com/query/v4/docs/guides/ssr) prefetch query,
`prefetchStreamSessions`, which makes it easy to prefetch data for server-side
rendering.
First, you add a
[`getStaticProps`](https://nextjs.org/docs/basic-features/data-fetching/get-static-props)
function to the page which you want to prefetch data on. The props should match
the `useStreamSessions` hook to ensure that the correct data is prefetched.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// pages/demo.tsx
import { prefetchStreamSessions, studioProvider } from "@livepeer/react";
export const getStaticProps = async () => {
const dehydratedState = await prefetchStreamSessions(
{ streamId },
{ provider: studioProvider({ apiKey: "yourStudioApiKey" }) }
);
return {
props: {
dehydratedState,
},
revalidate: 600,
};
};
```
We need to update the `_app.tsx` to pass the `dehydratedState` in `pageProps` to
the LivepeerConfig. We also move the `livepeerClient` into a useMemo hook so
that a new client is created on each request.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
// pages/_app.tsx
import {
LivepeerConfig,
createReactClient,
studioProvider,
} from "@livepeer/react";
import type { AppProps } from "next/app";
import { useMemo } from "react";
function App({ Component, pageProps }: AppProps<{ dehydratedState: string }>) {
// we create a new livepeer client on each request so data is
// not shared between users
const livepeerClient = useMemo(
() =>
createReactClient({
provider: studioProvider({
apiKey: process.env.NEXT_PUBLIC_STUDIO_API_KEY,
}),
}),
[]
);
return (
);
}
```
That's it! You now have data prefetching on the server, which is passed to the
browser and used to hydrate the initial query client.
### Other Frameworks
The process is very similar for other frameworks, with the exception that there
is a `clearClient` boolean which should be used to ensure that the client cache
is not reused across users.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { prefetchStreamSessions, studioProvider } from "@livepeer/react";
export const handleRequest = async (req, res) => {
const dehydratedState = await prefetchStreamSessions(
{
streamId,
clearClient: true,
},
{ provider: studioProvider({ apiKey: "yourStudioApiKey" }) }
);
// sanitize the custom SSR generated data
// https://medium.com/node-security/the-most-common-xss-vulnerability-in-react-js-applications-2bdffbcc1fa0
res.send(`
${html}
`);
};
```
# useUpdateStream
Source: https://docs.livepeer.org/v1/sdks/react/migration/3.x/stream/useUpdateStream
React Hook for updating an stream.
Hook for updating an existing
[Stream](https://github.com/livepeer/react/blob/main/packages/core/src/types/livepeer.ts).
## Usage
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useUpdateStream } from '@livepeer/react';
```
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { useUpdateStream } from '@livepeer/react-native';
```
The following example shows how an stream can be updated to enable recording and
require a JWT for playback
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
const streamId = "abcff74a-bb19-45af-8e63-b961efa1899e";
function SomeComponent() {
const { data: stream } = useStream({
streamId,
refetchInterval: 10000,
});
const {
mutate: updateStream,
status,
error,
} = useUpdateStream({
streamId,
record: true,
playbackPolicy: {
type: "jwt",
},
});
return (
{stream && (
<>
Stream Name: {stream?.name}
Recording?: {String(Boolean(stream.record))}
>
)}
{error &&
{error.message}
}
);
}
```
## Return Value
The return value is partially based on
[Tanstack Query](https://tanstack.com/query/v4/docs/reference/useMutation), with
some return types aggregated for simplicity.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
data?: Stream,
error?: Error,
isError: boolean,
isIdle: boolean,
isLoading: boolean,
isSuccess: boolean,
status: 'idle' | 'loading' | 'success' | 'error',
mutate: () => void,
mutateAsync: () => Promise,
variables?: UpdateStreamArgs
}
```
## Configuration
### streamId
The stream ID to update - required.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { mutate: createStream } = useUpdateStream({
streamId,
record: true,
});
}
```
### suspend
Whether to immediately block ingest and playback of the stream.
### record
Whether to create recordings of the stream sessions. Defaults to `false`.
### multistream
The configuration for multistreaming (AKA "restream" or "simulcast") - allows
configuration of targets where this stream should be simultaneously streamed to.
The multistream targets can be either a full `MultistreamTarget` like on create,
or a `MultistreamTargetRef`. The `Ref` object comes directly from the existing
`Stream` object, in case multistream has already been configured for the given
stream. It contains a vanity ID instead of the full `Spec` since the ingest URL
contains user secrets like the stream key.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
type MultistreamTarget = {
/**
* Name of transcoding profile that should be sent. Use "source" for pushing
* source stream data
*/
profile: string;
/**
* If true, the stream audio will be muted and only silent video will be
* pushed to the target.
*/
videoOnly?: boolean;
/**
* Unique ID of this multistream target. Used to dedup targets on update.
*/
id?: string;
/**
* Inline spec for the multistream target object. Underlying target resource
* will be automatically created.
*/
spec?: {
/** Name for the multistream target. Defaults to the URL hostname */
name?: string;
/** Livepeer-compatible multistream target URL (RTMP(s) or SRT) */
url: string;
};
};
```
### playbackPolicy
Configuration for stream playback access-control policy. Defaults to `public`.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
type PlaybackPolicy = {
/**
* The type of playback policy to apply. `jwt` requires a signed JWT for
* playback. `webhook` requires that a webhook is configured and passed during the
* creation of the asset. `public` indicates no
* access control will be applied (anyone with the `playbackId` can
* view without a JWT or webhook).
*/
type: "webhook" | "jwt" | "public";
};
type WebhookPlaybackPolicy = PlaybackPolicy & {
type: "webhook";
/** The ID of the webhook which has already been created. */
webhookId: string;
/** The context which is passed to the webhook when it is called on playback. */
webhookContext: TContext;
};
```
### mutationConfig
The `mutationConfig` parameter allows for any
[Tanstack Query](https://tanstack.com/query/v4/docs/reference/useMutation)
`useMutation` options, such as `cacheTime` or `retry`. These override any
configs passed by default by the internal hook.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function SomeComponent() {
const { mutate: updateStream } = useUpdateStream({
streamId,
record: true,
mutationConfig: { retry: 3 },
});
}
```
# Migration Guide for 4+
Source: https://docs.livepeer.org/v1/sdks/react/migration/migration-4.x
Migration guide for the 4.0.0 release of Livepeer React.
Livepeer React `v4.0.0+` was a complete rewrite of the library to support
video primitives.
## Introduction
This migration guide is designed to assist you in transitioning from the
previous version of the `@livepeer/react` library to the new major release. This
update is a significant overhaul aimed at addressing several key issues with the
previous releases.
## Before you start
### Major changes
* The library has been rewritten to offer unstyled, composable `` and
`` primitives based on
[Radix UI](https://www.radix-ui.com/primitives/docs/overview/introduction).
* The components are now highly composable, moving away from the monolithic
design of the previous versions.
* All components support the
[`asChild`](https://www.radix-ui.com/primitives/docs/guides/composition)
pattern, where the component will instead clone the part's child and passing
it the props and behavior required to make it functional.
* For instance: `{...}` will
not render a DOM element, and instead copy all of it's properties to the
child component, which will behave as a fullscreen trigger.
* The components are more aligned with web standards, allowing direct prop
passing to elements (notably the `Video` component).
* Automatic data fetching and CORS API key usage within components have been
removed to enhance security and reduce developer confusion.
* We highly recommend moving away from CORS API keys and making API requests
from your backend. *We plan to deprecate CORS API keys in the future.*
* The React Native package has been deprecated. The package was not
well-maintained and we have focused on web components for Livepeer React.
## Migration steps
### Primitives
Replace your usage of the single `` and `` components
with the new composable primitives. These include:
#### Player
* ``
* ``
* ``
* ``
* ``
* ``
* ...and more.
Check out our [complete example](/sdks/react/Player) for how these can be
composed to build a video player, modeled after the 3.x versions of the Player.
#### Broadcast
* ``
* ``
* ``
* ``
* ``
* ``
* ...and more.
Check out the [complete example](/sdks/react/Broadcast) for how these can be
composed to build a complete in-browser broadcast experience.
### Data fetching
1. All data fetching logic from the Livepeer Studio API has been removed from
the Player and Broadcast components.
* This includes all of the `useCreateAsset`, `useStream`, etc.
2. You will now need to use the [`livepeer`](/sdks/javascript) JS SDK (or
[another SDK](/sdks/introduction), depending on your applications's API
language) for data fetching and interaction.
* You must now make API requests in your backend to fetch playback info for a
playback ID.
* Use [`getSrc`](/sdks/react/player/get-src) utility function with the Player
or [`getIngest`](/sdks/react/broadcast/get-ingest) utility function with
Broadcast to parse the JSON responses from the API.
### Unstyled by default
1. The components are now unstyled by default. You will need to apply your own
styles.
2. Refer to the documentation for example styles that mimic the previous
versions, which you can customize as needed.
### Recommendations
1. Embrace the flexibility of **Composable components**. Use the `asChild`
pattern for more control over the rendering of components.
2. Use **automatic poster images** by passing the
[playback info](/api-reference/playback/get) response to `getSrc`.
3. There are no changes required to **resume progress on fallback**, which
resumes playback from where it was interrupted when an error occurs, and the
player falls back to another playback protocol.
4. Use `useMediaContext` for building custom components. See the implementation
of the primitives as an example of how to implement them.
### Callouts
1. Note the discontinuation of `autoUrlUpload` and direct IPFS playback. See
below for recommendations for how to migrate from this.
2. The new build system includes `use client` and `use server` directives in the
output. This means that you can directly import the client components into a
RSC and you don't need to wrap them. If you don't use React Server
Components, this doesn't affect you.
### React Native
The React Native package has been deprecated. Consider seeking alternative
solutions or consulting the team for future support plans.
### Replacing `autoUrlUpload`
To replace the usage of `autoUrlUpload`, use the following pseudocode as a guide
for how the logic used to work on the frontend.
```tsx /api/playback theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Livepeer } from "livepeer";
import { parseCid, parseArweaveTxId } from "@livepeer/core/utils";
const livepeer = new Livepeer({
apiKey: process.env.STUDIO_API_KEY ?? "",
});
const possibleIpfsCid =
"https://cloudflare-ipfs.com/ipfs/bafybeie2hgozfameyzawq6kkzc3tuf67g4kkufm4hoefxczpfe2fen2riu";
// if the source contains a CID or Arweave TX ID, these utility functions will parse out the
// ID and be non-null
const decentralizedSource =
parseCid(possibleIpfsCid) ?? parseArweaveTxId(possibleIpfsCid);
if (decentralizedSource?.id) {
// we check if the CID/Arweave ID already exists in the playback info endpoint
const response = await livepeer.playback.get(decentralizedSource.id);
if (!response.playbackInfo) {
// the CID/Arweave ID doesn't exist, so we import it by the URL
await livepeer.asset.createViaURL({
// this is the IPFS CID, or Arweave transaction ID
name: decentralizedSource.id,
// the formatted IPFS CID or Arweave tx ID as a URL:
// ipfs://{CID} or ar://{CID}
url: decentralizedSource.url,
});
// ...continue to poll the created asset and use the decentralized identifier
// to get the playback info, and pass to `getSrc` to use with
const imported = await livepeer.playback.get(decentralizedSource.id);
const source = getSrc(imported.playbackInfo);
return source;
}
}
```
# Clip
Source: https://docs.livepeer.org/v1/sdks/react/player/Clip
The `ClipTrigger` component enables users to create clips from live Player content.
The `ClipTrigger` is designed to be used as a child of the `Player` component.
It interacts with the playback state to provide a user-friendly interface for creating media
clips, **based on the Unix timestamp from the current playback position**.
*Clipping is currently supported only for livestreams*.
## Features
* Automatically handles determining the current playback head in Unix time
* Compatible with the [create clip API](/api-reference/stream/create-clip)
* Keyboard hotkeys and adheres to [WAI-ARIA](https://w3c.github.io/aria/) design
patterns
* Conditional rendering if it is supported by the current media and is enabled
`ClipTrigger` will automatically handle determining the Unix timestamp for the
current playback position. The playback position is *not* the same as the
server livestream head, due to natural latency from server ingest to playback.
This is why Unix timestamps are required, and relative timestamps cannot be
used.
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
export default () => (
);
```
## Usage
`ClipTrigger` is a button that users can interact with to initiate the clip
creation process. It's displayed only if clipping functionality is enabled (by
passing a valid `clipLength` to the Root component).
**It should be wrapped in a LiveIndicator, since the "last n seconds" clipping
functionality is only supported on livestreams.**
## Props
The component accepts all props suitable for a button element, along with
specific props:
### `forceMount`
A boolean that, when set to true, ensures the component is always mounted. This
is particularly useful for controlling animations with external animation
libraries.
### `onClip`
A function that gets called when a clip is requested. It receives an object
containing the `playbackId`, `startTime`, and `endTime`, which can be used to
handle the clip creation process.
## Data Attributes
The `ClipTrigger` component assigns data attributes to its underlying element to
reflect the current state and user interaction capabilities.
### `data-livepeer-controls-clip-button`
Serves to identify the component's role.
### `data-visible`
Indicates the visibility status of the trigger, with `"true"` meaning it's
currently visible (i.e., clip functionality is enabled) and `"false"` denoting
it's not visible, useful for CSS-based animations.
# Controls
Source: https://docs.livepeer.org/v1/sdks/react/player/Controls
The `Controls` component provides an interactive container for all other media control elements such as `Play`, `Fullscreen`, etc.
`Controls` serves as the interactive layer for media control actions, dynamically displayed based on the media state, loading state, or presence of an error. It is designed to automatically show upon user interaction with the Container element and hides based on the `Root` component's `autohide` property.
By default, controls are shown during hover or interaction, mimicking the
behavior of standard media players.
## Features
* Automatic conditional rendering based on user interactions
* Click/touch to pause/play media
* Compatible with CSS animations for dynamic enter/exit animations
The visibility of `Controls` is managed automatically, relying on the
`autohide` property of the `Root` component to determine how long after a user
interaction to wait before hiding.
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
export default () => (
{/* Place interactive control elements here, like play/pause buttons, progress bars, etc. */}
);
```
## Props
### `forceMount`
Ensures the component is always in the DOM, useful for animation controls.
### `autoHide`
Defines the auto-hide delay in milliseconds after user interaction. Default is
3000ms. Set to 0 to disable auto-hide.
## Data Attributes
### `data-livepeer-controls`
Identifies the control component within the Player.
### `data-visible`
Indicates if the controls are visible (`"true"`) or not (`"false"`), useful for
CSS-based animations.
# Fullscreen
Source: https://docs.livepeer.org/v1/sdks/react/player/Fullscreen
The `FullscreenIndicator` and `FullscreenTrigger` components provide visual cues and interactive elements for fullscreen functionality.
## Features
* Automatic conditional rendering based on fullscreen status and browser API
availability, customizable with the `matcher` pattern
* Handles all browser APIs back to IE11, with special handling for iOS
* Compatible with CSS animations for dynamic enter/exit animations
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
export default () => (
);
```
## Props
### `FullscreenIndicator`
#### `forceMount`
A boolean that, when true, keeps the component mounted at all times, useful for
controlling animations with external libraries.
#### `matcher`
A prop to define the condition under which the `FullscreenIndicator` should be
visible. It can be a boolean directly matching the fullscreen state or a
function providing custom logic to determine visibility.
### `FullscreenIndicator`
#### `forceMount`
A boolean that, when true, keeps the component mounted at all times, useful for
controlling animations with external libraries.
#### `matcher`
A prop to define the condition under which the `FullscreenIndicator` should be
visible. It can be a boolean directly matching the fullscreen state or a
function providing custom logic to determine visibility.
## Data Attributes
### `FullscreenIndicator`
#### `data-livepeer-controls-fullscreen-indicator`
Indicates the component's role.
#### `data-fullscreen`
Shows the current fullscreen state (`"true"` or `"false"`).
#### `data-visible`
Reflects whether the indicator is currently visible (`"true"` or `"false"`).
This is often used for dynamically applying enter/exit CSS animations.
### `FullscreenTrigger`
#### `data-livepeer-controls-fullscreen-trigger`
Indicates the component's role.
#### `data-fullscreen-state`
Shows the current fullscreen state (`"true"` or `"false"`).
# Live
Source: https://docs.livepeer.org/v1/sdks/react/player/Live
The `LiveIndicator` component visually signals the live status of media playback.
`LiveIndicator` is designed to provide a clear, visual cue of the live status
of the media playback.
## Features
* Conditional rendering based on live playback status, customizable with the
`matcher` pattern
* Adheres to [WAI-ARIA](https://w3c.github.io/aria/) design patterns
* Compatible with CSS animations for dynamic enter/exit animations
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
export default () => (
);
```
## Props
### `forceMount`
Keeps the component always mounted, aiding in managing animations.
### `matcher`
Determines when the `LiveIndicator` is shown, accepting a boolean or a function
for customized visibility logic.
## Data Attributes
### `data-livepeer-live-indicator`
Designates the live indicator component within the Player.
### `data-live`
Denotes the live status (`"true"` for live, `"false"` for not live).
### `data-visible`
Signifies if the indicator is visible (`"true"`) or hidden (`"false"`), useful
for CSS-based animations.
# Loading
Source: https://docs.livepeer.org/v1/sdks/react/player/Loading
The `LoadingIndicator` component is a visual indicator of the loading state of the media.
The `Loading` component can be composed with any other elements. Typically it
is combined with Poster
## Features
* Conditional rendering based on the error state, customizable with the
`matcher` pattern
* Dynamic data attributes for custom styling based on the current error state
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
export default () => (
);
```
## Props
The component accepts all props suitable for a div element, in addition to the
following specific props:
### `forceMount`
A boolean value that, when set to true, ensures the component is always mounted.
This is particularly useful for managing animations with external animation
libraries.
### `matcher`
A prop intended to define the circumstances under which the `LoadingIndicator`
should be visible. It can be a direct boolean comparison with the loading state
or a function that provides custom logic for visibility determination.
## Data Attributes
### `data-livepeer-loading-indicator`
Serves to identify the component's role.
### `data-loading`
Displays the current loading state, `"true"` when media is loading and `"false"`
when it's not.
### `data-visible`
Indicates the visibility status of the indicator, with `"true"` meaning it's
currently visible and `"false"` denoting it's not.
This is often used for dynamically applying enter/exit CSS animations.
# Picture in Picture
Source: https://docs.livepeer.org/v1/sdks/react/player/PictureInPicture
The `PictureInPictureTrigger` component toggles the picture-in-picture mode.
## Features
* Automatic conditional rendering based on browser API availability,
customizable with the `matcher` pattern
* Supports both the [w3c](https://w3c.github.io/picture-in-picture/) standard
(which most modern browsers support), as well as the
[older Safari/iOS spec](https://developer.apple.com/documentation/webkitjs/adding_picture_in_picture_to_your_safari_media_controls)
(see the browsers which support Picture-in-Picture on
[caniuse](https://caniuse.com/picture-in-picture))
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
export default () => (
);
```
## Props
The component accepts all props suitable for a button element.
## Data Attributes
### `data-livepeer-controls-picture-in-picture-trigger`
Serves to identify the component's role.
### `data-picture-in-picture`
Indicates the current picture-in-picture state, `"true"` when the feature is
active and `"false"` otherwise.
### `data-visible`
Reflects the visibility status of the trigger, with `"true"` meaning it's
currently visible (i.e., picture-in-picture is supported and the media is not in
fullscreen mode) and `"false"` denoting it's not visible.
This is often used for dynamically applying enter/exit CSS animations.
# Play
Source: https://docs.livepeer.org/v1/sdks/react/player/Play
The `PlayPauseTrigger` component enables users to toggle playback and the `PlayingIndicator` provides a visual cue for the current playback state.
`PlayPauseTrigger` and `PlayingIndicator` integrate together to form the
typical play/pause interaction for media players. They do not have to be used
together and can combine with other components.
## Features
* Controls the playback state and conditionally renders based on playing status,
customizable with the `matcher` pattern
* Keyboard hotkeys and adheres to [WAI-ARIA](https://w3c.github.io/aria/) design
patterns
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
export default () => (
);
```
## Props
### `PlayPauseTrigger`
Accepts all props for a typical button element.
### `PlayingIndicator`
#### `forceMount`
Ensures the component is always mounted, beneficial for animation consistency.
#### `matcher`
Defines the condition under which the `PlayingIndicator` displays, using a
boolean or a custom function for tailored visibility logic.
## Data Attributes
### PlayPauseTrigger
#### `data-livepeer-play-pause-trigger`
Identifies the play/pause button within the Player.
#### `data-playing`
Shows the playback status (`"true"` for playing, `"false"` for paused).
#### `data-visible`
Signifies if the indicator is visible (`"true"`) or hidden (`"false"`), useful
for CSS-based animations and visibility adjustments.
### PlayingIndicator
#### `data-livepeer-playing-indicator`
Marks the playing status indicator component.
#### `data-playing`
Shows the playback status (`"true"` for playing, `"false"` for paused).
#### `data-visible`
Signifies if the indicator is visible (`"true"`) or hidden (`"false"`), useful
for CSS-based animations.
# Portal
Source: https://docs.livepeer.org/v1/sdks/react/player/Portal
The `Portal` component allows projection of content into different parts of the DOM.
The `Portal` component is a simple wrapper over
[@radix-ui/react-portal](https://www.radix-ui.com/primitives/docs/utilities/portal#portal).
It inherits all of the documentation for the component.
## Features
* Provides an easy way to portal controls out of the Root components
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
export default () => (
{/* Place portalled elements here, which can still
consume the React Context from the Root, but are
appended to the document */}
);
```
## Props
### `children`
React nodes that are to be rendered inside the portal.
### `container`
An optional prop specifying a container element where the portal's children
should be rendered. If not provided, the children are appended to the body of
the document by default.
# Poster
Source: https://docs.livepeer.org/v1/sdks/react/player/Poster
The `Poster` component displays a visual placeholder for media content prior to playback.
When used with Livepeer's playback info API, `getSrc` will automatically parse
any available thumbnail images in the JSON response and pass them to `Poster`.
The example above assumes that the playback info has a "Thumbnail (JPEG)"
source.
## Features
* Displays a preview image as a placeholder while media is loading
* Conditionally renders based on the availability of a thumbnail image
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
export default () => (
);
```
## Props
`Poster` accepts all typical HTML `img` props.
It is usually used alongside a `Player.Video` with poster set to `null`, so
that the default poster URL is not parsed and set on the HTML5 video element.
It can be composed with custom img renderers, like Next.js Image, with the
`asChild` prop, so you can customize the image loading to go through your
optimization pipeline.
### `forceMount`
Ensures consistent presence in the DOM, aiding in the smooth application of
animations.
### `src`
Specifies the URL for the poster image, allowing for a customized preview. If
not set, the component attempts to retrieve a poster from the media's context.
## Data Attributes
### `data-livepeer-poster`
Identifies the poster component within the Player.
### `data-visible`
Signifies if the poster is visible (`"true"`) or hidden (`"false"`), useful for
CSS-based animations.
# Playback Speed
Source: https://docs.livepeer.org/v1/sdks/react/player/RateSelect
The `RateSelect` and `RateSelectItem` components provide an interface for users to adjust the playback speed of the media.
All of the `RateSelect` components extend from
[`@radix-ui/react-select`](https://www.radix-ui.com/primitives/docs/components/select),
and inherits all of the documentation for those components.
## Features
* Composes a dropdown menu for selecting any playback speed, and handles syncing
with the underlying media element
* Keyboard navigation (with Radix) and adheres to
[WAI-ARIA](https://w3c.github.io/aria/) design patterns
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
export default () => (
);
```
## Props
### `RateSelect`
Takes all props of the
[Radix Select Root](https://www.radix-ui.com/primitives/docs/components/select)
component.
### `RateSelectItem`
Takes all props of the
[Radix Select Item](https://www.radix-ui.com/primitives/docs/components/select)
component.
#### `value`
Required - denote the playback speed value as a number.
## Data Attributes
### `RateSelect`
#### `data-livepeer-rate-select`
Identifies the rate select component within the Player.
#### `data-rate`
Indicates the selected playback speed value.
### `RateSelectItem`
#### `data-livepeer-rate-select-item`
Identifies the rate select item within the Player.
# Seek
Source: https://docs.livepeer.org/v1/sdks/react/player/Seek
The `Seek` and `SeekBuffer` components provide visual elements for seeking through media and displaying buffer status.
All of the `Seek` components extend from
[`@radix-ui/react-slider`](https://www.radix-ui.com/primitives/docs/components/slider),
and inherits all of the documentation for those components.
## Features
* Composes a slider for the current progress and buffer, and handles syncing
with the underlying media element
* Keyboard navigation (with Radix) and adheres to
[WAI-ARIA](https://w3c.github.io/aria/) design patterns
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
export default () => (
);
```
## Props
### `Seek`
The component accepts all props for a
[Radix Slider](https://www.radix-ui.com/primitives/docs/components/slider)
element.
#### `forceMount`
A boolean that, when set to true, ensures the component is always mounted. This
is particularly useful for managing animations with external animation
libraries.
### `SeekBuffer`
The component accepts all props for a
[Radix Track](https://www.radix-ui.com/primitives/docs/components/slider)
element.
It is usually not used as the Slider Track (since the seekable media isn't
constrained by the amount buffered), but can be used for it, depending on the
use-case.
## Data Attributes
Both components assign several data attributes to their underlying elements to
reflect the current state, user interactions, and visibility conditions.
### `Seek`
#### `data-livepeer-controls-seek`
Serves to identify the component's role within the Player.
#### `data-duration`
Indicates the total duration of the media.
#### `data-progress`
Shows the current progress as a percentage of the total duration.
#### `data-live`
Indicates if the current media is live, `"true"` for live and `"false"` for
non-live media.
#### `data-buffered`
Shows the portion of the media that has been buffered.
#### `data-visible`
Reflects the visibility status of the slider, with `"true"` meaning it's
currently visible (i.e., the media is not live) and `"false"` denoting it's not
visible.
This is often used for dynamically applying enter/exit CSS animations.
### `SeekBuffer`
##### `data-livepeer-controls-seek-buffer`
Identifies the component's role within the Seek slider.
##### `data-buffered`
Shows the portion of the media that has been buffered.
# Time
Source: https://docs.livepeer.org/v1/sdks/react/player/Time
The `Time` component provides a display of the current time, total duration, and progress of the media.
## Features
* Automatic display of friendly time from state store
* Handles live and static assets (e.g. no fixed duration vs fixed duration)
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
export default () => (
);
```
## Props
The component accepts all props suitable for a span element, except for
`children`, since the formatted time will be rendered as the only child.
## Data Attributes
### `data-livepeer-controls-time`
Serves to identify the component's role in the playback interface.
### `data-duration`
Displays the total duration of the media.
### `data-progress`
Indicates the current progress of the media playback, usually represented as a
percentage or time elapsed.
### `data-live`
Shows the live state of the media, `"true"` for live streams and `"false"` for
pre-recorded content.
# Video Quality
Source: https://docs.livepeer.org/v1/sdks/react/player/VideoQualitySelect
The `VideoQualitySelect` and `VideoQualitySelectItem` components allow viewers to select the desired video quality during media playback.
All of the `VideoQualitySelect` components extend from
[`@radix-ui/react-select`](https://www.radix-ui.com/primitives/docs/components/select),
and inherits all of the documentation for those components.
## Features
* Synchronizes state with the HTML5 video element
* Adheres to [WAI-ARIA](https://w3c.github.io/aria/) design patterns
* Persists to `localStorage` by default (with storage overrides customizable in
`Root`)
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
export default () => (
);
```
## Props
### `VideoQualitySelect`
Takes all props of the
[Radix Select Root](https://www.radix-ui.com/primitives/docs/components/select)
component.
### `VideoQualitySelectItem`
Takes all props of the
[Radix Select Item](https://www.radix-ui.com/primitives/docs/components/select)
component.
#### `value`
The `VideoQuality` enum value representing the video quality that the item
corresponds to. This must be provided to ensure correct selection behavior.
This can be of the type:
`"auto" | "1080p" | "720p" | "480p" | "360p" | "240p" | "144p"`
## Data Attributes
### `VideoQualitySelect`
#### `data-livepeer-quality-select`
Serves to identify the component's role within the Player.
#### `data-video-quality`
Indicates the current video quality selection, matching the value of the
selected `VideoQualitySelectItem`.
This can be of the type:
`"auto" | "1080p" | "720p" | "480p" | "360p" | "240p" | "144p"`
### `VideoQualitySelectItem`
#### `data-livepeer-quality-select-item`
Serves to identify the component's role within the Player.
# Volume
Source: https://docs.livepeer.org/v1/sdks/react/player/Volume
The `Volume`, `VolumeIndicator`, and `MuteTrigger` components provide interactive controls for the volume level.
All of the `Volume` components extend from
[`@radix-ui/react-slider`](https://www.radix-ui.com/primitives/docs/components/slider),
and inherits all of the documentation for those components.
## Features
* Conditional rendering based on volume status, customizable with the `matcher`
pattern
* Keyboard shortcuts and adheres to [WAI-ARIA](https://w3c.github.io/aria/)
design patterns
* Compatible with CSS animations for dynamic enter/exit animations
* Persists to `localStorage` by default (with storage overrides customizable in
`Root`)
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
export default () => (
);
```
## Props
### MuteTrigger
Accepts all props for a typical button element.
### VolumeIndicator
#### `forceMount`
A boolean that, when set to true, ensures the component is always mounted. This
is particularly useful for managing animations with external animation
libraries.
#### `matcher`
A prop intended to define the circumstances under which the `VolumeIndicator`
should be visible. It can be a boolean matching the mute state or a function
that provides custom logic for visibility determination based on the volume
level.
### Volume
#### `forceMount`
Keeps the component always mounted, aiding in managing animations.
## Data Attributes
### MuteTrigger
#### `data-livepeer-mute-trigger`
Identifies the mute toggle component within the media player setup.
#### `data-muted`
Shows whether the audio is currently muted (`"true"`) or active (`"false"`),
assisting in the visual representation and scripting based on the mute state.
### VolumeIndicator
#### `data-livepeer-controls-volume-indicator`
Identifies the component's role within the Player.
#### `data-livepeer-muted`
Indicates the mute state, `"true"` if muted and `"false"` otherwise.
#### `data-livepeer-volume`
Shows the current volume as a percentage, e.g., `"50"` for 50% volume.
#### `data-visible`
Indicates the visibility status of the indicator, with `"true"` meaning it's
currently visible based on the `matcher` or mute state and `"false"` denoting
it's not visible.
This is often used for dynamically applying enter/exit CSS animations.
### Volume
#### `data-livepeer-controls-volume`
Serves to identify the component's role within the Player.
#### `data-livepeer-muted`
Indicates the mute state, `"true"` if muted and `"false"` otherwise.
#### `data-livepeer-volume`
Shows the current volume as a percentage, e.g., `"50"` for 50% volume.
#### `data-visible`
Reflects the visibility status of the slider, with `"true"` meaning it's
currently visible (i.e., volume change is supported) and `"false"` denoting it's
not visible.
# getSrc
Source: https://docs.livepeer.org/v1/sdks/react/player/get-src
`getSrc` is a utility function for parsing various types of playback information and converting them into a standardized format suitable for the Player.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { getSrc } from "@livepeer/react/external";
import * as Player from "@livepeer/react/player";
// An example response from the livepeer playback info API endpoint
const vodSource = {
type: "vod",
meta: {
playbackPolicy: null,
source: [
{
hrn: "HLS (TS)",
type: "html5/application/vnd.apple.mpegurl",
url: "https://lp-playback.com/hls/f5eese9wwl88k4g8/index.m3u8",
},
],
},
};
// This is either an array of `Src` or null,
// and can be passed into the Player.Root `src`
const src = getSrc(vodSource);
export default () => (
{/* All child components. */}
);
```
#### Features
* Supports inputs like Livepeer playback info, Cloudflare stream data, Mux URLs,
arrays of strings, and single strings
* Transforms into `Src[]` which contains essential playback information, along
with supportive metadata like thumbnails and VTT files.
### Functionality
#### Input Types
The function can process the following input types:
* `LivepeerPlaybackInfo`: Extracts the 'source' array from its 'meta' property
from the playback info endpoint.
* `LivepeerSource` or `LivepeerSource[]`: Uses the source object(s) directly.
* `CloudflareStreamData`: Retrieves the stream data from a Cloudflare stream
data object.
* `string[]`: Assumes each string as a URL and creates an array of Source
objects.
* `string`: Assumes the string is a URL and creates a single Source object.
#### Output Format
The output is an array of `Src` objects or `null` if the input is invalid or
empty.
# useMediaContext
Source: https://docs.livepeer.org/v1/sdks/react/player/useMediaContext
The `useMediaContext` hook lets you build custom components which interact directly with the media state store.
The `useStore` hook is from
[`zustand`](https://github.com/pmndrs/zustand?tab=readme-ov-file#using-zustand-without-react),
and inherits all of the documentation for Zustand stores.
## Features
* Flexible interaction with the player state store
* Based on Zustand's `useStore` hooks
## Anatomy
Import the components and piece the parts together.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import * as Player from "@livepeer/react/player";
import { useMediaContext, useStore } from "@livepeer/react/player";
export default () => (
{/** The `useMediaContext` hook can be used in any component,
as long as it's inside the Player.Root React Context provider */}
);
function CustomComponent({ __scopeMedia }: MediaScopedProps) {
const context = useMediaContext("CustomComponent", __scopeMedia);
const { currentSource } = useStore(context.store, ({ currentSource }) => ({
currentSource,
}));
return currentSource?.type ?? null;
}
```
## State
The `useMediaContext` hook returns a Zustand store, which contains the
`PlayerState`.
### `aria`
The ARIA text for the current state, providing accessible descriptions for media
control actions.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
type AriaText = {
progress: string;
pictureInPicture: string;
fullscreen: string;
playPause: string;
clip: string | null;
time: string;
};
aria: AriaText;
```
### `buffered`
Current buffered end time for the media in seconds.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
buffered: number;
```
### `bufferedPercent`
Current buffered percent of the media, from 0 to 1.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
bufferedPercent: number;
```
### `canPlay`
Indicates if the media has loaded sufficiently and can be played.
### `currentSource`
The current source that is playing.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
type Src =
| AudioSrc
| HlsSrc
| VideoSrc
| Base64Src
| WebRTCSrc
| ImageSrc
| VideoTextTrackSrc;
currentSource: Src | null;
```
### `currentUrl`
The final playback URL for the media that is playing, after any redirects.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
currentUrl: string | null;
```
### `duration`
Current total duration of the media in seconds.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
duration: number;
```
### `error`
If the media has experienced an error, this property provides details.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
type PlaybackError = {
type: "offline" | "access-control" | "fallback" | "permissions" | "unknown";
message: string;
};
error: PlaybackError | null;
```
### `errorCount`
The number of consecutive errors that have occurred during the media playback,
without resolution.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
errorCount: number;
```
### `stalled`
Indicates if the media playback is currently stalled.
### `fullscreen`
Indicates if the media is being played in fullscreen mode.
### `hasPlayed`
Indicates if the media has been played yet.
### `hidden`
Indicates if all controls are currently hidden.
### `live`
Indicates if the content is live media.
### `loading`
Indicates if the media is currently loading.
### `mounted`
Indicates if the video element is mounted on the DOM. This is used for
initialization logic.
### `playbackRate`
The current playback rate for the media. Defaults to 1. `constant` means playing
WebRTC playback at a constant pace and not speeding up.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
type PlaybackRate = number | "constant";
playbackRate: PlaybackRate;
```
### `pictureInPicture`
Indicates if the media is in picture in picture mode.
### `poster`
The poster image URL for the media. Any thumbnails are automatically parsed from
the input `Src[]`.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
poster: string | null;
```
### `progress`
Current progress of the media in seconds.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
progress: number;
```
### `playing`
Indicates if the media is currently trying to play or paused.
### `sortedSources`
The sorted sources that were passed into the Player. These are the playback
sources which will be tried, in order (e.g. WebRTC with a fallback to HLS).
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
sortedSources: Src[] | string | null;
```
### `volume`
Current volume of the media. 0 if it is muted.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
volume: number;
```
### `waiting`
Indicates if the media is currently waiting for data.
### `videoQuality`
The quality of the video playback.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
type VideoQuality =
| "1080p"
| "720p"
| "480p"
| "360p"
| "240p"
| "144p"
| "auto";
videoQuality: VideoQuality;
```
### `ended`
Indicates if the media playback has ended.
### `__controlsFunctions`
An object containing functions to manipulate the media's state, such as toggling
play/pause, seeking, and changing volume.
These functions are internal - please refer to the UI Kit source code before
interacting with these functions.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
__controlsFunctions: {
setHidden: (hidden: boolean) => void;
onCanPlay: () => void;
onDurationChange: (duration: number) => void;
onEnded: () => void;
onError: (error: Error | null) => void;
onFinalUrl: (url: string | null) => void;
onLoading: () => void;
onPause: () => void;
onPlay: () => void;
onProgress: (time: number) => void;
onStalled: () => void;
onWaiting: () => void;
requestClip: () => void;
requestMeasure: () => void;
requestSeek: (time: number) => void;
requestSeekBack: (difference?: number) => void;
requestSeekDiff: (difference: number) => void;
requestSeekForward: (difference?: number) => void;
requestToggleFullscreen: () => void;
requestToggleMute: () => void;
requestTogglePictureInPicture: () => void;
requestVolume: (volume: number) => void;
setAutohide: (autohide: number) => void;
setFullscreen: (fullscreen: boolean) => void;
setHlsConfig: (hlsConfig: any) => void;
setLive: (live: boolean) => void;
setMounted: () => void;
setPictureInPicture: (pictureInPicture: boolean) => void;
setPlaybackRate: (rate: number | string) => void;
setPoster: (poster: string | null) => void;
setVideoQuality: (videoQuality: VideoQuality) => void;
setSize: (size: Partial) => void;
setVolume: (volume: number) => void;
setWebsocketMetadata: (metadata: Metadata) => void;
togglePlay: (force?: boolean) => void;
updateBuffered: (buffered: number) => void;
updateLastInteraction: () => void;
updatePlaybackOffsetMs: (offset: number) => void;
};
```
### `__device`
Information about the device's capabilities and support for media features. This
is an internal object used by Player/Broadcast, but can be used for detecting
device capabilities.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
type DeviceInformation = {
version: string;
isMobile: boolean;
isIos: boolean;
isAndroid: boolean;
userAgent: string;
screenWidth: number | null;
/** If the media supports changing the volume */
isVolumeChangeSupported: boolean;
/** If the media supports PiP */
isPictureInPictureSupported: boolean;
/** If the media supports fullscreen */
isFullscreenSupported: boolean;
/** If the media supports HLS playback */
isHlsSupported: boolean;
/** If the media supports WebRTC */
isWebRTCSupported: boolean;
};
__device: DeviceInformation;
```
### `__controls`
Represents the state of various media control actions, such as play/pause and
fullscreen changes. This is an internal object used by Player/Broadcast.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
__controls: ControlsState;
```
### `__initialProps`
The initial properties passed into the media component. This is an internal
object used by Player/Broadcast.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
__initialProps: InitialProps;
```
### `__metadata`
Metadata related to the media, such as buffer window and frame rate. This is an
internal object used by Player/Broadcast.
```tsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
type Metadata = {
bframes?: number;
bufferWindow?: number;
};
__metadata: Metadata | null;
```
# Delete an asset
Source: https://docs.livepeer.org/v1/api-reference/asset/delete
DELETE /asset/{assetId}
# Retrieve an asset
Source: https://docs.livepeer.org/v1/api-reference/asset/get
GET /asset/{assetId}
# Retrieve assets
Source: https://docs.livepeer.org/v1/api-reference/asset/get-all
GET /asset
# Overview
Source: https://docs.livepeer.org/v1/api-reference/asset/overview
The Assets API is used to create, retrieve, update, delete assets object from pipeline.
### Asset object
This is a unique identifier for the asset.
Type of the asset. This can be either 'video' or 'audio'.
Used to form playback URL and storage folder.
Whether to generate MP4s for the asset.
Attach Livepeer Studio C2PA Attestation in the output mp4 video.
URL for HLS playback.
URL to manually download the asset if desired.
Reference to the playback-policy schema.
Source of the asset, which can be URL, recording, directUpload, or clip.
Reference to the creator-id schema.
Information about the storage of the asset, particularly on IPFS.
Status of the asset, including its phase, update time, and any error message.
Name of the asset. This is not necessarily the filename, can be a custom name
or title.
Timestamp (in milliseconds) at which asset was created.
Size of the asset in bytes.
Hash of the asset.
Video metadata including format, duration, bitrate, and tracks information.
```json Response theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"id": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"type": "video",
"playbackId": "eaw4nk06ts2d0mzb",
"staticMp4": "boolean",
"c2pa": "boolean",
"playbackUrl": "https://livepeercdn.com/asset/ea03f37e-f861-4cdd-b495-0e60b6d753ad/index.m3u8",
"downloadUrl": "https://livepeercdn.com/asset/eaw4nk06ts2d0mzb/video",
"playbackPolicy": {
"type": "public",
"webhookId": "3e02c844-d364-4d48-b401-24b2773b5d6c",
"webhookContext": {
"foo": "bar"
}
},
"source": {
"type": "url",
"url": "https://example.com/video.mp4",
"gatewayUrl": "https://example.com/video.mp4"
},
"creatorId": "object",
"storage": {
"ipfs": {
"spec": {
"nftMetadataTemplate": "file",
"nftMetadata": {
"name": "My NFT",
"description": "My NFT description"
}
}
}
},
"status": {
"phase": "ready",
"updatedAt": 1587667174725,
"progress": 100
},
"name": "filename.mp4",
"createdAt": 1587667174725,
"size": 84934509,
"hash": [
{
"hash": "9b560b28b85378a5004117539196ab24e21bbd75b0e9eb1a8bc7c5fd80dc5b57",
"algorithm": "sha256"
}
],
"videoSpec": {
"format": "mp4",
"duration": 23.8328,
"bitrate": 1000000,
"tracks": [
{
"type": "video",
"codec": "h264",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"width": 1920,
"height": 1080,
"pixelFormat": "yuv420p",
"fps": 30
},
{
"type": "audio",
"codec": "aac",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"channels": 2,
"sampleRate": 44100,
"bitDepth": 16
}
]
}
}
```
# Update an asset
Source: https://docs.livepeer.org/v1/api-reference/asset/update
PATCH /asset/{assetId}
# Upload an asset
Source: https://docs.livepeer.org/v1/api-reference/asset/upload
POST /asset/request-upload
To upload an asset, your first need to request for a direct upload URL
and only then actually upload the contents of the asset.
\
\
Once you created a upload link, you have 2 options, resumable or direct
upload. For a more reliable experience, you should use resumable uploads
which will work better for users with unreliable or slow network
connections. If you want a simpler implementation though, you should
just use a direct upload.
## Direct Upload
For a direct upload, make a PUT request to the URL received in the url
field of the response above, with the raw video file as the request
body. response above:
## Resumable Upload
Livepeer supports resumable uploads via Tus. This section provides a
simple example of how to use tus-js-client to upload a video file.
\
\
From the previous section, we generated a URL to upload a video file to
Livepeer on POST /api/asset/request-upload. You should use the
tusEndpoint field of the response to upload the video file and track the
progress:
```
# This assumes there is an `input` element of `type="file"` with id
`fileInput` in the HTML
const input = document.getElementById('fileInput');
const file = input.files[0];
const upload = new tus.Upload(file, {
endpoint: tusEndpoint, // URL from `tusEndpoint` field in the
`/request-upload` response
metadata: {
filename,
filetype: 'video/mp4',
},
uploadSize: file.size,
onError(err) {
console.error('Error uploading file:', err);
},
onProgress(bytesUploaded, bytesTotal) {
const percentage = ((bytesUploaded / bytesTotal) * 100).toFixed(2);
console.log('Uploaded ' + percentage + '%');
},
onSuccess() {
console.log('Upload finished:', upload.url);
},
});
const previousUploads = await upload.findPreviousUploads();
if (previousUploads.length > 0) {
upload.resumeFromPreviousUpload(previousUploads[0]);
}
upload.start();
```
> Note: If you are using tus from node.js, you need to add a custom URL
storage to enable resuming from previous uploads. On the browser, this
is enabled by default using local storage. In node.js, add urlStorage:
new tus.FileUrlStorage("path/to/tmp/file"), to the UploadFile object
definition above.
# Upload asset via URL
Source: https://docs.livepeer.org/v1/api-reference/asset/upload-via-url
POST /asset/upload/url
# Audio To Text
Source: https://docs.livepeer.org/v1/api-reference/generate/audio-to-text
POST /api/beta/generate/audio-to-text
# Image To Image
Source: https://docs.livepeer.org/v1/api-reference/generate/image-to-image
POST /api/beta/generate/image-to-image
# Image To Video
Source: https://docs.livepeer.org/v1/api-reference/generate/image-to-video
POST /api/beta/generate/image-to-video
# LLM
Source: https://docs.livepeer.org/v1/api-reference/generate/llm
## Overview
The `llm` pipeline provides an OpenAI-compatible interface for text generation,
designed to integrate seamlessly into media workflows.
## Models
The `llm` pipeline supports **any Hugging Face-compatible LLM model**. Since
models evolve quickly, the set of warm (preloaded) models on Orchestrators
changes regularly.
To see which models are currently available, check the
[Network Capabilities dashboard](https://tools.livepeer.cloud/ai/network-capabilities).\
At the time of writing, the most commonly available model is
[meta-llama/Meta-Llama-3.1-8B-Instruct](https://huggingface.co/meta-llama/Llama-3.1-8B-Instruct).
For faster responses with different
[LLM](https://huggingface.co/models?pipeline_tag=text-generation) diffusion
models, ask Orchestrators to load it on their GPU via the `ai-video` channel
in [Discord Server](https://discord.gg/livepeer).
## Basic Usage Instructions
For a detailed understanding of the `llm` endpoint and to experiment with the
API, see the [Livepeer AI API Reference](/ai/api-reference/llm).
To generate text with the `llm` pipeline, send a `POST` request to the Gateway's
`llm` API endpoint:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
curl -X POST "https:///llm" \
-H "Authorization: Bearer " \
-H "Content-Type: application/json" \
-d '{
"model": "meta-llama/Meta-Llama-3.1-8B-Instruct",
"messages": [
{ "role": "user", "content": "Tell a robot story." }
]
}'
```
In this command:
* `` should be replaced with your AI Gateway's IP address.
* `` should be replaced with your API token.
* `model` is the LLM model to use for generation.
* `messages` is the conversation or prompt input for the model.
For additional optional parameters such as `temperature`, `max_tokens`, or
`stream`, refer to the [Livepeer AI API Reference](/ai/api-reference/llm).
After execution, the Orchestrator processes the request and returns the response
to the Gateway:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"id": "chatcmpl-abc123",
"model": "meta-llama/Meta-Llama-3.1-8B-Instruct",
"choices": [
{
"message": {
"role": "assistant",
"content": "Once upon a time, in a gleaming city of circuits..."
}
}
]
}
```
By default, responses are returned as a single JSON object. To stream output
token-by-token using **Server-Sent Events (SSE)**, set `"stream": true` in the
request body.
## Orchestrator Configuration
To configure your Orchestrator to serve the `llm` pipeline, refer to the
[Orchestrator Configuration](/ai/orchestrators/get-started) guide.
### Tuning Environment Variables
The `llm` pipeline supports several environment variables that can be adjusted
to optimize performance based on your hardware and workload. These are
particularly helpful for managing memory usage and parallelism when running
large models.
Enables 8-bit quantization using `bitsandbytes` for lower memory usage. Set to
`true` to enable. Defaults to `false`.
Number of pipeline parallel stages. Should not exceed the number of model
layers. Defaults to `1`.
Number of tensor parallel units. Must divide evenly into the number of
attention heads in the model. Defaults to `1`.
Maximum number of tokens per input sequence. Defaults to `8192`.
Maximum number of tokens processed in a single batch. Should be greater than
or equal to `MAX_MODEL_LEN`. Defaults to `8192`.
Maximum number of sequences processed per batch. Defaults to `128`.
Target GPU memory utilization as a float between `0` and `1`. Higher values
make fuller use of GPU memory. Defaults to `0.97`.
### System Requirements
The following system requirements are recommended for optimal performance:
* [NVIDIA GPU](https://developer.nvidia.com/cuda-gpus) with **at least 16GB** of
VRAM.
## Recommended Pipeline Pricing
We are planning to simplify the pricing in the future so orchestrators can set
one AI price per compute unit and have the system automatically scale based on
the model's compute requirements.
The `/llm` pipeline is currently priced based on the **maximum output tokens**
specified in the request — not actual usage — due to current payment system
limitations. We're actively working to support usage-based pricing to better
align with industry standards.
The LLM pricing landscape is highly competitive and rapidly evolving.
Orchestrators should set prices based on their infrastructure costs and
[market positioning](https://llmpricecheck.com/). As a reference, inference on
`llama-3-8b-instruct` is currently around `0.08 USD` per 1 million **output
tokens**.
## API Reference
Explore the `llm` endpoint and experiment with the API in the Livepeer AI API
Reference.
# Overview
Source: https://docs.livepeer.org/v1/api-reference/generate/overview
The Generate API is used to run generative AI models.
These APIs implement the [Livepeer AI Gateway API spec](/ai/api-reference) and
are served under the Studio platform suite. They are prefixed with
`/api/beta/generate` and are used to run AI models to generate content.
# Segment Anything 2
Source: https://docs.livepeer.org/v1/api-reference/generate/segment-anything-2
POST /api/beta/generate/segment-anything-2
# Text To Image
Source: https://docs.livepeer.org/v1/api-reference/generate/text-to-image
POST /api/beta/generate/text-to-image
# Upscale
Source: https://docs.livepeer.org/v1/api-reference/generate/upscale
POST /api/beta/generate/upscale
# Create a multistream
Source: https://docs.livepeer.org/v1/api-reference/multistream/create
POST /multistream/target
# Delete a multistream
Source: https://docs.livepeer.org/v1/api-reference/multistream/delete
DELETE /multistream/target/{id}
Make sure to remove any references to the target on existing
streams before actually deleting it from the API.
# Retrieve a multistream
Source: https://docs.livepeer.org/v1/api-reference/multistream/get
GET /multistream/target/{id}
# Retrieve all multistreams
Source: https://docs.livepeer.org/v1/api-reference/multistream/get-all
GET /multistream/target
# Overview
Source: https://docs.livepeer.org/v1/api-reference/multistream/overview
The Multistream target API is used to create, retrieve, update, delete multi-stream targets object from pipeline.
### Multistream target object
Unique identifier for the multistream target.
Name of the multistream target.
Livepeer-compatible multistream target URL (RTMP(S) or SRT). This URL is used
for streaming to the target platform.
Indicates if this multistream target is disabled. If true, it will not be used
for pushing even if configured in a stream object.
Timestamp (in milliseconds) at which the multistream target object was
created.
```json Response theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"id": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"name": "My Multistream Target",
"url": "rtmps://live.my-service.tv/channel/secretKey",
"disabled": "boolean",
"createdAt": 1587667174725
}
```
# Update a multistream
Source: https://docs.livepeer.org/v1/api-reference/multistream/update
PATCH /multistream/target/{id}
# Authentication
Source: https://docs.livepeer.org/v1/api-reference/overview/authentication
Learn more about Livepeer's API.
Livepeer API uses API keys to verify and authorize requests. You can manage and
review your API keys through Livepeer Studio. You need to pass your API key in
the `Authorization` header with a `Bearer` prefix while sending a request.
```
Bearer YOUR_API_KEY
```
It's important to note that your API keys come with significant privileges, so
it's essential to keep them safe and secure! Refrain from sharing your secret
API keys in GitHub or other publicly accessible places.
By default, API keys can only be used from a backend server. This is to ensure
maximum security and prevent that you accidentally expose your account by
including the secret API key in a public web page.
### CORS-Enabled Keys
Please read the below documentation in its entirety before using CORS-enabled
API keys. **There is a different security model for CORS keys.**
Studio supports the creation of CORS-enabled API keys. This is a special option
when generating an API key which allows a webpage to make requests **directly**
to Studio, as opposed to coming from your backend.
#### Security with CORS Keys
**The security model is different for CORS-enabled API keys.** Since any user
has access to these keys, the IDs of assets and streams **must** be kept secret
from anyone who should not have admin control over them. For instance, a viewer
should only have access to the playback ID, since knowing the asset ID (together
with the CORS-enabled API key, which is embedded in the webpage) allows them to
make changes to the asset.
This is the same for streams - if a user has access to a stream ID alongside the
CORS API key, they can modify the stream or view the stream key. If a viewer had
access to the stream ID + CORS API key, they could hijack the stream. **A
`playbackId` should be exposed to the viewer only.**
# Introduction
Source: https://docs.livepeer.org/v1/api-reference/overview/introduction
Learn more about Livepeer's API.
Welcome to the Livepeer API reference docs! Here you'll find all the endpoints
exposed on the standard Livepeer API, learn how to use them and what they
return.
The Livepeer API is organized around REST, has predictable resource-oriented
URLs, accepts JSON request bodies, returns JSON-encoded responses, and uses
standard HTTP response codes, authentication, and verbs.
# Retrieve Playback Info
Source: https://docs.livepeer.org/v1/api-reference/playback/get
GET /playback/{id}
# Overview
Source: https://docs.livepeer.org/v1/api-reference/playback/overview
The Playback API is used to retrieve playback object from pipeline.
### Playback Object
Type of playback, such as live, vod, or recording.
Metadata for the playback information. This includes details about the source,
playback policy, and attestation.
Indicates if the playback is live (1) or not (0).
Reference to the playback-policy schema.
Array of source objects detailing the playback sources. Each source includes
HRN, type, URL, size, width, height, and bitrate.
Human-readable name (HRN) for the playback source format.
MIME type of the playback source.
URL for the playback source.
Size of the playback source file.
Width of the video in pixels.
Height of the video in pixels.
Bitrate of the playback source.
Reference to the attestation schema.
```json Response theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"type": "vod",
"meta": {
"live": 0,
"playbackPolicy": {
"type": "public",
"webhookId": "3e02c844-d364-4d48-b401-24b2773b5d6c",
"webhookContext": {
"foo": "bar"
}
},
"source": [
{
"hrn": "MP4",
"type": "html5/video/mp4",
"url": "https://asset-cdn.lp-playback.studio/hls/1bde4o2i6xycudoy/static360p0.mp4",
"size": 494778,
"width": 204,
"height": 360,
"bitrate": 449890
}
],
"attestation": {
"id": "5b9e63bb-6fd0-4bea-aff2-cc5d4eb9cad0",
"primaryType": "VideoAttestation",
"domain": {
"name": "Verifiable Video",
"version": "1"
},
"message": {
"video": "string",
"attestations": [
{
"role": "string",
"address": "string"
}
],
"signer": "string",
"timestamp": "number"
},
"signature": "string",
"createdAt": 1587667174725,
"signatureType": "eip712",
"storage": {
"ipfs": {
"cid": "bafybeihoqtemwitqajy6d654tmghqqvxmzgblddj2egst6yilplr5num6u",
"url": "ipfs://bafybeihoqtemwitqajy6d654tmghqqvxmzgblddj2egst6yilplr5num6u",
"gatewayUrl": "https://ipfs.io",
"updatedAt": 1587667174725
},
"status": {
"phase": "ready",
"progress": 0.5,
"errorMessage": "Failed to export to IPFS",
"tasks": {
"pending": "string",
"last": "string",
"failed": "string"
}
}
}
}
}
}
```
# Retrieve a session
Source: https://docs.livepeer.org/v1/api-reference/session/get
GET /session/{id}
# Retrieve all sessions
Source: https://docs.livepeer.org/v1/api-reference/session/get-all
GET /session
# Retrieve clips of a session
Source: https://docs.livepeer.org/v1/api-reference/session/get-clip
GET /session/{id}/clips
# Retrieve recorded sessions
Source: https://docs.livepeer.org/v1/api-reference/session/get-recording
GET /stream/{parentId}/sessions
# Overview
Source: https://docs.livepeer.org/v1/api-reference/session/overview
The Sessions API is used to retrieve sessions object from pipeline.
### Session Object
Unique identifier for the session.
Name of the session.
Timestamp of the last activity in the session.
Number of source segments in the session.
Number of transcoded segments in the session.
Duration of all the source segments in seconds.
Duration of all the transcoded segments in seconds.
Total bytes of source segments.
Total bytes of transcoded segments.
Rate at which sourceBytes increases (bytes/second).
Rate at which transcodedBytes increases (bytes/second).
Reference to the stream-health-payload schema for health status.
Reference to the stream-health-payload schema for human-readable issues.
Timestamp (in milliseconds) at which the session was created.
Identifier of the parent stream object.
Indicates whether the stream should be recorded.
Status of the recording process of this stream session.
URL for accessing the recording of this stream session.
URL for the stream session recording packaged in an MP4 format.
Identifier used to form the playback URL.
Array of profiles detailing various streaming qualities.
```json Response theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"id": "de7818e7-610a-4057-8f6f-b785dc1e6f88",
"name": "test_session",
"lastSeen": 1587667174725,
"sourceSegments": 1,
"transcodedSegments": 2,
"sourceSegmentsDuration": 1,
"transcodedSegmentsDuration": 2,
"sourceBytes": 1,
"transcodedBytes": 2,
"ingestRate": 1,
"outgoingRate": 2,
"isHealthy": true,
"issues": [
"Buffer underflow",
"Network congestion"
],
"createdAt": 1587667174725,
"parentId": "de7818e7-610a-4057-8f6f-b785dc1e6f88",
"record": "boolean",
"recordingStatus": "waiting",
"recordingUrl": "https://lp-playback.com/hls/29eb9byolvwdbkue/index.m3u8",
"mp4Url": "https://lp-playback.com/hls/29eb9byolvwdqkue/720.mp4",
"playbackId": "eaw4nk06ts2d0mzb",
"profiles": [
{
"name": "720p",
"width": 1280,
"height": 720,
"bitrate": 3000,
"fps": 30
}
]
}
```
# Create a signing key
Source: https://docs.livepeer.org/v1/api-reference/signing-key/create
POST /access-control/signing-key
The publicKey is a representation of the public key, encoded as base 64 and is passed as a string, and the privateKey is displayed only on creation. This is the only moment where the client can save the private key, otherwise it will be lost. Remember to decode your string when signing JWTs.
Up to 10 signing keys can be generated, after that you must delete at least one signing key to create a new one.
# Delete a signing key
Source: https://docs.livepeer.org/v1/api-reference/signing-key/delete
DELETE /access-control/signing-key/{keyId}
# Retrieve a signing key
Source: https://docs.livepeer.org/v1/api-reference/signing-key/get
GET /access-control/signing-key/{keyId}
# Retrieve signing keys
Source: https://docs.livepeer.org/v1/api-reference/signing-key/get-all
GET /access-control/signing-key
# Overview
Source: https://docs.livepeer.org/v1/api-reference/signing-key/overview
The Access control API is used to create, retrieve, update, delete signing keys object from pipeline.
### Signing key Object
Unique identifier for the signing key.
Name of the signing key.
Timestamp (in milliseconds) at which the signing key was created.
Timestamp of the last activity with the signing key.
The public key portion of the signing key.
Indicates whether the signing key is disabled.
The private key portion of the signing key.
```json Response theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"id": "78df0075-b5f3-4683-a618-1086faca35dc",
"name": "My signing key",
"createdAt": 1587667174725,
"lastSeen": 1587667174725,
"publicKey": "LS0tLS1CRUdJTiBQUklWQVRFIBtFWS0tLS0tCk1JR0hBZ0VBTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEJHMHdhd0lCQVFRZ1RDRzhRWDZKdkR0eC95ZDMKdlpkUHJKR25LcjhiWHRsdXNIL2FOYW5XdHEraFJBTkNBQVE0QnZ6ODI2L2lDaXV1U0NiZVkwc3FmOXljYWh0OApDRFYyUFF2bDFVM1FLSVRBcWRpaktLa0FSUFVkcWRrYWZzR21PMzBDeElPaDBLNWJSQW5XQzd4KwotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tCg==",
"disabled": "boolean",
"privateKey": "LS0tLS1CRUdJTiBQUklWQVRFIBtFWS0tLS0tCk1JR0hBZ0VBTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEJHMHdhd0lCQVFRZ1RDRzhRWDZKdkR0eC95ZDMKdlpkUHJKR25LcjhiWHRsdXNIL2FOYW5XdHEraFJBTkNBQVE0QnZ6ODI2L2lDaXV1U0NiZVkwc3FmOXljYWh0OApDRFYyUFF2bDFVM1FLSVRBcWRpaktLa0FSUFVkcWRrYWZzR21PMzBDeElPaDBLNWJSQW5XQzd4KwotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tCg=="
}
```
# Update a signing key
Source: https://docs.livepeer.org/v1/api-reference/signing-key/update
PATCH /access-control/signing-key/{keyId}
# Add a multistream target
Source: https://docs.livepeer.org/v1/api-reference/stream/add-multistream-target
POST /stream/{id}/create-multistream-target
# Create a livestream
Source: https://docs.livepeer.org/v1/api-reference/stream/create
POST /stream
The only parameter you are required to set is the name of your stream,
but we also highly recommend that you define transcoding profiles
parameter that suits your specific broadcasting configuration.
\
\
If you do not define transcoding rendition profiles when creating the
stream, a default set of profiles will be used. These profiles include
240p, 360p, 480p and 720p.
\
\
The playback policy is set to public by default for new streams. It can
also be added upon the creation of a new stream by adding
`"playbackPolicy": {"type": "jwt"}`
# Create a clip
Source: https://docs.livepeer.org/v1/api-reference/stream/create-clip
POST /clip
# Delete a livestream
Source: https://docs.livepeer.org/v1/api-reference/stream/delete
DELETE /stream/{id}
This will also suspend any active stream sessions, so make sure to wait
until the stream has finished. To explicitly interrupt an active
session, consider instead updating the suspended field in the stream
using the PATCH stream API.
# Remove a multistream target
Source: https://docs.livepeer.org/v1/api-reference/stream/delete-multistream-target
DELETE /stream/{id}/multistream/{targetId}
# Retrieve a livestream
Source: https://docs.livepeer.org/v1/api-reference/stream/get
GET /stream/{id}
# Retrieve all livestreams
Source: https://docs.livepeer.org/v1/api-reference/stream/get-all
GET /stream
# Retrieve clips of a livestream
Source: https://docs.livepeer.org/v1/api-reference/stream/get-clip
GET /stream/{id}/clips
# Overview
Source: https://docs.livepeer.org/v1/api-reference/stream/overview
The Livestream API is used to create, retrieve, update, delete stream object from pipeline.
### Stream Object
Unique identifier for the stream.
Name of the stream.
Reference to the creator-id schema.
Timestamp of the last activity on the stream.
Number of source segments.
Number of transcoded segments.
Duration of all the source segments in seconds.
Duration of all the transcoded segments in seconds.
Total bytes of source segments.
Total bytes of transcoded segments.
Rate at which sourceBytes increases (bytes/second).
Rate at which transcodedBytes increases (bytes/second).
Indicates if the stream is currently active.
Reference to the stream-health-payload schema for health status.
Reference to the stream-health-payload schema for human-readable issues.
Name of the token used to create this stream.
Timestamp (in milliseconds) of when the stream object was created.
Identifier for the parent stream object.
Key used to form the RTMP ingest URL.
Identifier used to form the playback URL.
Reference to the playback-policy schema.
Array of profiles detailing various streaming qualities.
Indicates if the stream should be recorded.
Details about multistreaming targets and their configurations.
Indicates if the stream is currently suspended.
```json Response theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"id": "de7818e7-610a-4057-8f6f-b785dc1e6f88",
"name": "test_stream",
"creatorId": "object",
"lastSeen": 1587667174725,
"sourceSegments": 1,
"transcodedSegments": 2,
"sourceSegmentsDuration": 1,
"transcodedSegmentsDuration": 2,
"sourceBytes": 1,
"transcodedBytes": 2,
"ingestRate": 1,
"outgoingRate": 2,
"isActive": "boolean",
"isHealthy": true,
"issues": ["Buffer underflow", "Network congestion"],
"createdByTokenName": "staging key",
"createdAt": 1587667174725,
"parentId": "de7818e7-610a-4057-8f6f-b785dc1e6f88",
"streamKey": "hgebdhhigq",
"playbackId": "eaw4nk06ts2d0mzb",
"playbackPolicy": {
"type": "public",
"webhookId": "3e02c844-d364-4d48-b401-24b2773b5d6c",
"webhookContext": {
"foo": "bar"
}
},
"profiles": [
{
"name": "720p",
"width": 1280,
"height": 720,
"bitrate": 3000,
"fps": 30
}
],
"record": "boolean",
"multistream": {
"targets": [
{
"id": "PUSH123",
"profile": "720p"
}
]
},
"suspended": "boolean"
}
```
# Terminates a livestream
Source: https://docs.livepeer.org/v1/api-reference/stream/terminate
DELETE /stream/{id}/terminate
`DELETE /stream/{id}/terminate` can be used to terminate an ongoing
session on a live stream. Unlike suspending the stream, it allows the
streamer to restart streaming even immediately, but it will force
terminate the current session and stop the recording.
\
\
A 204 No Content status response indicates the stream was successfully
terminated.
# Update a livestream
Source: https://docs.livepeer.org/v1/api-reference/stream/update
PATCH /stream/{id}
# Retrieve a task
Source: https://docs.livepeer.org/v1/api-reference/task/get
GET /task/{taskId}
# Retrieve tasks
Source: https://docs.livepeer.org/v1/api-reference/task/get-all
GET /task
# Overview
Source: https://docs.livepeer.org/v1/api-reference/task/overview
The Tasks API is used to retrieve tasks object from pipeline.
### Task Object
Task ID.
Type of the task, such as upload, import, export, etc.
Timestamp (in milliseconds) at which the task was created.
Timestamp (in milliseconds) at which the task was scheduled for execution.
ID of the input asset for the task.
ID of the output asset for the task.
Parameters of the task, which vary depending on the task type.
Status of the task, including phase, update time, and error message.
Output of the task, specifics depend on the task type.
```json Response theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"id": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"type": "upload",
"createdAt": 1587667174725,
"scheduledAt": 1587667174725,
"inputAssetId": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"outputAssetId": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"params": {
"upload": {
"url": "https://cdn.livepeer.com/ABC123/filename.mp4",
"encryption": {
"encryptedKey": "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JR0hBZ0VBTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEJHMHdhd0lCQVFRZ1RDRzhRWDZKdkR0eC95ZDMKdlpkUHJKR25LcjhiWHRsdXNIL2FOYW5XdHEraFJBTkNBQVE0QnZ6ODI2L2lDaXV1U0NiZVkwc3FmOXljYWh0OApDRFYyUFF2bDFVM1FLSVRBcWRpaktLa0FSUFVkcWRrYWZzR21PMzBDeElPaDBLNWJSQW5XQzd4KwotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tCg=="
},
"recordedSessionId": "78df0075-b5f3-4683-a618-1086faca35dc"
},
"import": {
"url": "https://cdn.livepeer.com/ABC123/filename.mp4",
"encryption": {
"encryptedKey": "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JR0hBZ0VBTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEJHMHdhd0lCQVFRZ1RDRzhRWDZKdkR0eC95ZDMKdlpkUHJKR25LcjhiWHRsdXNIL2FOYW5XdHEraFJBTkNBQVE0QnZ6ODI2L2lDaXV1U0NiZVkwc3FmOXljYWh0OApDRFYyUFF2bDFVM1FLSVRBcWRpaktLa0FSUFVkcWRrYWZzR21PMzBDeElPaDBLNWJSQW5XQzd4KwotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tCg=="
},
"recordedSessionId": "78df0075-b5f3-4683-a618-1086faca35dc"
},
"exportData": {
"content": "object",
"ipfs": {
"nftMetadataTemplate": "file",
"nftMetadata": "object",
"pinata": {
"jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MDI4NjQwNzcsImlhdCI6MTYwMjI3NjA3NywiaXNzIjoiYXBpLmlzc3VlciIsInN1YiI6I"
}
},
"type": "string",
"id": "string"
},
"transcode": {
"profile": {
"width": 1280,
"name": "720p",
"height": 720,
"bitrate": 4000,
"fps": 30,
"fpsDen": 1,
"gop": "60",
"profile": "H264High",
"encoder": "h264"
}
},
"transcode-file": {
"input": {
"url": "https://cdn.livepeer.com/ABC123/filename.mp4"
},
"storage": {
"url": "s3+https://accessKeyId:secretAccessKey@s3Endpoint/bucket"
},
"outputs": {
"hls": {
"path": "/samplevideo/hls"
},
"mp4": {
"path": "/samplevideo/mp4"
}
},
"profiles": [
{
"width": 1280,
"name": "720p",
"height": 720,
"bitrate": 4000,
"fps": 30,
"fpsDen": 1,
"gop": "60",
"profile": "H264High",
"encoder": "h264"
}
],
"targetSegmentSizeSecs": "number",
"c2pa": "boolean"
}
},
"clip": {
"url": "string",
"clipStrategy": {
"startTime": "number",
"endTime": "number",
"playbackId": "string"
},
"catalystPipelineStrategy": "catalyst",
"sessionId": "string",
"inputId": "string"
},
"status": {
"phase": "pending",
"updatedAt": 1587667174725,
"progress": "number",
"errorMessage": "string",
"retries": "number",
"step": "string"
},
"output": {
"upload": {
"videoFilePath": "string",
"metadataFilePath": "string",
"assetSpec": {
"id": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"type": "video",
"playbackId": "eaw4nk06ts2d0mzb",
"staticMp4": "boolean",
"c2pa": "boolean",
"playbackUrl": "https://livepeercdn.com/asset/ea03f37e-f861-4cdd-b495-0e60b6d753ad/index.m3u8",
"downloadUrl": "https://livepeercdn.com/asset/eaw4nk06ts2d0mzb/video",
"playbackPolicy": {
"type": "public",
"webhookId": "3e02c844-d364-4d48-b401-24b2773b5d6c",
"webhookContext": {
"foo": "bar"
}
},
"source": {
"type": "url",
"url": "https://example.com/video.mp4",
"gatewayUrl": "https://example.com/video.mp4"
},
"creatorId": "object",
"storage": {
"ipfs": {
"spec": {
"nftMetadataTemplate": "file",
"nftMetadata": {
"name": "My NFT",
"description": "My NFT description"
}
}
}
},
"status": {
"phase": "ready",
"updatedAt": 1587667174725,
"progress": 100
},
"name": "filename.mp4",
"createdAt": 1587667174725,
"size": 84934509,
"hash": [
{
"hash": "9b560b28b85378a5004117539196ab24e21bbd75b0e9eb1a8bc7c5fd80dc5b57",
"algorithm": "sha256"
}
],
"videoSpec": {
"format": "mp4",
"duration": 23.8328,
"bitrate": 1000000,
"tracks": [
{
"type": "video",
"codec": "h264",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"width": 1920,
"height": 1080,
"pixelFormat": "yuv420p",
"fps": 30
},
{
"type": "audio",
"codec": "aac",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"channels": 2,
"sampleRate": 44100,
"bitDepth": 16
}
]
}
}
},
"import": {
"videoFilePath": "string",
"metadataFilePath": "string",
"assetSpec": {
"id": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"type": "video",
"playbackId": "eaw4nk06ts2d0mzb",
"staticMp4": "boolean",
"c2pa": "boolean",
"playbackUrl": "https://livepeercdn.com/asset/ea03f37e-f861-4cdd-b495-0e60b6d753ad/index.m3u8",
"downloadUrl": "https://livepeercdn.com/asset/eaw4nk06ts2d0mzb/video",
"playbackPolicy": {
"type": "public",
"webhookId": "3e02c844-d364-4d48-b401-24b2773b5d6c",
"webhookContext": {
"foo": "bar"
}
},
"source": {
"type": "url",
"url": "https://example.com/video.mp4",
"gatewayUrl": "https://example.com/video.mp4"
},
"creatorId": "object",
"storage": {
"ipfs": {
"spec": {
"nftMetadataTemplate": "file",
"nftMetadata": {
"name": "My NFT",
"description": "My NFT description"
}
}
}
},
"status": {
"phase": "ready",
"updatedAt": 1587667174725,
"progress": 100
},
"name": "filename.mp4",
"createdAt": 1587667174725,
"size": 84934509,
"hash": [
{
"hash": "9b560b28b85378a5004117539196ab24e21bbd75b0e9eb1a8bc7c5fd80dc5b57",
"algorithm": "sha256"
}
],
"videoSpec": {
"format": "mp4",
"duration": 23.8328,
"bitrate": 1000000,
"tracks": [
{
"type": "video",
"codec": "h264",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"width": 1920,
"height": 1080,
"pixelFormat": "yuv420p",
"fps": 30
},
{
"type": "audio",
"codec": "aac",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"channels": 2,
"sampleRate": 44100,
"bitDepth": 16
}
]
}
}
},
"export": {
"ipfs": {
"videoFileCid": "string",
"videoFileUrl": "string",
"videoFileGatewayUrl": "string",
"nftMetadataCid": "string",
"nftMetadataUrl": "string",
"nftMetadataGatewayUrl": "string"
}
},
"exportData": {
"ipfs": {
"cid": "string"
}
},
"transcode": {
"asset": {
"videoFilePath": "string",
"metadataFilePath": "string",
"assetSpec": {
"id": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"type": "video",
"playbackId": "eaw4nk06ts2d0mzb",
"staticMp4": "boolean",
"c2pa": "boolean",
"playbackUrl": "https://livepeercdn.com/asset/ea03f37e-f861-4cdd-b495-0e60b6d753ad/index.m3u8",
"downloadUrl": "https://livepeercdn.com/asset/eaw4nk06ts2d0mzb/video",
"playbackPolicy": {
"type": "public",
"webhookId": "3e02c844-d364-4d48-b401-24b2773b5d6c",
"webhookContext": {
"foo": "bar"
}
},
"source": {
"type": "url",
"url": "https://example.com/video.mp4",
"gatewayUrl": "https://example.com/video.mp4"
},
"creatorId": "object",
"storage": {
"ipfs": {
"spec": {
"nftMetadataTemplate": "file",
"nftMetadata": {
"name": "My NFT",
"description": "My NFT description"
}
}
}
},
"status": {
"phase": "ready",
"updatedAt": 1587667174725,
"progress": 100
},
"name": "filename.mp4",
"createdAt": 1587667174725,
"size": 84934509,
"hash": [
{
"hash": "9b560b28b85378a5004117539196ab24e21bbd75b0e9eb1a8bc7c5fd80dc5b57",
"algorithm": "sha256"
}
],
"videoSpec": {
"format": "mp4",
"duration": 23.8328,
"bitrate": 1000000,
"tracks": [
{
"type": "video",
"codec": "h264",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"width": 1920,
"height": 1080,
"pixelFormat": "yuv420p",
"fps": 30
},
{
"type": "audio",
"codec": "aac",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"channels": 2,
"sampleRate": 44100,
"bitDepth": 16
}
]
}
}
}
}
}
}
```
# Transcode a video
Source: https://docs.livepeer.org/v1/api-reference/transcode/create
POST /transcode
`POST /transcode` transcodes a video file and uploads the results to the
specified storage service.
\
\
Transcoding is asynchronous so you will need to check the status of the
task in order to determine when transcoding is complete. The `id` field
in the response is the unique ID for the transcoding `Task`. The task
status can be queried using the [GET tasks
endpoint](https://docs.livepeer.org/reference/api/get-tasks):
\
\
When `status.phase` is `completed`, transcoding will be complete and
the results will be stored in the storage service and the specified
output location.
\
\
The results will be available under `params.outputs.hls.path` and
`params.outputs.mp4.path` in the specified storage service.
## Input
\
This endpoint currently supports the following inputs:
- HTTP
- S3 API Compatible Service
\
\
**HTTP**
\
A public HTTP URL can be used to read a video file.
```json
{
"url": "https://www.example.com/video.mp4"
}
```
| Name | Type | Description |
| ---- | ------ | ------------------------------------ |
| url | string | A public HTTP URL for the video file. |
Note: For IPFS HTTP gateway URLs, the API currently only supports “path
style” URLs and does not support “subdomain style” URLs. The API will
support both styles of URLs in a future update.
\
\
**S3 API Compatible Service**
\
\
S3 credentials can be used to authenticate with a S3 API compatible
service to read a video file.
```json
{
"type": "s3",
"endpoint": "https://gateway.storjshare.io",
"credentials": {
"accessKeyId": "$ACCESS_KEY_ID",
"secretAccessKey": "$SECRET_ACCESS_KEY"
},
"bucket": "inbucket",
"path": "/video/source.mp4"
}
```
## Storage
\
This endpoint currently supports the following storage services:
- S3 API Compatible Service
- Web3 Storage
\
\
**S3 API Compatible Service**
```json
{
"type": "s3",
"endpoint": "https://gateway.storjshare.io",
"credentials": {
"accessKeyId": "$ACCESS_KEY_ID",
"secretAccessKey": "$SECRET_ACCESS_KEY"
},
"bucket": "mybucket"
}
```
**Web3 Storage**
```json
{
"type": "web3.storage",
"credentials": {
"proof": "$UCAN_DELEGATION_PROOF",
}
}
```
## Outputs
\
This endpoint currently supports the following output types:
- HLS
- MP4
**HLS**
```json
{
"hls": {
"path": "/samplevideo/hls"
}
}
```
**MP4**
```json
{
"mp4": {
"path": "/samplevideo/mp4"
}
}
```
# Overview
Source: https://docs.livepeer.org/v1/api-reference/transcode/overview
The Transcode API is used to create transcode object from pipeline.
### Transcode Object
Task ID.
Type of the task, such as upload, import, export, etc.
Timestamp (in milliseconds) at which the task was created.
Timestamp (in milliseconds) at which the task was scheduled for execution.
ID of the input asset for the task.
ID of the output asset for the task.
Parameters of the task, which vary depending on the task type.
Status of the task, including phase, update time, and error message.
Output of the task, specifics depend on the task type.
```json Response theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"id": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"type": "upload",
"createdAt": 1587667174725,
"scheduledAt": 1587667174725,
"inputAssetId": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"outputAssetId": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"params": {
"upload": {
"url": "https://cdn.livepeer.com/ABC123/filename.mp4",
"encryption": {
"encryptedKey": "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JR0hBZ0VBTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEJHMHdhd0lCQVFRZ1RDRzhRWDZKdkR0eC95ZDMKdlpkUHJKR25LcjhiWHRsdXNIL2FOYW5XdHEraFJBTkNBQVE0QnZ6ODI2L2lDaXV1U0NiZVkwc3FmOXljYWh0OApDRFYyUFF2bDFVM1FLSVRBcWRpaktLa0FSUFVkcWRrYWZzR21PMzBDeElPaDBLNWJSQW5XQzd4KwotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tCg=="
},
"recordedSessionId": "78df0075-b5f3-4683-a618-1086faca35dc"
},
"import": {
"url": "https://cdn.livepeer.com/ABC123/filename.mp4",
"encryption": {
"encryptedKey": "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JR0hBZ0VBTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEJHMHdhd0lCQVFRZ1RDRzhRWDZKdkR0eC95ZDMKdlpkUHJKR25LcjhiWHRsdXNIL2FOYW5XdHEraFJBTkNBQVE0QnZ6ODI2L2lDaXV1U0NiZVkwc3FmOXljYWh0OApDRFYyUFF2bDFVM1FLSVRBcWRpaktLa0FSUFVkcWRrYWZzR21PMzBDeElPaDBLNWJSQW5XQzd4KwotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tCg=="
},
"recordedSessionId": "78df0075-b5f3-4683-a618-1086faca35dc"
},
"exportData": {
"content": "object",
"ipfs": {
"nftMetadataTemplate": "file",
"nftMetadata": "object",
"pinata": {
"jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MDI4NjQwNzcsImlhdCI6MTYwMjI3NjA3NywiaXNzIjoiYXBpLmlzc3VlciIsInN1YiI6I"
}
},
"type": "string",
"id": "string"
},
"transcode": {
"profile": {
"width": 1280,
"name": "720p",
"height": 720,
"bitrate": 4000,
"fps": 30,
"fpsDen": 1,
"gop": "60",
"profile": "H264High",
"encoder": "h264"
}
},
"transcode-file": {
"input": {
"url": "https://cdn.livepeer.com/ABC123/filename.mp4"
},
"storage": {
"url": "s3+https://accessKeyId:secretAccessKey@s3Endpoint/bucket"
},
"outputs": {
"hls": {
"path": "/samplevideo/hls"
},
"mp4": {
"path": "/samplevideo/mp4"
}
},
"profiles": [
{
"width": 1280,
"name": "720p",
"height": 720,
"bitrate": 4000,
"fps": 30,
"fpsDen": 1,
"gop": "60",
"profile": "H264High",
"encoder": "h264"
}
],
"targetSegmentSizeSecs": "number",
"c2pa": "boolean"
}
},
"clip": {
"url": "string",
"clipStrategy": {
"startTime": "number",
"endTime": "number",
"playbackId": "string"
},
"catalystPipelineStrategy": "catalyst",
"sessionId": "string",
"inputId": "string"
},
"status": {
"phase": "pending",
"updatedAt": 1587667174725,
"progress": "number",
"errorMessage": "string",
"retries": "number",
"step": "string"
},
"output": {
"upload": {
"videoFilePath": "string",
"metadataFilePath": "string",
"assetSpec": {
"id": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"type": "video",
"playbackId": "eaw4nk06ts2d0mzb",
"staticMp4": "boolean",
"c2pa": "boolean",
"playbackUrl": "https://livepeercdn.com/asset/ea03f37e-f861-4cdd-b495-0e60b6d753ad/index.m3u8",
"downloadUrl": "https://livepeercdn.com/asset/eaw4nk06ts2d0mzb/video",
"playbackPolicy": {
"type": "public",
"webhookId": "3e02c844-d364-4d48-b401-24b2773b5d6c",
"webhookContext": {
"foo": "bar"
}
},
"source": {
"type": "url",
"url": "https://example.com/video.mp4",
"gatewayUrl": "https://example.com/video.mp4"
},
"creatorId": "object",
"storage": {
"ipfs": {
"spec": {
"nftMetadataTemplate": "file",
"nftMetadata": {
"name": "My NFT",
"description": "My NFT description"
}
}
}
},
"status": {
"phase": "ready",
"updatedAt": 1587667174725,
"progress": 100
},
"name": "filename.mp4",
"createdAt": 1587667174725,
"size": 84934509,
"hash": [
{
"hash": "9b560b28b85378a5004117539196ab24e21bbd75b0e9eb1a8bc7c5fd80dc5b57",
"algorithm": "sha256"
}
],
"videoSpec": {
"format": "mp4",
"duration": 23.8328,
"bitrate": 1000000,
"tracks": [
{
"type": "video",
"codec": "h264",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"width": 1920,
"height": 1080,
"pixelFormat": "yuv420p",
"fps": 30
},
{
"type": "audio",
"codec": "aac",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"channels": 2,
"sampleRate": 44100,
"bitDepth": 16
}
]
}
}
},
"import": {
"videoFilePath": "string",
"metadataFilePath": "string",
"assetSpec": {
"id": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"type": "video",
"playbackId": "eaw4nk06ts2d0mzb",
"staticMp4": "boolean",
"c2pa": "boolean",
"playbackUrl": "https://livepeercdn.com/asset/ea03f37e-f861-4cdd-b495-0e60b6d753ad/index.m3u8",
"downloadUrl": "https://livepeercdn.com/asset/eaw4nk06ts2d0mzb/video",
"playbackPolicy": {
"type": "public",
"webhookId": "3e02c844-d364-4d48-b401-24b2773b5d6c",
"webhookContext": {
"foo": "bar"
}
},
"source": {
"type": "url",
"url": "https://example.com/video.mp4",
"gatewayUrl": "https://example.com/video.mp4"
},
"creatorId": "object",
"storage": {
"ipfs": {
"spec": {
"nftMetadataTemplate": "file",
"nftMetadata": {
"name": "My NFT",
"description": "My NFT description"
}
}
}
},
"status": {
"phase": "ready",
"updatedAt": 1587667174725,
"progress": 100
},
"name": "filename.mp4",
"createdAt": 1587667174725,
"size": 84934509,
"hash": [
{
"hash": "9b560b28b85378a5004117539196ab24e21bbd75b0e9eb1a8bc7c5fd80dc5b57",
"algorithm": "sha256"
}
],
"videoSpec": {
"format": "mp4",
"duration": 23.8328,
"bitrate": 1000000,
"tracks": [
{
"type": "video",
"codec": "h264",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"width": 1920,
"height": 1080,
"pixelFormat": "yuv420p",
"fps": 30
},
{
"type": "audio",
"codec": "aac",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"channels": 2,
"sampleRate": 44100,
"bitDepth": 16
}
]
}
}
},
"export": {
"ipfs": {
"videoFileCid": "string",
"videoFileUrl": "string",
"videoFileGatewayUrl": "string",
"nftMetadataCid": "string",
"nftMetadataUrl": "string",
"nftMetadataGatewayUrl": "string"
}
},
"exportData": {
"ipfs": {
"cid": "string"
}
},
"transcode": {
"asset": {
"videoFilePath": "string",
"metadataFilePath": "string",
"assetSpec": {
"id": "09F8B46C-61A0-4254-9875-F71F4C605BC7",
"type": "video",
"playbackId": "eaw4nk06ts2d0mzb",
"staticMp4": "boolean",
"c2pa": "boolean",
"playbackUrl": "https://livepeercdn.com/asset/ea03f37e-f861-4cdd-b495-0e60b6d753ad/index.m3u8",
"downloadUrl": "https://livepeercdn.com/asset/eaw4nk06ts2d0mzb/video",
"playbackPolicy": {
"type": "public",
"webhookId": "3e02c844-d364-4d48-b401-24b2773b5d6c",
"webhookContext": {
"foo": "bar"
}
},
"source": {
"type": "url",
"url": "https://example.com/video.mp4",
"gatewayUrl": "https://example.com/video.mp4"
},
"creatorId": "object",
"storage": {
"ipfs": {
"spec": {
"nftMetadataTemplate": "file",
"nftMetadata": {
"name": "My NFT",
"description": "My NFT description"
}
}
}
},
"status": {
"phase": "ready",
"updatedAt": 1587667174725,
"progress": 100
},
"name": "filename.mp4",
"createdAt": 1587667174725,
"size": 84934509,
"hash": [
{
"hash": "9b560b28b85378a5004117539196ab24e21bbd75b0e9eb1a8bc7c5fd80dc5b57",
"algorithm": "sha256"
}
],
"videoSpec": {
"format": "mp4",
"duration": 23.8328,
"bitrate": 1000000,
"tracks": [
{
"type": "video",
"codec": "h264",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"width": 1920,
"height": 1080,
"pixelFormat": "yuv420p",
"fps": 30
},
{
"type": "audio",
"codec": "aac",
"startTime": 0,
"duration": 23.8328,
"bitrate": 1000000,
"channels": 2,
"sampleRate": 44100,
"bitDepth": 16
}
]
}
}
}
}
}
}
```
# Query creator viewership metrics
Source: https://docs.livepeer.org/v1/api-reference/viewership/get-creators-metrics
GET /data/views/query/creator
Requires a proof of ownership to be sent in the request, which for now is just the assetId or streamId parameters (1 of those must be in the query-string).
# Query public total views metrics
Source: https://docs.livepeer.org/v1/api-reference/viewership/get-public-total-views
GET /data/views/query/total/{playbackId}
Allows querying for the public metrics for viewership about a video.
This can be called from the frontend with a CORS key, or even
unauthenticated.
# Query realtime viewership
Source: https://docs.livepeer.org/v1/api-reference/viewership/get-realtime-viewership
GET /data/views/now
Requires a private (non-CORS) API key to be used.
# Query usage metrics
Source: https://docs.livepeer.org/v1/api-reference/viewership/get-usage-metrics
GET /data/usage/query
# Query viewership metrics
Source: https://docs.livepeer.org/v1/api-reference/viewership/get-viewership-metrics
GET /data/views/query
Requires a private (non-CORS) API key to be used.
# Create a webhook
Source: https://docs.livepeer.org/v1/api-reference/webhook/create
POST /webhook
To create a new webhook, you need to make an API call with the events you want to listen for and the URL that will be called when those events occur.
# Delete a webhook
Source: https://docs.livepeer.org/v1/api-reference/webhook/delete
DELETE /webhook/{id}
# Retrieve a webhook
Source: https://docs.livepeer.org/v1/api-reference/webhook/get
GET /webhook/{id}
# Retrieve all webhooks
Source: https://docs.livepeer.org/v1/api-reference/webhook/get-all
GET /webhook
# Overview
Source: https://docs.livepeer.org/v1/api-reference/webhook/overview
The Webhooks API is used to create, retrieve, update, delete webhooks object from pipeline.
### Webhook Object
Unique identifier for the webhook.
Name of the webhook.
Timestamp (in milliseconds) at which the webhook object was created.
List of events that the webhook subscribes to. Possible events include
stream.started, stream.detection, recording.ready, etc.
URL of the webhook endpoint.
Shared secret used to sign the webhook payload.
StreamId of the stream to which the webhook is applied.
Status of the webhook, including last failure and last triggered timestamp.
Details about the last failure of the webhook, including timestamp, error
message, response, and status code.
Timestamp (in milliseconds) at which the webhook was last triggered.
```json Response theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"id": "de7818e7-610a-4057-8f6f-b785dc1e6f88",
"name": "My webhook",
"createdAt": 1587667174725,
"events": [
"stream.started",
"recording.ready"
],
"url": "https://webhook.example.com",
"sharedSecret": "mySharedSecret",
"streamId": "de7818e7-610a-4057-8f6f-b785dc1e6f88",
"status": {
"lastFailure": {
"timestamp": 1587667174725,
"error": "Error message",
"response": "Response body",
"statusCode": 500
},
"lastTriggeredAt": 1587667174725
}
}
```
# Update a webhook
Source: https://docs.livepeer.org/v1/api-reference/webhook/update
PUT /webhook/{id}
# Assess concurrent stream
Source: https://docs.livepeer.org/v1/orchestrators/guides/assess-capabilities
Once you have confirmed that your
[hardware](/references/go-livepeer/gpu-support) is supported by `Go Livepeer`,
you should assess how many concurrent streams it can support.
## Hardware functionality and constraints
The Livepeer protocol enables those with the excess hardware and bandwidth
available to earn additional revenue by advertising video encoding services on
an open marketplace, and using their idle hardware to perform the work. There
are a number of different types of hardware capable of encoding video in a
performant and cost-effective manner, each with its own unique capabilities and
terms of use.
Some of these terms restrict users from utilizing their own hardware to its full
capacity through artificial restrictions. While googling for open-source patches
reveals workarounds to these limitations, Livepeer encourages operators on the
network to read and comply with the terms of service and usage policies of the
hardware that they are using.
### NVIDIA
If you are using an NVIDIA card, check you are running the latest driver version
on your NVIDIA GPU, or update your driver before proceeding to benchmarking. You
can access the GPU configuration, Display Adapters, and drivers for your
operating system either directly or through your NVIDIA Control Panel.
Concurrent session caps for NVIDIA hardware can be found
[here](https://developer.nvidia.com/video-encode-decode-gpu-support-matrix).
## Testing
You can test the performance of your card using the `livepeer_bench`
[benchmarking tool](/orchestrators/guides/benchmark-transcoding).
# Benchmark Transcoding
Source: https://docs.livepeer.org/v1/orchestrators/guides/benchmark-transcoding
This guide provides steps to test the performance of your GPU(s) with the
`livepeer_bench` benchmark transcoding tool provided with the
[Livepeer install](/orchestrators/guides/install-go-livepeer/).
The benchmarking tool is designed to:
* Simulate live-mode to measure transcoding as if connected to the network
* Gauge local transcoding capacity
* Provide output statistics to show real-time segment ratio and stream duration
ratio
* Provide for adjusting configurations according to GPU capacity
## Transcoding Performance
Overall transcoding performance on the network depends on the speed video is
transcoded and uploaded/downloaded from an orchestrator.
The transcode time should be as low as possible. At the least, it should be
lower than the total segment duration which is faster than real-time.
If you want to get an approximation of how many streams you can transcode
simultaneously, increase the number of concurrent sessions with the
`-concurrentSessions` flag to assess the total transcoding time.
After running your benchmark transcoding, you can follow up with further
instructions about setting [session
limits](/orchestrators/guides/set-session-limits).
## Start Benchmarking
1. Download the test stream we provide for benchmarking transcoding:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
wget -c https://storage.googleapis.com/lp_testharness_assets/bbb_1080p_30fps_1min_2sec_hls.tar.gz
tar -xvf bbb_1080p_30fps_1min_2sec_hls.tar.gz
ls bbb/ # Should print the stream *.ts segments and source.m3u8 manifest
```
It is important to note that running this benchmarking only gauges local
transcoding capacity.
2. Download the
[common output rendition configuration](https://github.com/livepeer/go-livepeer/blob/master/cmd/livepeer_bench/transcodingOptions.json)
`.json` file that you can copy and save in the Livepeer folder as
`transcodingOptions.json`.
3. Run `livepeer_bench`
The number and type of output renditions will impact benchmark results.
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
livepeer_bench \
-in bbb/source.m3u8 \
-transcodingOptions transcodingOptions.json \
-nvidia # Only required for transcoding with GPUs
-concurrentSessions
```
### Flags
* The `-nvidia` flag is only required when transcoding with Nvidia GPUs. It is
used to specify a comma-delimited string of Nvidia GPU IDs.
* The `-concurrentSessions` flag is used to specify the number of concurrent
transcoding sessions. The default value is 1.
### Livestreams
Livestreams are the most common type of workload on the network. By default, the
flag is set to live mode `-live=*true*` so that the segments of the stream will
be queued one-by-one as they arrive in a livestream.
If you want to queue all segments at once without any gaps in time, thus
replicating a video-on-demand scenario, you can switch off live mode by changing
the 'live' flag to *`=false`*.
**For example:**
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
livepeer_bench \
-in bbb/source.m3u8 \
-live=false
```
For the purposes of this example above, all other flags are omitted.
The first few lines of the output should display the source file, the output
rendition profiles, and the number of concurrent sessions.
**For example:**
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
*---------------------*----------------------------------------------*
| Source File | .../go-livepeer/bbb/source.m3u8 |
| Transcoding Options | P240p30fps16x9,P360p30fps16x9,P720p30fps16x9 |
| Concurrent Sessions | 1 |
| Live Mode | true |
*---------------------*----------------------------------------------*
```
The transcoding metrics will be output in CSV format per segment as each segment
gets transcoded.
**For example:**
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
timestamp,session,segment,seg_dur,transcode_time
2021-03-12 00:21:29.1412,0,0,2,0.2545
2021-03-12 00:21:30.998,0,1,2,0.1107
2021-03-12 00:21:32.9816,0,2,2,0.09381
2021-03-12 00:21:34.9786,0,3,2,0.09031
2021-03-12 00:21:36.9806,0,4,2,0.09178
2021-03-12 00:21:38.9811,0,5,2,0.09216
2021-03-12 00:21:40.9831,0,6,2,0.09363
2021-03-12 00:21:42.9874,0,7,2,0.09746
2021-03-12 00:21:44.9885,0,8,2,0.09811
2021-03-12 00:21:46.9851,0,9,2,0.09412
```
When all the transcoding sessions end, metrics output will be generated.
* `Real-Time Segs Ratio` captures the number of segments transcoded in
real-time.
* `Real-Time Duration Ratio` captures the total time taken to transcode all
segments relative to the total duration of all source segments.
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
*------------------------------*---------------------*
| Concurrent Sessions | 1 |
| Total Segs Transcoded | 10 |
| Real-Time Segs Transcoded | 10 |
| * Real-Time Segs Ratio * | 1 |
| Total Source Duration | 20s |
| Total Transcoding Duration | 1.1165546499999999s |
| * Real-Time Duration Ratio * | 0.05583 |
*------------------------------*---------------------*
```
You can export the per-segment CSV data to an `output.csv` file to analyze it
with other tools:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
livepeer_bench \
-in bbb/source.m3u8 \
-transcodingOptions transcodingOptions.json \
-nvidia # Only required for transcoding with GPUs
-concurrentSessions > output.csv
```
# Dual Mine
Source: https://docs.livepeer.org/v1/orchestrators/guides/dual-mine
In this guide, we'll go over how to process video on the Livepeer Network using
your GPU while simultaneously mining cryptocurrencies such as Filecoin or
Bitcoin using the same GPU.
## Dual ethash mining and transcoding
### Choosing a miner
Dual ethash mining and transcoding has been tested on the GPUs in
[this list](/references/go-livepeer/gpu-support) and with the following miners:
* [t-rex](https://github.com/trexminer/T-Rex)
* [ethminer](https://github.com/ethereum-mining/ethminer)
If you successfully test with other miners, contributions to this document are
welcome.
If you are using a post-Volta GPU, the recommendation is to use ethminer because
it exposes flags for more granular adjustments to the GPU workload which will be
needed when using CUDA MPS (see the next section) to prevent the miner from
fully staturating the GPU. Other miners that support similar flags can be
substituted for ethminer as well.
If you are using a pre-Volta GPU, the recommendation is to use t-rex because it
is, at the time of writing, the most popular and efficient ethash miner that has
been tested with `livepeer`. Other miners that have been tested successfully
with `livepeer` can be substituted for t-rex as well.
Note that regardless of the miner used, the VRAM available on your GPU will
affect the number of concurrent streams that can be transcoded while mining.
### Run a ethminer + livepeer script
If you are using ethminer,
[this script](https://github.com/livepeer/ethminer/blob/master/start.sh) can be
used to start both processes.
If you want to setup a dual mining manually perhaps because the script does not
serve your needs, continue to the next sections.
### Run CUDA MPS
[CUDA MPS](https://docs.nvidia.com/deploy/mps/index.html) can be used to try to
improve parallelization of the ethash mining and transcoding workloads on the
GPU. If you are not using CUDA MPS you can move on to the next section.
Requirements:
* Linux
* A post-Volta Nvidia GPU. Refer to the
[GPU NVENC/NVDEC support matrix](https://developer.nvidia.com/video-encode-and-decode-gpu-support-matrix-new)
for the generation that a GPU is from.
Start the MPS server by following
[these instructions](https://docs.nvidia.com/deploy/mps/index.html#topic_6_1_2)
Take note of the following points that are mentioned in the docs:
* The `CUDA_VISIBLE_DEVICES` environment variable should be set with device IDs
of the GPUS you will be using before the MPS daemon is started, but it should
NOT be set before starting the miner and `livepeer`
* If you are using a mix of pre-Volta and post-Volta GPUs, make sure to read
this [section](https://docs.nvidia.com/deploy/mps/index.html#topic_3_3_4) to
avoid device ID issues
### Run the miner
The following instructions will assume you are using either t-rex or ethminer.
If you are using a different miner, the miner commands should be updated to
reflect the requirements of the miner being used.
If you are using ethminer, run ethminer with flags to adjust the GPU workload
(other flags to connect to a mining pool omitted):
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
ethminer \
-U \
--cu-devices \ # List of Nvidia GPU IDs
--cuda-streams \ # Number of multiprocessor streams
--cuda-block-size \ # Number of threads per block
--cuda-grid-size \ # Number of blocks per grid
```
The `--cuda-streams`, `--cuda-block-size` and `--cuda-grid-size` flags are used
to adjust the GPU workload. The best values to use for these flags will depend
on your GPU and whether you want lower hashrate and faster transcoding speed or
higher hashrate and lower transcoding speed.
If you are using t-rex, run t-rex with a flag to adjust mining intensity (other
flags to connect to a mining pool omitted):
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
t-rex \
-a ethash \
-d \ # List of Nvidia GPU IDs
-i
Contract addresses in this guide may be outdated. For current verified addresses, see:
**[Livepeer Contract Addresses](/v2/about/resources/livepeer-contract-addresses)**
This guide provides instructions for Livepeer participants using a contract
wallet (i.e., multisig) to stake on L1 (Ethereum Mainnet), to migrate this stake
to L2 (Arbitrum Mainnet) as per the
[Livepeer Confluence upgrade](https://medium.com/livepeer-blog/the-confluence-upgrade-is-live-3b6b342ea71e).
This guide is designed to be used in conjunction with the
[Livepeer Explorer L2 Contract Wallet Migration Tools](https://explorer.livepeer.org/migrate)
to support migrating to Arbitrum:
* Orchestrators - Migrate stake and fees
* Gateways - Migrate your deposit and reserve
* Delegators - Migrate undelegated stake
The migration process will transfer ownership of funds (i.e., stake) owned by
your L1 address to the L2 address.
## Create an L2 Address
**Before moving your stake, you MUST confirm that you have a valid L2 address
that can own funds migrated from L1. Otherwise, you could lose access to your L1
assets after the migration if you use the L1 address of your contract wallet as
the L2 address**
The L2 address can be that of a contract wallet (i.e.
[Gnosis Safe](https://gnosis-safe.io/)) deployed on L2, or an EOA (an externally
owned account managed by a hardware wallet (e.g., Ledger)), or a browser wallet
(e.g., Metamask).
**If you would like to use a contract wallet on L2 you MUST make sure that the
contract wallet is deployed on L2 and that you have control of it before
proceeding.**
> **Note:** If you are unsure about how to ensure you have a valid L2 address,
> please **reach out to the core team on Discord**.
## Migrate Stake
1. Use the
[Contract Wallet Tool](https://explorer.livepeer.org/migrate/delegator/contract-wallet-tool)
to generate the required parameters for the migration transactions. These
parameters will be required in upcoming steps:
2. Once you enter the L1 address, and an L2 address (the address you created in
the prior step), the tool will display the following:
* The `migrateDelegator` transaction parameters if the L1 address has stake to
migrate
* The `migrateUnbondingLocks` transaction parameters if the L1 address has
unbonding locks (i.e., undelegated stake) to migrate
### Submit a Stake Migration Transaction
If your L1 address has stake to migrate:
* Submit the stake migration transaction from your contract wallet, a function
call to the L1Migrator on **Ethereum Mainnet**.
* The contract address is `0x21146B872D3A95d2cF9afeD03eE5a783DaE9A89A`
* Copy the
[contract ABI](https://etherscan.io/address/0x21146B872D3A95d2cF9afeD03eE5a783DaE9A89A#code)
* The function name is `migrateDelegator` with the following parameters:
* `address _l1Addr`: the address of your L1 contract wallet that has stake to
migrate
* `address _l2Addr`: the address on L2 that will receive migrated stake (the
L2 address you created prior).
* `bytes _sig`: this parameter can be left blank
* `uint256 _maxGas`: the `maxGas` printed by the command-line tool
* `uint256 _gasPriceBid`: the `gasPriceBid` printed by the command-line tool
* `uint256 _maxSubmissionCost`: the `maxSubmissionCost` printed by the
command-line tool
* The ETH value to include with the function call should be the `value` printed
by the command-line tool. The `value` printed by the command-line tool is
**denominated in Wei**, so make sure to convert it into the units (i.e.,
Ether) required by the tool you are using to submit the transaction.
### Submit an Unbonding Lock Migration Transaction
If your L1 address has unbonding locks to migrate, submit an unbonding locks
migration transaction from your contract wallet; a function call to the
L1Migrator on **Ethereum Mainnet**.
* The contract address is `0x21146B872D3A95d2cF9afeD03eE5a783DaE9A89A`
* Copy the
[contract ABI](https://etherscan.io/address/0x21146B872D3A95d2cF9afeD03eE5a783DaE9A89A#code)
* The function name is `migrateUnbondingLocks` with the following parameters:
* `address _l1Addr`: the address of your L1 contract wallet that has unbonding
locks to migrate
* `address _l2Addr`: the address on L2 that will receive the total stake of
migrated unbonding locks (the L2 address you created prior).
* `uint256[] _unbondingLockIds`: The array of IDs for unbonding locks that
will be migrated
* `bytes _sig`: This parameter can be ignored and left blank
* `uint256 _maxGas`: This should be the `maxGas` printed by the command-line
tool
* `uint256 _gasPriceBid`: This should be the `gasPriceBid` printed by the
command-line tool
* `uint256 _maxSubmissionCost`: This should be the `maxSubmissionCost` printed
by the command-line tool
* The ETH value to include with the function call should be the `value` printed
by the command-line tool. The `value` printed by the command-line tool is
**denominated in Wei**, so make sure to convert it into the units (i.e.,
Ether) required by the tool you are using to submit the transaction.
### Waiting For Transaction Finalization on L2
After a migration transaction is submitted by the contract wallet and confirmed
on L1, it takes about \~10 minutes to finalize on L2. You can use a command-line
tool to confirm the transaction is finalized on L2:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
# Clone the repository
git clone https://github.com/livepeer/arbitrum-lpt-bridge
# Navigate into the repository
cd arbitrum-lpt-bridge
# Install dependencies
yarn
# Set environment variables
export MAINNET_URL=
export ARB_MAINNET_URL=
# Run command
npx hardhat wait-to-relay-tx-to-l2
```
* `` is the hash of the L1 transaction submitted by your contract
wallet.
The command will notify you when the transaction is finalized on L2. You
should then be able to navigate to the
[Livepeer Explorer](https://explorer.livepeer.org/) to find the L2 address you
specified and view the migrated stake owned by that address.
# Migrate to Arbitrum
Source: https://docs.livepeer.org/v1/orchestrators/guides/migrate-to-arbitrum
This guide provides instructions for the one-time migration from the L1 Ethereum
Mainnet to the L2 Arbitrum Mainnet, as per the
[Livepeer Confluence upgrade](https://medium.com/livepeer-blog/the-confluence-upgrade-is-live-3b6b342ea71e).
This guide is designed for node operators who have not yet upgraded to a
Livepeer version `>=0.5.28`, connecting to Arbitrum Mainnet after the
`LIP-73 block`.
## Prerequisites for all chains
* Your connected Ethereum account should have enough ETH to cover gas for the
`migrate` transaction.
If you do not have ETH in your wallet, you can add some using another wallet
or an on-ramp so you can buy enough for the `migrate` transaction.
* You can complete the migration using the
[Livepeer Explorer](https://explorer.livepeer.org/migrate).
Alternatively, you may opt to sign a typed data message via `livepeer_cli`,
instead.
* Ensure you are interacting with the correct contracts. Addresses can be found
[here](/v1/references/contract-addresses).
* **If you use a contract account rather than an EOA**: You will need to
interact directly with the Migrator contract methods following the
[Contract Wallet Migration](/v1/orchestrators/guides/migrate-from-contract-wallet)
guide.
If you are not familiar with this, it may not apply to you.
* Use a `go-livepeer`
[release](https://github.com/livepeer/go-livepeer/releases) `>= 0.5.28`.
* To register your Orchestrator on the destination chain,
[bridge some ETH](https://bridge.arbitrum.io/) to pay for the transaction.
## On Mainnet
This guide applies to orchestrators who registered on-chain on the Ethereum
mainnet prior to February 14th, 2022. It can be used starting on February 14th,
2022 onward.
Once you have successfully completed the migration, this guide is no longer
applicable and you will use Arbitrum in lieu of Ethereum for all protocol
actions.
Before starting the migration process, you will need to acquire an `RPC url` for
Arbitrum:
* [Set up an Arbitrum node](https://developer.offchainlabs.com/docs/running_node),
or
* Acquire an Arbitrum `RPC url` using a third-party service (e.g.,
[Alchemy](https://www.alchemy.com/) or [Infura](https://infura.io/)).
## On Testnet
This guide is applicable to orchestrators who registered on-chain on Rinkeby
prior to January 24th, 2022.
**Note:** Once you have successfully completed the migration, this guide is no
longer applicable and you will use Arbitrum Rinkeby in lieu of Rinkeby for all
protocol actions.
Before starting the migration process, you will need to acquire an `RPC url` for
Arbitrum. We recommend using
[the Offchain Labs public testnet endpoint](https://developer.offchainlabs.com/docs/public_testnet).
Alternatively, you can:
* [Set up an Arbitrum node](https://developer.offchainlabs.com/docs/running_node),
or
* Acquire an Arbitrum `RPC url` using a third-party service,
> **For example:**
>
> * [Alchemy](https://www.alchemy.com/), or
> * [Infura](https://infura.io/)
## Migrating to Arbitrum
1. Connect your wallet
If you have not connected a wallet, connect one using the prompt in the upper
left-hand corner of the Livepeer Explorer.
The wallet you choose should contain a small amount of ETH to pay for the
`migrate` transaction.
> **Note:** You do not have to use the same wallet you use for your
> orchestrator. However, if you are using a different wallet to submit the
> transaction, you will still need to access the wallet that you use for your
> orchestrator so that you can sign a typed data message.
**For example:**
2. Navigate to the L2 Migration Tool to begin migration to Arbitrum:
3. Sign the `migrate` transaction:
You can sign to authorize the migration transaction with one of the
following:
4a. Sign using a connected wallet.
If you prefer to sign using the wallet that you have connected to the
explorer, click "Approve Migration" and approve the transaction using your
browser extension.
4b. Sign using the `livepeer_cli`.
If you prefer to sign a typed data message through the `livepeer_cli`,
connect your wallet to the explorer with any other account. You will be
prompted to enter the public address of the orchestrator you wish to migrate.
> **Note:** If you are signing with the CLI and your connected wallet is NOT
> your orchestrator wallet, the stake amount will not appear until after you
> enter your Ethereum account address.
Once you have entered an address, you will see a message to sign and a text
entry box for the signature.
* Copy the message provided. Then go into your CLI and select option 19: Sign
Typed Data.
* Follow the CLI's prompts to generate a signature.
**Note:** For `Windows` users, after pasting the typed data you will need to
type `ctrl+Z`, instead of `ctrl+D`.
* Paste this message in the provided box and click Continue.
* Click `Approve Migration` to send the transaction to Ethereum. The connected
browser wallet will pay gas, but it will use the provided signature.
4. View your profile:
Once the `migrate` transaction has been confirmed (this usually takes up to
10 minutes between mainnet and Arbitrum), you should see a link to your
profile where you will be able to see your newly claimed balances.
You will see an [Arbiscan](https://arbiscan.io/) link to the `transaction id`
to view the submitted transaction.
5. Restart your Orchestrator, pointing at Arbitrum instead of mainnet as
follows:
5a. Find your Arbitrum RPC Url
> **Note:** If you prefer to run your own Arbitrum node, you should start it
> at this time. Otherwise, you should find the Arbitrum RPC Url that you
> created at the beginning of this guide.
5b. Restart your Orchestrator with an updated configuration
Once you are ready, you should restart your orchestrator using your usual
flags, changing only the `network` and `ethUrl`.
**Error Note:** If you're running on the same machine as your mainnet
Orchestrator, you may encounter an **error**:
**For example:**
You were expecting `chainID of 4`, but got `421611` instead. You may have
changed networks without changing `network name` or `datadir`.
This indicates your testnet setup is trying to access the same `.lpData` that it
used for mainnet, and it is finding a conflict on `chainId`.
**To fix this error:**
* Specify a new data directory using the `-datadir` flag when you start your
Orchestrator. Specify only the directory, not the file.
Additionally, you may need to copy your keystore to
`/.lpData/arbitrum-one-< mainnet / rinkeby >/keystore`.
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
livepeer \
-network arbitrum-one-mainnet # testnet: arbitrum-one-rinkeby
-ethUrl # testnet: arbitrum rinkeby RPC url
```
6. Register your service URI and fee structure on Arbitrum using
`Set orchestrator config`:
To receive work, you must register your service URI and fees so that gateways
can discover your orchestrator.
\> 6a. Select the following option using `livepeer_cli`:
`13: Set orchestrator config`
\> 6b. Acquire some `arbETH` to pay for the transaction:
* Use the [Arbitrum bridge](https://bridge.arbitrum.io) to send Ethereum on
Layer 1, to Arbitrum on Layer 2, over the appropriate (i.e. Mainnet or
Rinkeby) network.
Once this is complete, you are all set to receive work, rewards, and fees on
Arbitrum.
**Note:** In the future, you'll be prompted to connect to the Livepeer Explorer
using Arbitrum, and all future rewards and fees will accrue to Arbitrum rather
than Ethereum.
# Monitor Metrics
Source: https://docs.livepeer.org/v1/orchestrators/guides/monitor-metrics
This guide provides instructions on configuring metrics monitoring for
orchestrators that have been
[activated](/orchestrators/guides/get-started#activate) on the Livepeer network.
* Enable Metrics Monitoring
* Monitor with visualizations
* Prometheus
* Grafana
* Monitor with Docker
You can refer to [Prometheus
Metrics](/references/go-livepeer/prometheus-metrics) to check what metrics are
exposed.
## Enabling Metrics Monitoring
You can enable metrics monitoring with `livepeer.exe` adding the `-monitor` flag
and additional parameters:
* `-monitor`: enables metric monitoring
* `-metricsPerStream`: groups performance metrics per stream
* `-metricsClientIP`: exposes client's IP in metrics
**For Example:**
Enable metrics monitoring with a combined orchestrator and transcoder:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
livepeer \
-orchestrator \
-transcoder \
-monitor
```
For the purpose of this example, other flags have been omitted.
## Monitoring With Prometheus and Grafana
Follow the instructions in this
[monitoring guide](https://forum.livepeer.org/t/guide-transcoder-monitoring-with-prometheus-grafana/1225)
to learn how metrics recorded by `livepeer` can be:
* Exported to [Prometheus](https://prometheus.io/), and
* Visualized in [Grafana](https://grafana.com/)
## Monitoring with Docker
You can use this
[Docker container](https://github.com/livepeer/livepeer-monitoring) to easily
start monitoring your orchestrator or transcoder. It bundles Prometheus,
Grafana, and a few starter Grafana dashboard templates.
# Connect to Transcoders
Source: https://docs.livepeer.org/v1/orchestrators/guides/o-t-split
In this guide we'll go over how to connect multiple transcoding processes to a
single orchestrator.
## Run a standalone orchestrator
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
livepeer \
-network arbitrum-one-mainnet \
-ethURL \
-orchestrator \
-orchSecret \
-pricePerUnit \
-serviceAddr
```
* `-orchSecret` is used to specify a secret that transcoders can use to connect
with the orchestrator. The secret can be provided in plaintext or via a file
(recommended) i.e. `-orchSecret secret.txt`
## Run a standalone transcoder
The following instructions assume that the transcoder is run on a separate
machine from the orchestrator. These instructions can be used to connect as many
transcoders as you want to the orchestrator.
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
livepeer -transcoder \
-nvidia \ # Only required for transcoding with Nvidia GPUs
-orchSecret \
-orchAddr
```
* The value for `-orchSecret` should be the same as the value used for your
orchestrator
* `-orchAddr` is used to specify the publicly accessible address that the
orchestrator is receiving transcoder registration requests at
On startup, the transcoder will automatically run a test to confirm that it is
able to transcode using the specified GPUs. The transcoder will exit if this
test fails. If the test passes, you should see the following message in the log
output without any additional error messages following it indicating that your
transcoder successfully connected with the orchestrator:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
Registering transcoder to my-orchestrator.com:443
```
When the orchestrator receives a connection from a transcoder, you will see a
message in the orchestrator logs that looks like:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
Got a RegisterTranscoder request from transcoder=10.3.27.1 capacity=10
```
The `transcoder` field indicates the IP of the connecting transcoder and the
`capacity` field indicates the number of simultaneous transcoding jobs that the
transcoder can handle. Once the orchestrator has at least one transcoder
connected, it will be able to send transcoding jobs to the transcoder when it
receives a stream from a gateway.
# Set Pricing
Source: https://docs.livepeer.org/v1/orchestrators/guides/set-pricing
In this guide we'll go over how to set and configure pricing to charge for
transcoding advertised to gateways off-chain.
# Setting WEI Price
## Choose a Price
To charge for transcoding orchestrators set a price per pixel denominated in Wei
(1 ETH = 1e18 Wei), advertised to gateways off-chain.
To get support for setting a price that will allow you to receive work on the
network, contact us on our [Discord](https://discord.gg/livepeer) channel.
## Configure Automatic Price Adjustments
The default behavior of orchestrators is to automatically adjust their
advertised price per pixel based on the estimated overhead for redeeming a
ticket. The overhead for redeeming a ticket is the estimated transaction cost of
the redemption transaction divided by the face value of the ticket represented
as a percentage. For example, given a base price per pixel of 1000 wei:
* If the overhead is 1%, the advertised price would be 1010 wei
* If the overhead is 20%, the advertised price would be 1200 wei
* If the overhead is 50%, the advertised price is 1500 wei
The motivation for this automatic price adjustment mechanism is to allow
orchestrators to dynamically adjust their price to compensate for higher
overheads for ticket redemptions when gas prices are high.
Orchestrators can disable this mechanism and advertise a constant price by
setting the `-autoAdjustPrice=false` flag.
## Set a Price With `livepeer_cli`
You can set the base price per pixel using the `livepeer_cli`:
1. Run `livepeer_cli`
2. Enter the number corresponding to the `Set orchestrator config` option
3. You will get prompted to enter values for several fields.
If you only want to set the price, you can continue using the existing default
values.
4. You will get prompted for the price per pixel:
5. Set the number of pixels in a single unit of work you will charge for.
**For example:**
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
Enter a transcoding base price in wei per pixels
eg. 1 wei / 10 pixels = 0,1 wei per pixel
Enter the number of pixels that make up a single unit (default: 1 pixel):
```
The Default setting `option (1)` is typically used.
6. Set the price (in wei) that you will charge per unit of work:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
Enter the price for 1 pixel in Wei (required):
```
7. To verify the price was updated, check the log from your node.
# Setting fiat-denominated price
With the release of go-livepeer version 0.8.0, we are introducing a feature to
allow specifying the transcoding price per pixel in USD. This is a
backward-compatible change, which still supports setting the price in Wei but
now gives the option of using custom currencies instead, with USD being the
default.
The feature works by integrating with a
[Chainlink Price Feed](https://docs.chain.link/data-feeds/price-feeds) to fetch
the quote of the given currency and periodically update the transcoding price on
the running node. This is meant to be performed both in Bs and Os, keeping the
price over the network consistent over time.
## Configuration
To set a price in USD, one just needs to add the `USD` suffix to the value
provided in the `-pricePerUnit` flag sent to the `livepeer` binary. If the
currency suffix is missing, it will default to Wei to keep
backward-compatibility.
Given the price per pixel in USD is going to be a really low number, the
recommendation is to also set the `-pixelsPerUnit` flag so a more human-friendly
number can be specified on the price per unit. The `-pixelsPerUnit` acts as a
denominator on the `-pricePerUnit` and the recommendation is to keep it constant
over time, updating only the price per unit as seen fit.
e.g.:
* To set a price of **\$4.10 E -13**
```jsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
-pixelsPerUnit 1e12 \
-pricePerUnit 0.41USD
```
* To set a price of **\$6.65 E -14**
```jsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
-pixelsPerUnit 1e12 \
-pricePerUnit 0.0665USD
```
Notice that the `-pixelsPerUnit` flag supports the exponential notation, so it’s
easier to understand the value being set. The `-pricePerUnit` does not support
it though, so a standard decimal notation must be used. This is also an
incentive to use the `-pixelsPerUnit` value in order to keep the `-pricePerUnit`
as an easily readable value.
This feature is also supported by gateways, with the `-pixelsPerUnit` flag
staying the same, while the `-maxPricePerUnit` should be set instead for the max
price. The currency is specified in the same format.
### Advanced
The `livepeer` binary is automatically configured with the ETH/USD price feed in
the Arbitrum mainnet. If you are running the node on a different network or
would like to use a different currency to peg the price to, you should configure
the `-priceFeedAddr` with the address of the corresponding price feed. You can
search for existing price feed addresses on
[Chainlink website](https://docs.chain.link/data-feeds/price-feeds/addresses?network=ethereum\&page=1).
Notice that the price feed must have both `ETH` and your desired currency in the
quote pair. You should then specify the price per unit with the currency suffix
corresponding to the currency provided by the price feed.
e.g.
* To use `USD` as the price currency in Ethereum mainnet:
```jsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
-priceFeedAddr 0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419 \
-pricePerUnit 1USD
```
* To use `BTC` as the price currency on Arbitrum mainnet:
```jsx theme={"theme":{"light":"github-light","dark":"dark-plus"}}
-priceFeedAddr 0xc5a90A6d7e4Af242dA238FFe279e9f2BA0c64B2e \
-pricePerUnit 1BTC
```
The `-pixelsPerUnit` flag is independent of this. Also keep in mind that while
custom currencies are supported, Livepeer Studio will be pegging their
`-maxPricePerPixel` to USD so the recommendation is to also keep the default USD
configuration on your node to stay in sync with the rest of the network.
# Set Session Limits
Source: https://docs.livepeer.org/v1/orchestrators/guides/set-session-limits
This guide provides instructions on setting session limits to manage transcoding
capacity. You will be able to maximize work received while also protecting
against performance degradation due to overload. Once you have completed the
benchmark transcoding via the `livepeer_bench` tool and the
[common output rendition configuration](https://github.com/livepeer/go-livepeer/blob/master/cmd/livepeer_bench/transcodingOptions.json)
`transcodingOptions.json` you stored during the benchmarking, you can work with
this guide to fine tune your configuration:
* Calculate session limits
* Evaluate hardware capacity
* Benchmark transcoding for a range of concurrent sessions
* Evaluate bandwidth
* Derive a session limit
* Set session limits
It is recommended you complete the steps in [benchmark
transcoding](/orchestrators/guides/benchmark-transcoding) guide before
proceeding.
## Session Limits
The **default limit of concurrent sessions is set to 10**. When this limit is
exceeded, the orchestrator returns an error, `OrchestratorCapped`, to the
gateway and transcoders and they will stop receiving work from orchestrators.
The session limit should then be set depending on available hardware and
bandwidth.
## Calculating session limits
The session limit is an estimate and may require adjustments after running live
on the network.
The bandwidth and computational power needed to transcode a video stream varies
with the source video and requested output configuration.
Session limits are passed through the `-maxSessions` parameter to the node where
they should be set based on taking the minimum of:
* Transcoding Hardware, and
* Bandwidth
## Set Session Limits
The following steps require that incoming streams are configured with the common
web video streaming Adaptive Bitrate (ABR) ladder on the Livepeer network.
Session limits can be similarly calculated for a different ABR ladder.
1. Evaluate hardware
The recommendation for determining a hardware level limit is to use the
concurrent sessions value of the last log indicating that the real-time
duration ratio `X` was less than or equal 0.8. This leaves a \~20% buffer for
upload/download within real-time.
* You can use the following script with the `livepeer_bench` tool to benchmark
transcoding for a range of concurrent sessions:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
#!/bin/bash
for i in {1..20}
do
./livepeer_bench \
-in bbb/source.m3u8 \
-transcodingOptions transcodingOptions.json \
-nvidia 0 \ # Only required for transcoding with Nvidia GPUs
-concurrentSessions $i |& grep "Duration Ratio" >> bench.log
done
```
* Transcoding with multiple identical Nvidia GPUs:
Benchmarking with a single GPU should suffice and then you can multiply the
limit for a single GPU by the number of available GPUs. If you are transcoding
multiple different Nvidia GPUs, you should benchmark each unique GPU and
determine a limit that is specific to that GPU.
* Adjust the loop range (`{1..20}`) to reflect the maximum number of concurrent
sessions you want to benchmark. If at 20 maximum concurrent sessions real-time
duration is still below 1.0, you should increase the maximum number of
concurrent sessions.
* View the final output in a file called `bench.log`.
**For Example:**
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
| * Real-Time Duration Ratio * | | // Concurrent Session Count 1
| * Real-Time Duration Ratio * | | // Concurrent Session Count 2
...
| * Real-Time Duration Ratio * | | // Concurrent Session Count 20
```
If you are transcoding with a CPU, you will likely want to lower the value of
the maximum number of concurrent sessions (i.e. 5).
2. Evaluate bandwidth
The most
[common output rendition configuration](https://github.com/livepeer/go-livepeer/blob/master/cmd/livepeer_bench/transcodingOptions.json)
found on the network is (assuming source is `1080p30fps`):
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
+------------------------+----------+
| Resolution & Fps | Bitrate |
+========================+==========+
| 1080p30fps | 6000kbps |
+------------------------+----------+
| 720pfps | 3000kbps |
+------------------------+----------+
| 480pfps | 1600kbps |
+------------------------+----------+
| 360pfps | 800kbps |
+------------------------+----------+
| 240pfps | 250kbps |
+------------------------+----------+
```
A single stream requires an approximation of:
* *Download Bandwidth* = **6 Mbps** Per Stream. This is about 6000 kbps for
downloading the source rendition.
* *Upload Bandwidth* = **5.6 Mbps** Per Stream. This is about 5600 kbps for
uploading the output rendition.
* To estimate the number of streams you can process, divide the above from your
network provider's limits.
**For example:**
A typical broadband connection with `upstream/downstream` speed of `100 Mbps`
should reliably be able to serve/process \~16 streams.
However, as not all streams' segments may be processed at the same time, you may
be able to extend this by an additional \~20%.
[Bandwidth requirements](/references/go-livepeer/bandwidth-requirements)
provides further information about testing your available upload/download
bandwidth.
3. Derive a session limit based on hardware and bandwidth
Once you have calculated a hardware level limit and a bandwidth level limit, the
minimum of the two can be used as your session limit. This is set via the
`-maxSessions` flag.
Session management in orchestrators and transcoders is still constantly being
improved. Your mileage may vary with this approach; you may find that your
orchestrator or transcoder performance may be affected with a higher session
limit.
Further adjusting the session limit values after performing work on the network
may be necessary.
4. Set session limits
The `-maxSessions` flag is used to set session limits on both orchestrators and
transcoders.
**For Example:**
For a combined orchestrator and transcoder, set the session limit to 30:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
livepeer \
-orchestrator \
-transcoder \
-maxSessions 30
```
# Troubleshoot
Source: https://docs.livepeer.org/v1/orchestrators/guides/troubleshoot
This page contains troubleshooting advice for video miners and lists some of the
most common issues that a video miner might encounter.
## OrchestratorCapped error
This error means that your orchestrator has hit its session limit so it is not
longer accepting work from gateways. See the
[session limit guide](/orchestrators/guides/set-session-limits) for information
on setting the session limit.
## Cannot allocate memory error
If this error occurs on startup when using the `-nvidia` flag, the transcoding
test using the Nvidia GPUs likely failed because it hit the maximum number of
video encoding/decoding sessions supported on a single GPU. Different Nvidia
GPUs have different limits (if any) - more information can be found on
[this page](https://developer.nvidia.com/video-encode-and-decode-gpu-support-matrix-new)
and by searching for "nvenc nvdec session limit" online.
## insufficient funds for gas \* price + value error
This error means that the node attempted to submit a transaction, but its
account did not have enough ETH available for the transaction. You should add
more ETH to your account in order to submit the transaction.
## Transcode loop timed out and Segment loop timed out logs
These logs indicate that a session that was previously being used to transcode a
stream was cleaned up because no segments were received for awhile. These are
not errors and are expected to show up.
## MB rate > Level limit warning
This is a warning about the source video segment being transcoded (see this
[page](https://en.wikipedia.org/wiki/Advanced_Video_Coding#Levels) for more
technical details), but typically should not impact operation as long as
transcoding completes.
## Unable to transcode errors
These errors occur when a source video segment with certain properties that
prevent it from being transcoded. There are no actionable steps for an operator
in this scenario since the gateway is responsible for sending video segments
that are supported by the Livepeer network.
## My node is still calling the reward claims function and spending gas, even though I have set `reward` to false
Make sure to add `-reward=false` as an override in the launch command, even if
using a `.conf` file. Also make sure that if you have Orchestrator and
Transcoder processes running separately that all launch commands have `reward`
set to false. To be safe, you can also remove the `ethUrl` option from the
Transcoder process(es) to ensure that they are not performing any onchain
actions on behalf of your orchestrator if using the same wallet.
## TicketParams expired
This error indicates that the gateway sent a payment ticket with too old
parameters. This may be caused by the gateway's delay (between getting the last
orchestrator info message and sending the segment) or by the delay in polling
chain blocks (the expiration time is measured in L1 blocks). For more details
please check
[TicketParams expiration time](https://github.com/livepeer/go-livepeer/issues/1343).
There are no actionable steps for an operator, gateway will retry a request with
the updated ticket parameters.
## Error creating Ethereum account manager
This error means that Livepeer was not able to fetch your ETH account (or create
a new one). Livepeer stores ETH accounts in the `/keystore/` directory
(by default `~/.lpData//keystore/`).
Please make sure that one of the files in that directory contains the account
you specified with the `-ethAcctAddr` parameter. If you used another `datadir`
(or different `network`) in the past, you may need to copy the your keystore
files.
Please also make sure that your `keystore` directory has correct file
permissions.
## Unsupported input pixel format
This error occurs when someone submits a stream with an unsupported pixel
format. There are no actionable steps, the video of this format cannot be
transcoded in Livepeer.
## Common Questions
**What does being ‘publicly accessible’ mean? Can I run a transcoder from
home?**
Orchestrators should be reachable by gateways via the public IP and port that is
set during registration. The only port that is required to be public is the one
that was set during registration (default 8935). Be aware that there are many
risks to running a public server. Only set up an orchestrator if you are
comfortable with managing these risks.
Orchestrators will not be able to serve the Livepeer network if they are behind
a NAT (eg, a home router). If this is the case, special accommodations must be
made for the transcoder, such as port forwarding or putting the orchestrator in
the DMZ. The only port that is required to be public is the one that was set
during the orchestrator registration step (default 8935). Be aware that there
are many risks to running a public server. Only set up an orchestrator if you
are comfortable with managing these risks.
**Can I run an orchestrator from home?**
Running an orchestrator at home likely means that you will be behind a NAT (i.e.
a home router). This is generally not recommended. But, if you do choose to do
so, special accommodations will need to be made for the orchestrator such as
port forwarding or putting the orchestrator in the DMZ.
Some orchestrators in the past have used
[hairpinning](https://en.wikipedia.org/wiki/Hairpinning) by:
* Adding a second rule to the SNAT chain like:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
13119 786268 DNAT tcp -- * * 0.0.0.0/0 tcp dpt:8935 to:10.0.0.10
2 120 SNAT tcp -- * * 10.0.0.10 10.0.0.10 to:
```
* Running a command like:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
iptables -t nat -A POSTROUTING -p tcp -s 10.0.0.10 -d 10.0.0.10 -j SNAT --to-source
```
**What is the service URI? Does this need to be an IP?**
The service registry acts as a discovery mechanism to allow gateways to look up
the addresses of orchestrators on the network. Orchestrators register their
service URI by storing it on the blockchain. During registration you are only
asked for your IP:port, but the URI stored on the blockchain in the form of .
Orchestrators are expected to provide a consistent and reliable service, so IPs
here should remain static. However, a host (DNS) name is also allowed for the
service URI to give some flexibility.
**What does this error mean? “Service address [https://127.0.0.1:4433](https://127.0.0.1:4433) did not
match discovered address [https://127.1.5.10:8935](https://127.1.5.10:8935); set the correct address in
livepeer\_cli or use -serviceAddr”**
When starting up, the orchestrator checks if the current public IP matches the
IP that is stored on the blockchain. If there is a mismatch, there is a
possibility that your node is not publicly accessible. Override the locally
inferred IP address by setting `-serviceAddr IP:port` to what is stored on the
blockchain. Ensure your node is actually accessible at that address.
**How do I know if my node is transcoding?**
If you set the `-v 6` flag when starting `livepeer`, more verbose logs
indicating transcoding activity will be available. You can also setup
[metrics monitoring](/orchestrators/guides/monitor-metrics).
**How do I keep a record of my node's logs?**
By default, `livepeer` will only send logs to stdout so they can be shown in
your terminal. However, a tool such as
[tee](https://linuxize.com/post/linux-tee-command/) can be used to pipe the logs
to both stdout and a log file.
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
livepeer ... 2>&1 | tee livepeer.log
```
# Vote on proposals
Source: https://docs.livepeer.org/v1/orchestrators/guides/vote
Follow the steps below to set and configure voting in governance polls with
`livepeer_cli`. You can do this without exporting keys from the machine on which
the orchestrator node is running.
## Voting With the `livepeer_cli`
Follow the steps herein to access and vote with the `livepeer_cli`:
1. Find the contract address for the poll in the
[Livepeer Explorer](https://explorer.livepeer.org/voting) page for the poll.
The poll page displays the following message:
Click the link, "Follow these instructions", to display the instructions for
voting with `livepeer_cli`:
It is important to note the poll contract address for upcoming steps.
2. Run `livepeer_cli`
3. Enter the number corresponding to the option to `Vote on a poll`
4. Enter the contract address saved in step 1.:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
Enter the contract address for the poll you want to vote on - >
```
You will be prompted with the following voting options:
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
Identifier Voting Options
0 Yes
1 No
```
5. Choose and confirm your vote
**For example:**
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
Enter the ID of the option you want to vote for - > 0
Are you sure you want to vote "Yes" ? (y/n) - > y
success
```
6. Wait for the transaction to be confirmed. You should be able to view your
node submitting the vote transaction.
**For example:**
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
I0422 03:30:44.191809 43457 backend.go:96]
******************************Eth Transaction******************************
Invoking transaction: "vote". Inputs: "_choiceID: 0" Hash: "0xf6957c190f1f16fc2ca4a93846903eb435c5e08fa7f6f40b6e159aab6d74905f".
**************************************************************************
```
7. Once the vote transaction is confirmed, you will be able to see your vote
reflected in the explorer poll page of the UI.
# API Support Matrix
Source: https://docs.livepeer.org/v1/references/api-support-matrix
## On Demand
### Inputs
Currently, only file sizes up to 30GB are supported.
#### Video
| Container | Video codecs supported with container |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| MPEG-4 (.mp4) | Uncompressed, AVC Intra 50/100, DivX/Xvid, H.261, H.262, H.263, AVC (H.264), HEVC (H.265), JPEG 2000, MPEG-2, MPEG-4 part 2, VC-1 |
| QuickTime (.mov). | Uncompressed, AVC Intra 50/100, DivX/Xvid, DV/DVCPRO, H.261, H.262, H.263, AVC (H.264), HEVC (H.265), JPEG 2000 (J2K), MJPEG, MPEG-2, MPEG-4 part 2, QuickTime Animation (RLE) |
| Audio Video Interleave (.avi) | Uncompressed, Canopus HQ, DivX/Xvid, DV/DVCPRO, MJPEG |
| Adobe Flash (.flv) | AVC (H.264), Flash 9 File, H.263 |
| Matroska (.mkv) | AAC, Dolby Digital (AC3), Dolby Digital Plus (EAC3), Opus, WMA, WMA2 |
| WebM (.webm) | VP8, VP9 |
| Advanced Systems Format (.wmv) | WMA, WMA2, WMA Pro |
#### Audio
| Container | Audio codecs supported with container |
| ------------------------------ | ----------------------------------------------------------------------------------------------------------- |
| MPEG-4 (.mp4) | AAC, Dolby Digital (AC3), Dolby Digital Plus (EAC3), PCM, WMA, WMA2 |
| QuickTime (.mov) | AAC, MP3, PCM |
| Audio Video Interleave (.avi) | Dolby Digital (AC3), Dolby Digital Plus (EAC3), Dolby E frames carried in PCM streams, MP3, MPEG Audio, PCM |
| Adobe Flash (.flv) | AAC |
| Matroska (.mkv) | AAC, Dolby Digital (AC3), Dolby Digital Plus (EAC3), Opus, WMA, WMA2 |
| WebM (.webm) | Opus, Vorbis |
| Advanced Systems Format (.wmv) | WMA, WMA2, WMA Pro |
#### Other Attributes
| Attribute | Notes |
| ---------- | ------------------------------------------------------------------------- |
| Resolution | Maximum resolution is \[8192]x\[4320] or \[4320]x\[8192] in portrait mode |
### Outputs
#### Video
| Container | Video codecs supported with container |
| ------------- | ------------------------------------- |
| MPEG-4 (.mp4) | AVC (H.264) |
| HLS | AVC (H.264) |
#### Audio
| Container | Audio codecs supported with container |
| ------------- | ------------------------------------- |
| MPEG-4 (.mp4) | AAC |
## Livestream
### Ingest Support
| attribute | notes |
| ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Location | Global |
| Ingest Format | RTMP, SRT (Beta) |
| Ingest Codec | H264 + AAC |
| Ingest Authentication | Webhook based |
| Encoder Software | Supported tested: OBS 25.0.8, ffmpeg 4.3, Streamaxia Supported untested: Xsplit, other versions of OBS and ffmpeg, other RTMP encoders, SRT encoders Unsupported: WebRTC |
| Framerate | Between 5fps and 60fps, passthrough or custom |
| GOP Size (Keyframe Interval) | Supported tested: Constant GOP, Variable GOP of 0.5s to 8s Supported untested: Xsplit, Other versions of OBS and ffmpeg, other RTMP encoders Unsupported: Variable GOP not within 0.5s to 8s |
### Transcoding Support
| attribute | notes |
| ------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| Location | Global |
| Codec | H264 + AAC |
| H264 Transcoding Profiles | Baseline, Main, High |
| FPS | Supported tested: 24, 25, 30, 60 fps, uniform across all renditions Supported untested: custom fps, uniform across all renditions |
| Resolution | Supported tested: Custom resolution up to 1080pSupported untested: Custom resolution up to 4k |
| Pixel format | YUV4:2:0 |
### Video Workflow Support
| attribute | notes |
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| On Demand upload format | MP4 |
| Live latency | 10-18 seconds with good RTMP ingest health, 2s segment size, and standard 3 seg buffering in player |
| Live output format | HLS playback URL (m3u8) |
| H264 Transcoding Profiles | Baseline, Main, High |
| Video players | Supported tested: Livepeer UI Kit Player, video.js, hls.js, safari/ios native player, Theoplayer; Supported untested: JWPlayer, android native, Shaka, Exo, Bitmovin, Brightcove |
| Video Delivery Location | Supported tested: EU, USSupported untested: Asia, South America, Australia, Africa |
| Livestream recording | Only available for paying users. HLS playback URL (m3u8) available 5 minutes after session ends. Livepeer.Studio stores recording and serves playback via CDN. There is no limit on recording length. |
| Recording output format | HLS playback URL (m3u8) |
| CDN delivery | CDN delivery is only available for paying users. |
| Non-CDN Delivery | Non-CDN delivery for free tier users is limited to 10 viewers per account. Free tier users will have transcoding limited to 240p after 30 free minutes. |
| Custom CDN | Only for custom pricing tier users. |
| Stream Status | active or inactive |
| Stream length | We can support streams up to 12 hours in length. Please reach out to [contact@livepeer.studio](mailto:contact@livepeer.studio) if you’re looking to run longer uninterrupted streams through Livepeer.Studio. |
| Scalability | 1000 concurrent streams across all users. Please contact us at [contact@livepeer.studio](mailto:contact@livepeer.studio) for additional capacity |
# Awesome Livepeer
Source: https://docs.livepeer.org/v1/references/awesome-livepeer
# Contract Addresses
Source: https://docs.livepeer.org/v1/references/contract-addresses
Look up current Livepeer protocol contract addresses across supported networks and deployed versions — Arbitrum One (active) and Ethereum Mainnet (legacy).
**This page is no longer maintained.** Contract addresses on this page may be outdated or incorrect.
The canonical, automatically verified contract addresses are at:
**[Livepeer Contract Addresses](/v2/about/resources/livepeer-contract-addresses)**
All addresses on the canonical page are verified on-chain weekly and updated automatically from the protocol's governor-scripts repository.
Addresses of deployed contracts of the Livepeer protocol on multiple networks.
## Current
### Arbitrum One
All contracts on Arbitrum One implement the Delta version of the protocol.
* **Governor**: [`0xD9dEd6f9959176F0A04dcf88a0d2306178A736a6`](https://arbiscan.io/address/0xD9dEd6f9959176F0A04dcf88a0d2306178A736a6)
* **Controller**: [`0xD8E8328501E9645d16Cf49539efC04f734606ee4`](https://arbiscan.io/address/0xD8E8328501E9645d16Cf49539efC04f734606ee4)
* **LivepeerToken**: [`0x289ba1701C2F088cf0faf8B3705246331cB8A839`](https://arbiscan.io/address/0x289ba1701C2F088cf0faf8B3705246331cB8A839)
* **Minter**: [`0xc20DE37170B45774e6CD3d2304017fc962f27252`](https://arbiscan.io/address/0xc20DE37170B45774e6CD3d2304017fc962f27252)
* **BondingManager (Proxy)**: [`0x35Bcf3c30594191d53231E4FF333E8A770453e40`](https://arbiscan.io/address/0x35Bcf3c30594191d53231E4FF333E8A770453e40)
* **BondingManager (Target)**: [`0x4bA7E7531Ab56bC8d78dB4FDc88D21F621f34BB4`](https://arbiscan.io/address/0x4bA7E7531Ab56bC8d78dB4FDc88D21F621f34BB4)
* **TicketBroker (Proxy)**: [`0xa8bB618B1520E284046F3dFc448851A1Ff26e41B`](https://arbiscan.io/address/0xa8bB618B1520E284046F3dFc448851A1Ff26e41B)
* **TicketBroker (Target)**: [`0xea1b0F6c8D158328a6e3D3F924B86A759F41465c`](https://arbiscan.io/address/0xea1b0F6c8D158328a6e3D3F924B86A759F41465c)
* **RoundsManager (Proxy)**: [`0xdd6f56DcC28D3F5f27084381fE8Df634985cc39f`](https://arbiscan.io/address/0xdd6f56DcC28D3F5f27084381fE8Df634985cc39f)
* **RoundsManager (Target)**: [`0x92d804Ed49D92438aEA6fe552BD9163aacb7E841`](https://arbiscan.io/address/0x92d804Ed49D92438aEA6fe552BD9163aacb7E841)
* **BondingVotes (Proxy)**: [`0x0B9C254837E72Ebe9Fe04960C43B69782E68169A`](https://arbiscan.io/address/0x0B9C254837E72Ebe9Fe04960C43B69782E68169A)
* **BondingVotes (Target)**: [`0x68AF80376Bc1CA0C25a83b28e5570E8c7bdD3119`](https://arbiscan.io/address/0x68AF80376Bc1CA0C25a83b28e5570E8c7bdD3119)
* **Treasury**: [`0xf82C1FF415F1fCf582554fDba790E27019c8E8C4`](https://arbiscan.io/address/0xf82C1FF415F1fCf582554fDba790E27019c8E8C4)
* **LivepeerGovernor (Proxy)**: [`0xcFE4E2879B786C3aa075813F0E364bb5acCb6aa0`](https://arbiscan.io/address/0xcFE4E2879B786C3aa075813F0E364bb5acCb6aa0)
* **LivepeerGovernor (Target)**: [`0xd2Ce37BCB287CaDc40647f567C2D3C4220901634`](https://arbiscan.io/address/0xd2Ce37BCB287CaDc40647f567C2D3C4220901634)
* **ServiceRegistry (Proxy)**: [`0xC92d3A360b8f9e083bA64DE15d95Cf8180897431`](https://arbiscan.io/address/0xC92d3A360b8f9e083bA64DE15d95Cf8180897431)
* **ServiceRegistry (Target)**: [`0x38093CDca43aeCd7bb474983519A246e93A3b0a7`](https://arbiscan.io/address/0x38093CDca43aeCd7bb474983519A246e93A3b0a7)
* **AIServiceRegistry (Target)**: [`0x04C0b249740175999E5BF5c9ac1dA92431EF34C5`](https://arbiscan.io/address/0x04C0b249740175999E5BF5c9ac1dA92431EF34C5) (detached from controller)
* **SortedDoublyLL**: [`0xC45f6918F7Bcac7aBc8fe05302b3cDF39776cdeb`](https://arbiscan.io/address/0xC45f6918F7Bcac7aBc8fe05302b3cDF39776cdeb)
* **PollCreator**: [`0x8bb50806D60c492c0004DAD5D9627DAA2d9732E6`](https://arbiscan.io/address/0x8bb50806D60c492c0004DAD5D9627DAA2d9732E6)
* **MerkleSnapshot**: [`0x10736ffaCe687658F88a46D042631d182C7757f7`](https://arbiscan.io/address/0x10736ffaCe687658F88a46D042631d182C7757f7)
* **DelegatorPool**: [`0xfdb06109032AD3671a8f14f5f2E78f4B9E81b567`](https://arbiscan.io/address/0xfdb06109032AD3671a8f14f5f2E78f4B9E81b567)
* **L2LPTDataCache**: [`0xd78b6bD09cd28A83cFb21aFa0DA95c685A6bb0B1`](https://arbiscan.io/address/0xd78b6bD09cd28A83cFb21aFa0DA95c685A6bb0B1)
* **L2LPTGateway**: [`0x6D2457a4ad276000A615295f7A80F79E48CcD318`](https://arbiscan.io/address/0x6D2457a4ad276000A615295f7A80F79E48CcD318)
* **L2Migrator (Proxy)**: [`0x148D5b6B4df9530c7C76A810bd1Cdf69EC4c2085`](https://arbiscan.io/address/0x148D5b6B4df9530c7C76A810bd1Cdf69EC4c2085)
* **L2Migrator (Target)**: [`0x93BB030735747708b4D33093A98d4c804Cd6B58C`](https://arbiscan.io/address/0x93BB030735747708b4D33093A98d4c804Cd6B58C)
### Ethereum Mainnet
The following contracts on Ethereum Mainnet implement the Delta version of the protocol:
* Governor
* LivepeerToken
* L1Escrow
* L1LPTDataCache
* L1LPTGateway
* L1Migrator
* BridgeMinter
Since the Confluence upgrade, the protocol has been deployed to Arbitrum One and all contracts on Ethereum Mainnet besides the above are paused.
* **Governor**: [`0xFC3CBed6A3476F7616CC70f078397700136eEBFd`](https://etherscan.io/address/0xFC3CBed6A3476F7616CC70f078397700136eEBFd)
* **Controller**: [`0xf96d54e490317c557a967abfa5d6e33006be69b3`](https://etherscan.io/address/0xf96d54e490317c557a967abfa5d6e33006be69b3)
* **LivepeerToken**: [`0x58b6a8a3302369daec383334672404ee733ab239`](https://etherscan.io/address/0x58b6a8a3302369daec383334672404ee733ab239)
* **Minter**: [`0x505F8c2ee81f1C6fa0D88e918eF0491222E05818`](https://etherscan.io/address/0x505F8c2ee81f1C6fa0D88e918eF0491222E05818)
* **BondingManager (Proxy)**: [`0x511bc4556d823ae99630ae8de28b9b80df90ea2e`](https://etherscan.io/address/0x511bc4556d823ae99630ae8de28b9b80df90ea2e)
* **BondingManager (Target)**: [`0x5FE3565dB7F1Dd8d6A9E968D45BD2Aee3836a1D4`](https://etherscan.io/address/0x5FE3565dB7F1Dd8d6A9E968D45BD2Aee3836a1D4)
* **TicketBroker (Proxy)**: [`0x5b1ce829384eebfa30286f12d1e7a695ca45f5d2`](https://etherscan.io/address/0x5b1ce829384eebfa30286f12d1e7a695ca45f5d2)
* **TicketBroker (Target)**: [`0x6F582E2bB19ac31D4B1e6eDD0c2eFEabD700f808`](https://etherscan.io/address/0x6F582E2bB19ac31D4B1e6eDD0c2eFEabD700f808)
* **RoundsManager (Proxy)**: [`0x3984fc4ceeef1739135476f625d36d6c35c40dc3`](https://etherscan.io/address/0x3984fc4ceeef1739135476f625d36d6c35c40dc3)
* **RoundsManager (Target)**: [`0xC89fE48382F8fda6992dC590786A84275bCD1C57`](https://etherscan.io/address/0xC89fE48382F8fda6992dC590786A84275bCD1C57)
* **ServiceRegistry (Proxy)**: [`0x406a112f3218b988c66778fd72fc8467f2601366`](https://etherscan.io/address/0x406a112f3218b988c66778fd72fc8467f2601366)
* **ServiceRegistry (Target)**: [`0x72d9dfa25f75a5f2c27b7336e643a559ae6aeb8e`](https://etherscan.io/address/0x72d9dfa25f75a5f2c27b7336e643a559ae6aeb8e)
* **GenesisManager**: [`0x3a9543d4767b2c914ea22fd0b07e17b0901aaebf`](https://etherscan.io/address/0x3a9543d4767b2c914ea22fd0b07e17b0901aaebf)
* **MerkleMine**: [`0x8e306b005773bee6ba6a6e8972bc79d766cc15c8`](https://etherscan.io/address/0x8e306b005773bee6ba6a6e8972bc79d766cc15c8)
* **MultiMerkleMine**: [`0x182ebf4c80b28efc45ad992ecbb9f730e31e8c7f`](https://etherscan.io/address/0x182ebf4c80b28efc45ad992ecbb9f730e31e8c7f)
* **SortedDoublyLL**: [`0x1a0b2ca69ca2c7f96e2529faa6d63f881655d81a`](https://etherscan.io/address/0x1a0b2ca69ca2c7f96e2529faa6d63f881655d81a)
* **Refunder**: [`0x780c98cbb0cc21d6617c05332bd5cf6f847c71c2`](https://etherscan.io/address/0x780c98cbb0cc21d6617c05332bd5cf6f847c71c2)
* **PollCreator**: [`0xBf824EDb6b94D9B52d972d5B25bCc19b4e6E3F3C`](https://etherscan.io/address/0xBf824EDb6b94D9B52d972d5B25bCc19b4e6E3F3C)
* **MerkleSnapshot**: [`0x24ebEd82c681f435E944BEEbFAEEAaE443D08438`](https://etherscan.io/address/0x24ebEd82c681f435E944BEEbFAEEAaE443D08438)
* **L1Escrow**: [`0x6A23F4940BD5BA117Da261f98aae51A8BFfa210A`](https://etherscan.io/address/0x6A23F4940BD5BA117Da261f98aae51A8BFfa210A)
* **L1LPTDataCache**: [`0x1d24838b35A9c138Ac157A852e19e948aD6323D7`](https://etherscan.io/address/0x1d24838b35A9c138Ac157A852e19e948aD6323D7)
* **L1LPTGateway**: [`0x6142f1C8bBF02E6A6bd074E8d564c9A5420a0676`](https://etherscan.io/address/0x6142f1C8bBF02E6A6bd074E8d564c9A5420a0676)
* **L1Migrator**: [`0x21146B872D3A95d2cF9afeD03eE5a783DaE9A89A`](https://etherscan.io/address/0x21146B872D3A95d2cF9afeD03eE5a783DaE9A89A)
* **BridgeMinter**: [`0x8dDDB96CF36AC8860f1DE5C7c4698fd499FAB405`](https://etherscan.io/address/0x8dDDB96CF36AC8860f1DE5C7c4698fd499FAB405)
## Historical (DEPRECATED — FOR REFERENCE ONLY)
### Arbitrum One
#### BondingManager (Target)
* **V1**: [`0xe479B9fbA2Cd65f822f451fC8C145c663B995CE6`](https://arbiscan.io/address/0xe479B9fbA2Cd65f822f451fC8C145c663B995CE6)
* **V2**: [`0xC40df4db2f99e7e235780A93B192F1a934f0c45b`](https://arbiscan.io/address/0xC40df4db2f99e7e235780A93B192F1a934f0c45b)
* **V3**: [`0x3757DB506ECd9CBE643660C0F5b70db5b321202C`](https://arbiscan.io/address/0x3757DB506ECd9CBE643660C0F5b70db5b321202C)
* **V4**: [`0x0f9C425E7374602C20370d3fd263155B4c3bDc91`](https://arbiscan.io/address/0x0f9C425E7374602C20370d3fd263155B4c3bDc91)
* **V5**: [`0x3a941e1094B9E33efABB26a9047a8ABb4b257907`](https://arbiscan.io/address/0x3a941e1094B9E33efABB26a9047a8ABb4b257907)
* **V6**: [`0x9c9209c9ff6996513b3673d69ee7b36a6c58a8cf`](https://arbiscan.io/address/0x9c9209c9ff6996513b3673d69ee7b36a6c58a8cf)
* **V7**: [`0x363cdB9BaE210Ef182c60b5a496139E980330127`](https://arbiscan.io/address/0x363cdB9BaE210Ef182c60b5a496139E980330127)
* **V8**: [`0x557093B1Ab53412166beAd939f34244170b6525B`](https://arbiscan.io/address/0x557093B1Ab53412166beAd939f34244170b6525B)
* **V9**: [`0x6b397f20DC227B4E23fEc20BBDBe166d0DFFC452`](https://arbiscan.io/address/0x6b397f20DC227B4E23fEc20BBDBe166d0DFFC452)
* **V10**: [`0xd1C1F5d44D8F83ca2A05Baf40461e550cFDDecA2`](https://arbiscan.io/address/0xd1C1F5d44D8F83ca2A05Baf40461e550cFDDecA2)
* **V11 (current)**: [`0x4bA7E7531Ab56bC8d78dB4FDc88D21F621f34BB4`](https://arbiscan.io/address/0x4bA7E7531Ab56bC8d78dB4FDc88D21F621f34BB4)
#### BondingVotes (Target)
* **V1**: [`0x1561fC5F7Efc049476224005DFf38256dccfc509`](https://arbiscan.io/address/0x1561fC5F7Efc049476224005DFf38256dccfc509)
#### TicketBroker (Target)
* **V1**: [`0x7Beb84c52ce96DFd90431FAA97378994a8baa6df`](https://arbiscan.io/address/0x7Beb84c52ce96DFd90431FAA97378994a8baa6df)
* **V2 (current)**: [`0xea1b0F6c8D158328a6e3D3F924B86A759F41465c`](https://arbiscan.io/address/0xea1b0F6c8D158328a6e3D3F924B86A759F41465c)
#### Minter
* **V1**: [`0x4969dcCF5186e1c49411638fc8A2a020Fdab752E`](https://arbiscan.io/address/0x4969dcCF5186e1c49411638fc8A2a020Fdab752E)
#### L2Migrator (Target)
* **V1**: [`0x4F59b39e2ea628fe8371BDfd51B063319339c7EE`](https://arbiscan.io/address/0x4F59b39e2ea628fe8371BDfd51B063319339c7EE)
### Ethereum Mainnet
#### LivepeerVerifier
* **V1**: [`0xf623811b08b45792d0223d77d9c922dae29712ec`](https://etherscan.io/address/0xf623811b08b45792d0223d77d9c922dae29712ec)
* **V2**: [`0xe4be2a35dec0063f9dfccb9b740b1acb7eefefec`](https://etherscan.io/address/0xe4be2a35dec0063f9dfccb9b740b1acb7eefefec)
#### Minter
* **V1**: [`0x8573f2f5a3bd960eee3d998473e50c75cdbe6828`](https://etherscan.io/address/0x8573f2f5a3bd960eee3d998473e50c75cdbe6828)
#### BondingManager (Target)
* **V1**: [`0x81eb0b10ff8703905904e4d91cf6aa575d59736f`](https://etherscan.io/address/0x81eb0b10ff8703905904e4d91cf6aa575d59736f)
* **V2**: [`0x5A9512826EAAF1FE4190f89443314E95A515fE24`](https://etherscan.io/address/0x5A9512826EAAF1FE4190f89443314E95A515fE24)
* **V3**: [`0x633101b3f15f93c5f415830d48e56b9b1f7ba584`](https://etherscan.io/address/0x633101b3f15f93c5f415830d48e56b9b1f7ba584)
* **V4**: [`0x05C03EA0039f2e828A725A82939fc1e90de38B44`](https://etherscan.io/address/0x05C03EA0039f2e828A725A82939fc1e90de38B44)
* **V5**: [`0xCBAa6eA4886b535FC7ABACe3F3985Ed03b3b80a0`](https://etherscan.io/address/0xCBAa6eA4886b535FC7ABACe3F3985Ed03b3b80a0)
* **V6**: [`0xDC6eE74A18994caD3876a078B6fa4920FD9C507d`](https://etherscan.io/address/0xDC6eE74A18994caD3876a078B6fa4920FD9C507d)
* **V7**: [`0x1a6007d1D0583452Bd6f45a4e1a9190B15Fbd7E3`](https://etherscan.io/address/0x1a6007d1D0583452Bd6f45a4e1a9190B15Fbd7E3)
* **V8**: [`0xef5E170b679ddaF5e22ADC10fD23DDdB79E3C0c5`](https://etherscan.io/address/0xef5E170b679ddaF5e22ADC10fD23DDdB79E3C0c5)
* **V9**: [`0xc8a695155648F18B0cfd6989498B6f8b2c4cc56A`](https://etherscan.io/address/0xc8a695155648F18B0cfd6989498B6f8b2c4cc56A)
* **V10**: [`0x35F99F326681FE4F38719491be48Ab4950795013`](https://etherscan.io/address/0x35F99F326681FE4F38719491be48Ab4950795013)
* **V11**: [`0xAC0153a8C5227e43506901a4f3f83FD000c8178f`](https://etherscan.io/address/0xAC0153a8C5227e43506901a4f3f83FD000c8178f)
* **V12**: [`0x246edEBae14b186a67e3d466A485321169a8bcD5`](https://etherscan.io/address/0x246edEBae14b186a67e3d466A485321169a8bcD5)
* **V13**: [`0x223398d0BF9cc24960b3886CC481dBf5276EdeD2`](https://etherscan.io/address/0x223398d0BF9cc24960b3886CC481dBf5276EdeD2)
* **V14**: [`0x0da7c263eCF5cD3ddba275b9A2D63320E28fD287`](https://etherscan.io/address/0x0da7c263eCF5cD3ddba275b9A2D63320E28fD287)
#### JobsManager (Proxy)
* **V1**: [`0xbf07ff45f14c9ff0571b9fbdc7e2b62d29931224`](https://etherscan.io/address/0xbf07ff45f14c9ff0571b9fbdc7e2b62d29931224)
#### JobsManager (Target)
* **V1**: [`0x68b463bca7d561118636e9f028ff0f2e8398dd6a`](https://etherscan.io/address/0x68b463bca7d561118636e9f028ff0f2e8398dd6a)
* **V2**: [`0xB620c762dd4bC350602936d7401BB8393Ee6687c`](https://etherscan.io/address/0xB620c762dd4bC350602936d7401BB8393Ee6687c)
* **V3**: [`0x8eade5eec609572bf53deadb88d36f862ddec517`](https://etherscan.io/address/0x8eade5eec609572bf53deadb88d36f862ddec517)
#### RoundsManager (Target)
* **V1**: [`0xa3aa52ce79e85a21d9ccda705c57e426b160112c`](https://etherscan.io/address/0xa3aa52ce79e85a21d9ccda705c57e426b160112c)
* **V2**: [`0x857d4bf18a80f03d3d11f438825cd3d0aa0d9d68`](https://etherscan.io/address/0x857d4bf18a80f03d3d11f438825cd3d0aa0d9d68)
#### MerkleProof
* **V1**: [`0x289ba1701c2f088cf0faf8b3705246331cb8a839`](https://etherscan.io/address/0x289ba1701c2f088cf0faf8b3705246331cb8a839)
#### ECRecovery
* **V1**: [`0xd8e8328501e9645d16cf49539efc04f734606ee4`](https://etherscan.io/address/0xd8e8328501e9645d16cf49539efc04f734606ee4)
#### JobLib
* **V1**: [`0x4969dccf5186e1c49411638fc8a2a020fdab752e`](https://etherscan.io/address/0x4969dccf5186e1c49411638fc8a2a020fdab752e)
# Example Applications
Source: https://docs.livepeer.org/v1/references/example-applications
Curated collection of Livepeer example applications and integrations
Enjoy a curated collection of Livepeer example applications and integrations.
Use these starter projects to build your own video applications.
| Example | Description |
| -------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| [React Native Example App](https://github.com/suhailkakar/Livepeer-YouTube) | Example application which demonstrates how to use Livepeer React to create a React Native YouTube clone. |
| [Justcast.it](https://github.com/victorges/justcast.it) | Web app that provides code for adding "1-click starting a livestream" so that you can create a stream using the Livepeer API. |
| [EVM Token-Gated Livestream](https://github.com/suhailkakar/Livepeer-EVM-Tokengating) | Example application which demonstrates how to create and tokengate a livestream using Livepeer on EVM compatible chains. |
| [Decentralized storage playback](https://github.com/suhailkakar/livepeer-dStorage-playback/) | Example application which demonstrates how to play back a video from decentralized storage such as IPFS and Arweave using Livepeer. |
# Bandwidth Requirements
Source: https://docs.livepeer.org/v1/references/go-livepeer/bandwidth-requirements
The bandwidth requirements for video miners are based on the amount of video
data that needs to be uploaded and downloaded during transcoding.
The amount of available bandwidth will not only impact the number of streams
that can be transcoded on a machine, but also the speed of data upload/download
which needs to be fast so that video streaming applications can receive
transcoded results as soon as possible.
The amount of bandwidth required for a stream will depend on the bitrate of the
source stream and the bitrate of the output renditions. The download bandwidth
required for a single stream can be roughly estimated as the bitrate of the
source stream. The upload bandwidth required for a single stream can be roughly
estimated as the sum of the bitrates of each of the output renditions for the
stream. As a result, the total number of streams that can be transcoded given a
certain amount of available of bandwidth will vary.
While there is not a strict bandwidth requirement for video miners, past testing
has demonstrated that 1G upload/download bandwidth is a good starting point if
possible. If you do not have access to this amount of bandwidth you will still
be able to transcode on the network, but you will have a lower ceiling on the
number of streams you will be able to handle.
Upload/download bandwidth available can be tested with tools such as:
* [speedtest](https://www.speedtest.net/apps/cli)
* By default the tool will run a bandwidth test against the closest public
server, but there is also an option to run the test against a specified
public server
* Note: The results of this test also depend on the available bandwidth on the
server used
* [iperf3](https://iperf.fr/)
* This tool can be run on client and server machines that you have access to
* If you have access to a machine with good bandwidth availability in a region
that you expect/want to receive streams from, then this tool will likely be
more useful than speedtest
# CLI Reference
Source: https://docs.livepeer.org/v1/references/go-livepeer/cli-reference
The `livepeer` binary in `go-livepeer` has a number of configurable options. You
can set your configuration using command-line flags, environment variables, or a
config file.
A comprehensive list of options can be found below. They are sourced and
regularly updated from
[this file](https://github.com/livepeer/go-livepeer/blob/master/cmd/livepeer/livepeer.go).
The
[go-livepeer developer docs](https://github.com/livepeer/go-livepeer/tree/master/doc)
also contain instructions for using flags to enable certain functionality in
`livepeer`.
## Options
### Configuration
* config: Path to config file.
### Network and Addresses
* network: Network to connect to. Default `offchain`
* rtmpAddr: Address to bind for RTMP commands. Default `127.0.0.1:+RtmpPort`
* cliAddr: Address to bind for CLI commands. Default `127.0.0.1:+CliPort`
* httpAddr: Address to bind for HTTP commands. No default
* serviceAddr: Orchestrator only. Overrides the on-chain serviceURI that
gateways can use to contact this node; may be an IP or hostname. No default
* orchAddr: Orchestrator to connect to as a standalone transcoder. No default.
* verifierURL: URL of the verifier to use. No default.
* verifierPath: Path to verifier shared volume. No default.
* localVerify: Set to true to enable local verification i.e. pixel count and
signature verification. Default `true`. However, if you are running in
offchain mode, this will be set to false.
* httpIngest: Set to true to enable HTTP ingest. Default `true`. However, if (1)
you do not provide a value, (2) you provide a non-local URL for `httpAddr`,
and (3) you do not provide an `authWebhookURL`, this will be set to false.
### Transcoding
* orchestrator: Set to true to be an orchestrator. Default `false`
* transcoder: Set to true to be an transcoder. Default `false`
* gateway: Set to true to be an gateway (formerly known as *Broadcaster*).
Default `false`
* orchSecret: Shared secret with the orchestrator as a standalone transcoder or
path to file
* transcodingOptions: Transcoding options for broadcast job, or path to json
config. Default `P240p30fps16x9,P360p30fps16x9`
* maxAttempts: Maximum transcode attempts. Default `3`
* selectRandFreq: Frequency to randomly select unknown orchestrators (on-chain
mode only). Default `0.3`
* maxSessions: Maximum number of concurrent transcoding sessions for
Orchestrator, maximum number or RTMP streams for Gateway, or maximum capacity
for transcoder. Default `10`
* currentManifest: Expose the currently active ManifestID as
"/stream/current.m3u8". Default `false`
* nvidia: Comma-separated list of Nvidia GPU device IDs (or "all" for all
available devices). No default
* testTranscoder: Test Nvidia GPU transcoding at startup. Default `true`
* sceneClassificationModelPath: Path to scene classification model. No default
### Onchain
* ethAcctAddr: Existing Eth account address. For use when multiple ETH accounts
exist in the keystore directory
* ethPassword: Password for existing Eth account address or path to file
* ethKeystorePath: Path to ETH keystore directory or keyfile. If keyfile,
overrides -ethAcctAddr and uses parent directory
* ethOrchAddr: address of an on-chain registered orchestrator. No default
* ethUrl: EVM-compatible chain node JSON-RPC URL. No default
* txTimeout: Amount of time (ms) to wait for a transaction to confirm before
timing out. Default `300000 (5 mins)`
* maxTxReplacements: Number of times to automatically replace pending
transactions. Default `1`
* gasLimit: Gas limit for ETH transaction. Default `0`
* minGasPrice: Minimum gas price (priority fee + base fee) for ETH transactions
in wei, 10 Gwei = 10000000000. If not set, this will be the network's default
min gas fee.
* maxGasPrice: Maximum gas price (priority fee + base fee) for ETH transactions
in wei, 40 Gwei = 40000000000. Default `0`
* ethController: Protocol smart contract address. No default
* initializeRound: Set to true if running as a transcoder and the node should
automatically initialize new rounds. Default false.
* ticketEV: The expected value for PM tickets. Default `1000000000000`
* maxTicketEV: The maximum acceptable expected value for PM tickets. Default
`3000000000000`
* depositMultiplier: The deposit multiplier used to determine max acceptable
faceValue for PM tickets. Default `1`
* pricePerUnit: The price per 'pixelsPerUnit' amount pixels. Must be greater
than 0. Error if not set.
* maxPricePerUnit: The maximum transcoding price (in wei) per 'pixelsPerUnit' a
gateway is willing to accept. If not set explicitly, gateway is willing to
accept ANY price. Default `0`
* pixelsPerUnit: Amount of pixels per unit. Set to '> 1' to have smaller price
granularity than 1 wei / pixel. Default `1`
* pricePerGateway: json list of price per gateway or path to json config file.
Example:
`{"gateways":[{"ethaddress":"address1","priceperunit":1000,"pixelsperunit":1},{"ethaddress":"address2","priceperunit":1200,"pixelsperunit":1}]}`
* autoAdjustPrice: Enable/disable automatic price adjustments based on the
overhead for redeeming tickets. Default `true`
* blockPollingInterval: Interval in seconds at which different blockchain event
services poll for blocks. Default `5`
* redeemer: Set to true to run a ticket redemption service. Default `false`
* redeemerAddr: URL of the ticket redemption service to use. No default
* reward: Set to true to run a reward service. If you do not want to
automatically call `reward()`, you need to explicitly set this to `false` for
any node that's registered onchain. Otherwise, it will default to true.
* monitor: Set to true to send performance metrics. Default `false`
* version: Print out the version. Default `false`
* v: Log verbosity - . No default
* metadataQueueUri: URI for message broker to send operation metadata. No
default
* metadataAmqpExchange: Name of AMQP exchange to send operation metadata.
Default `lp_golivepeer_metadata`
* metadataPublishTimeout: Max time (ms) to wait in background for publishing
operation metadata events. Default `1000 (1s)`
* maxFaceValue: Set the maximum face value of a ticket (in wei). No default
### Storage
* datadir: Directory that data is stored in. No default
* objectstore: URL of primary object store. No default
* recordstore: URL of object store for recodings. No default
### API
* authWebhookURL: RTMP authentication webhook URL. No default
* orchWebhookURL: Orchestrator discovery callback URL. No default
* detectionWebhookURL: (Experimental) Detection results callback URL. No default
# GPU Support
Source: https://docs.livepeer.org/v1/references/go-livepeer/gpu-support
Livepeer enables node operators to transcode video on GPUs while concurrently
mining cryptocurrencies and performing other CUDA operations such as machine
learning. As there is a very wide range of GPU hardware out there, this document
aims to crowdsource a list of specific GPU models that have been tested and
verified to work on Livepeer. If you've tested an additional model, please
submit an update to this document.
## Overview
* Livepeer supports transcoding on NVIDIA GPUs with NVENC/NVDEC. Any GPU
[listed here](https://developer.nvidia.com/video-encode-and-decode-gpu-support-matrix-new)
with those chips should theoretically work. Note that different models may be
subject to different session limits that restrict the amount of video that can
be transcoded.
* See
[this document which lists tested driver versions](https://github.com/livepeer/go-livepeer/blob/master/doc/gpu.md)
on the NVIDIA cards.
| GPU Model | Tested Transcoding | Tested Concurrent Ethash Mining | Notes | |
| ----------------------------- | ------------------ | ------------------------------- | ------------------------------------------------------------------------------------------------------ | - |
| NVIDIA GeForce GTX 950 | ✅ | | [Benchmarks](https://forum.livepeer.org/t/gtx-950-quadro-p400-benchmarks/1497) | |
| NVIDIA GeForce GTX 1060 | ✅ | ✅ | | |
| NVIDIA GeForce GTX 1070 | ✅ | | | |
| NVIDIA GeForce GTX 1070 Ti | ✅ | ✅ | | |
| NVIDIA GeForce GTX 1080 | ✅ | | | |
| NVIDIA GeForce GTX 1080 Ti | ✅ | | | |
| NVIDIA Tesla T4 | ✅ | | | |
| NVIDIA GeForce GTX 1660 Ti | ✅ | | | |
| NVIDIA GeForce GTX 1660 SUPER | ✅ | | | |
| NVIDIA GeForce GTX 2080 Ti | ✅ | ✅ | | |
| NVIDIA GeForce RTX 3080 | ✅ | ✅ | [Benchmarks](https://forum.livepeer.org/t/dual-ethash-mining-transcoding-w-rtx-3080-10g-cuda-mps/1161) | |
| NVIDIA GeForce GTX 3090 | ✅ | ✅ | | |
| NVIDIA Titan V | ✅ | ✅ | | |
| NVIDIA Quadro P400 | ✅ | | [Benchmarks](https://forum.livepeer.org/t/gtx-950-quadro-p400-benchmarks/1497) | |
| NVIDIA Quadro T600 | ✅ | | [Benchmarks](https://forum.livepeer.org/t/nvidia-quadro-t600-benchmark/1650) | |
# Hardware Requirements
Source: https://docs.livepeer.org/v1/references/go-livepeer/hardware-requirements
The hardware requirements for video miners are based on the computational
resources required for transcoding.
## GPU
A GPU with a built-in hardware video encoder/decoder is **strongly** recommended
because it will significantly speed up transcoding and it will be difficult to
compete for work in the marketplace without one. Transcoding capacity will scale
with the number of GPUs available.
Currently, `livepeer` only supports Nvidia GPUs with
[NVENC (hardware video encoder) and NVDEC (hardware video decoder) support](https://developer.nvidia.com/video-encode-and-decode-gpu-support-matrix-new).
For a list of of GPUs that have been tested and that are known to be supported
by `livepeer`, see [this page](/references/go-livepeer/gpu-support).
## CPU
CPU transcoding using a software video encoder/decoder is possible, but not
recommended due to its significant speed disadvantage relative to GPU
transcoding. If you choose to do CPU transcoding (perhaps to try things out or
as a temporary measure until a GPU is available), generally a CPU with more
cores will improve transcoding speed.
## RAM
TBD.
## Disk
TBD.
# Prometheus Metrics
Source: https://docs.livepeer.org/v1/references/go-livepeer/prometheus-metrics
Livepeer exposes a number of metrics via the Prometheus exporter. This page
documents all metrics that you can scrape via the `/metrics` endpoint when the
[monitoring is enabled](/orchestrators/guides/monitor-metrics).
## Livepeer metrics
### General
| Name | Description | Node Type |
| -------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | ------------------------------------------- |
| `livepeer_versions` | Versions used by Livepeer node. | Gateway, Orchestrator, Transcoder, Redeemer |
| `livepeer_segment_source_appeared_total` | SegmentSourceAppeared | Gateway |
| `livepeer_segment_source_emerged_total` | SegmentEmerged | Gateway |
| `livepeer_segment_source_emerged_unprocessed_total` | Raw number of segments emerged from segmenter. | Gateway, Orchestrator |
| `livepeer_segment_source_uploaded_total` | SegmentUploaded | Gateway, Orchestrator, Transcoder |
| `livepeer_segment_source_upload_failed_total` | SegmentUploadedFailed | Gateway |
| `livepeer_segment_transcoded_downloaded_total` | SegmentDownloaded | Gateway, Orchestrator |
| `livepeer_segment_transcoded_total` | SegmentTranscoded | Gateway, Orchestrator |
| `livepeer_segment_transcoded_unprocessed_total` | Raw number of segments successfully transcoded. | Gateway |
| `livepeer_segment_transcode_failed_total` | SegmentTranscodeFailed | Gateway |
| `livepeer_segment_transcoded_all_appeared_total` | SegmentTranscodedAllAppeared | Gateway |
| `livepeer_stream_created_total` | StreamCreated | Gateway |
| `livepeer_stream_started_total` | StreamStarted | Gateway |
| `livepeer_stream_ended_total` | StreamEnded | Gateway |
| `livepeer_max_sessions_total` | Max Sessions | Gateway, Orchestrator, Transcoder, Redeemer |
| `livepeer_current_sessions_total` | Number of streams currently transcoding | Gateway, Orchestrator |
| `livepeer_discovery_errors_total` | Number of discover errors | Gateway |
| `livepeer_transcode_retried` | Number of times segment transcode was retried | Gateway |
| `livepeer_transcoders_number` | Number of transcoders currently connected to orchestrator | Gateway, Orchestrator, Transcoder, Redeemer |
| `livepeer_transcoders_capacity` | Total advertised capacity of transcoders currently connected to orchestrator | Gateway, Orchestrator, Transcoder, Redeemer |
| `livepeer_transcoders_load` | Total load of transcoders currently connected to orchestrator | Gateway, Orchestrator, Transcoder, Redeemer |
| `livepeer_success_rate` | Number of transcoded segments divided on number of source segments | Gateway, Orchestrator, Transcoder, Redeemer |
| `livepeer_success_rate_per_stream` | Number of transcoded segments divided on number of source segments, per stream | Gateway |
| `livepeer_transcode_time_seconds` | TranscodeTime, seconds | Gateway, Orchestrator |
| `livepeer_transcode_overall_latency_seconds` | Transcoding latency, from source segment emerged from segmenter till all transcoded segment apeeared in manifest | Gateway |
| `livepeer_upload_time_seconds` | UploadTime, seconds | Gateway, Orchestrator, Transcoder |
| `livepeer_download_time_seconds` | Download time | Gateway, Orchestrator |
| `livepeer_auth_webhook_time_milliseconds` | Authentication webhook execution time, milliseconds | Gateway |
| `livepeer_source_segment_duration_seconds` | Source segment's duration | Gateway, Orchestrator |
| `livepeer_http_client_timeout_1` | Number of times HTTP connection was dropped before transcoding complete | Gateway |
| `livepeer_http_client_timeout_2` | Number of times HTTP connection was dropped before transcoded segments was sent back to client | Gateway |
| `livepeer_http_client_segment_transcoded_realtime_ratio` | Ratio of source segment duration / transcode time as measured on HTTP client | Gateway |
| `livepeer_http_client_segment_transcoded_realtime_3x` | Number of segment transcoded 3x faster than realtime | Gateway |
| `livepeer_http_client_segment_transcoded_realtime_2x` | Number of segment transcoded 2x faster than realtime | Gateway |
| `livepeer_http_client_segment_transcoded_realtime_1x` | Number of segment transcoded 1x faster than realtime | Gateway |
| `livepeer_http_client_segment_transcoded_realtime_half` | Number of segment transcoded no more than two times slower than realtime | Gateway |
| `livepeer_http_client_segment_transcoded_realtime_slow` | Number of segment transcoded more than two times slower than realtime | Gateway |
| `livepeer_transcode_score` | Ratio of source segment duration vs. transcode time | Gateway, Orchestrator |
| `livepeer_recording_save_latency` | How long it takes to save segment to the OS | Gateway |
| `livepeer_recording_save_errors` | Number of errors during save to the recording OS | Gateway |
| `livepeer_recording_saved_segments` | Number of segments saved to the recording OS | Gateway |
| `livepeer_orchestrator_swaps` | Number of orchestrator swaps mid-stream | Gateway |
### Sending payments
| Name | Description | Node Type |
| -------------------------------- | ---------------------------------------------- | --------- |
| `livepeer_ticket_value_sent` | Ticket value sent | Gateway |
| `livepeer_tickets_sent` | Tickets sent | Gateway |
| `livepeer_payment_create_errors` | Errors when creating payments | Gateway |
| `livepeer_gateway_deposit` | Current remaining deposit for the gateway node | Gateway |
| `livepeer_gateway_reserve` | Current remaining reserve for the gateway node | Gateway |
### Receiving payments
| Name | Description | Node Type |
| ----------------------------------- | -------------------------------------------------- | ------------------------------- |
| `livepeer_ticket_value_recv` | Ticket value received | Orchestrator |
| `livepeer_tickets_recv` | Tickets received | Orchestrator |
| `livepeer_payment_recv_errors` | Errors when receiving payments | Orchestrator |
| `livepeer_winning_tickets_recv` | Winning tickets received | Orchestrator |
| `livepeer_value_redeemed` | Winning ticket value redeemed | Orchestrator, Redeemer |
| `livepeer_ticket_redemption_errors` | Errors when redeeming tickets | Orchestrator, Redeemer |
| `livepeer_suggested_gas_price` | Suggested gas price for winning ticket redemption | Gateway, Orchestrator, Redeemer |
| `livepeer_min_gas_price` | Minimum gas price to use for gas price suggestions | Gateway, Orchestrator, Redeemer |
| `livepeer_max_gas_price` | Maximum gas price to use for gas price suggestions | Gateway, Orchestrator, Redeemer |
| `livepeer_transcoding_price` | Transcoding price per pixel | Orchestrator |
### Pixel accounting
| Name | Description | Node Type |
| ------------------------------- | ------------------------ | --------------------- |
| `livepeer_mil_pixels_processed` | Million pixels processed | Gateway, Orchestrator |
### Fast verification
| Name | Description | Node Type |
| ----------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | --------- |
| `livepeer_fast_verification_done` | Number of fast verifications done | Gateway |
| `livepeer_fast_verification_failed` | Number of fast verifications failed | Gateway |
| `livepeer_fast_verification_enabled_current_sessions_total` | Number of currently transcoded streams that have fast verification enabled | Gateway |
| `livepeer_fast_verification_using_current_sessions_total` | Number of currently transcoded streams that have fast verification enabled and that are using an untrusted orchestrator | Gateway |
# Livestream
Source: https://docs.livepeer.org/v1/references/knowledge-base/livestream
Diagnose: We do not have a feature to livestream audio only, but it is being
planned. Visit our feature request page for updates.
[https://livepeer.canny.io/feature-requests](https://livepeer.canny.io/feature-requests) Workaround: Add `?video=false` to
the end of the playback URL. Ex.
[https://livepeercdn.com/hls/playbackId/index.m3u8?video=false](https://livepeercdn.com/hls/playbackId/index.m3u8?video=false)
Diagnose: This is supported but has not been thoroughly tested.
Workaround: When creating a stream, add the following to the profile:
```json theme={"theme":{"light":"github-light","dark":"dark-plus"}}
{
"name": "1080p",
"bitrate": 5000000,
"fps": 30,
"width": 1920,
"height": 1080
}
```
Diagnose: At the moment, we do not offer closed captioning features.
Workaround: This has been added to the feature request [https://livepeer.canny.io/feature-requests/p/adding-subtitles-to-your-video-assets](https://livepeer.canny.io/feature-requests/p/adding-subtitles-to-your-video-assets)
Diagnose: You can suspend the stream
Workaround: Use either the API or SDK to suspend the stream. [https://docs.livepeer.org/reference/api#update-a-stream](https://docs.livepeer.org/reference/api#update-a-stream) or [https://docs.livepeer.org/reference/livepeer-js/stream/useUpdateStream#suspend](https://docs.livepeer.org/reference/livepeer-js/stream/useUpdateStream#suspend)
Diagnose: Yes, it is under the `sourceBytes` in the stream object.
Workaround: [https://docs.livepeer.org/reference/api#retrieve-a-stream](https://docs.livepeer.org/reference/api#retrieve-a-stream)
Diagnose: Short form videos need to use the MP4 playback as default
Workaround: Get the MP4 playback from the asset object and set it as the source. If you use the HLS instead for short form videos, this will affect the playback experience for users drastically.
Diagnose: If you're using livepeer.studio you can force a region.
Workaround: Replace the `rtmp://rtmp.livepeer.com/live/streamkey` with the region you want to force the broadcast to. Ex. `rtmp://sin-rtmp.livepeer.com/live/streamkey`, contact us for a list of regions available.
Diagnose: When creating a stream, set the profile object of the stream empty.
Workaround: `profile:[]`
Diagnose: You can use latency inject to increase the latency for a stream as a trade-off to reduce buffering.
Workaround: You add the query to the end of the playback URL in the amount of seconds you want to increase the latency. Ex. `&latency=10&buffer=10`
Diagnose: You can add a query to the end of the playback url.
Workaround: `?video=640x360,1m&pswait&trackcount=9`
# Playback
Source: https://docs.livepeer.org/v1/references/knowledge-base/playback
Diagnose: This is due to the low latency playback feature using WebRTC. If
there are bframes in the stream, the default behavior is to fallback to HLS
playback, which means a slight increase in latency. Workaround: In the
settings of the gateway, turn off the use of frames. If using OBS, select
Livepeer as the service for the video settings.
[https://docs.livepeer.org/guides/developing/stream-via-obs#input-your-stream-settings](https://docs.livepeer.org/guides/developing/stream-via-obs#input-your-stream-settings)
Diagnose: Reconnection: If a stream is down, attempt to retry for that stream
from other nodes nearby until there is a connection(using Livepeer player)
Workaround: Implement a retry logic or switch over to the Livepeer player with
the SDK or iframe embedded player.
Diagnose: We do not support pagination yet but it is a pending feature. You can use the playbackId as a workaround.
Workaround: A short term workaround could be to "paginate" by playbackId instead.
* First list all playback ids with: `/api/data/views/query?breakdownBy[]=playbackId`
* then viewers by playbackId with `/api/data/views/query?playbackId=&breakdownBy[]=viewerId`
Diagnose: Yes, you can use the iframe embedded player and set the width and
height in the iframe tag, however the best way to do this is to use the aspect
ratio.
There are two solutions to accomplish this:
1. If you are using react component, you can pass `lowLatency="force"` to the player component.
You can
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
function PlayerComponent() {
return (
);
}
```
2. If you are using the iframe embedded player, you can add `lowLatency=true` to
the query string. `lvpr.tv/?v={playbackid}&lowLatency=true`
You can use a poster image by default for a player, then, when playback info API returns the thumbnail url, you can start to use dynamic thumbnail for preview.
Here is how to set up a poster image in Player:
You can set the poster image for a video by utilizing the poster property in Livepeer’s Player component. This property can take either an image URL or a React component as its value.
To set the poster image with a URL, you can use the following code example:
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
import { Player } from "@livepeer/react";
function PlayerComponent() {
return (
);
}
```
If you prefer using a React component, then you can create an image component
and pass it as a value to the poster property. Here is a code example that
illustrates how you can do this:
```js theme={"theme":{"light":"github-light","dark":"dark-plus"}}
=
import { Player } from "@livepeer/react";
import Image from "next/image";
import yourPosterImage from "./images/your-image-file.png";
const PosterImageComponent = () => {
return (
);
};
function PlayerComponent() {
return (
}
/>
);
};
```
# Vod
Source: https://docs.livepeer.org/v1/references/knowledge-base/vod
Diagnose: The playback format is HLS and for any asset that is \< 2 minutes is MP4.
Workaround: N/A
Diagnose: You can use our webhook to get the status of an asset while it is
being uploaded. Workaround: You can use these events for asset statuses:
`asset.created` `asset.updated` `asset.ready` `asset.failed` `asset.deleted`
[https://docs.livepeer.org/guides/developing/listen-for-webhooks#request](https://docs.livepeer.org/guides/developing/listen-for-webhooks#request)
Diagnose: A new asset with a different Id will be created. Workaround: N/A
Diagnose: Check to make sure that the asset is not using access control.
Workaround: Check the playback information of the asset and make sure that the playback policy is set to `null` or `public`. Use the API endpoint to check: `https://livepeer.studio/api/playback/Playback_Id`
Diagnose: Anything with more than 1 video track will be reduced to 1 video
track. Workaround: N/A
Diagnose: Any other tracks and data types (subtitles/captions, metadata, track
titles, chapter data, etc) will be removed. Workaround: N/A
Diagnose: If the error specifies 401 or 403, this is indicating that there is
an issue with the credentials of your storage. Workaround: Make sure that the
storage credentials allow for both reading and writing to it.
Diagnose: If you close or refresh the page the video is being uploaded, this
can cause the asset to fail. Workaround: Do not refresh or close the page when
uploading with the Livepeer Studio dashboard, otherwise, it will cause the
asset to fail
Diagnose: Check to see if the asset had codecs that are being supported.
Workaround: No support for assets using VP9 codec in an MP4 container see our
[support matrix](https://docs.livepeer.org/references/api-support-matrix).
Diagnose: Make sure the asset is not over the size limit. Workaround: Only up
to 30GB file size is supported
Diagnose: Make sure that the amount of uploads is not exceeding the limit.
Workaround: Limited to 20 uploads at a time with 5 assets processing at the
same time
Diagnose: You can fetch usage of storage in a given time frame using the API
Workaround:
[https://livepeer.studio/data/usage/query?from=UNIX\_TIMESTAMP\_MILLISECONDS\&to=UNIX\_TIMESTAMP\_MILLISECONDS](https://livepeer.studio/data/usage/query?from=UNIX_TIMESTAMP_MILLISECONDS\&to=UNIX_TIMESTAMP_MILLISECONDS)
# Go
Source: https://docs.livepeer.org/v1/sdks/go
Learn how to create your first stream using the Livepeer Go SDK.
To get the most out of this guide, you’ll need to:
* [Create an API key](https://livepeer.studio/dashboard/developers/api-keys)
Get the Livepeer Go SDK.
```bash theme={"theme":{"light":"github-light","dark":"dark-plus"}}
go get github.com/livepeer/livepeer-go
```
The first step is to initialize the SDK with your Livepeer Studio API key.
```go theme={"theme":{"light":"github-light","dark":"dark-plus"}}
package main
import (
"context"
livepeer "github.com/livepeer/livepeer-go"
"github.com/livepeer/livepeer-go/models/components"
"log"
)
func main() {
lpClient := livepeer.New(
livepeer.WithSecurity(""),
)
}
```
Now that you have the SDK installed and initialized, you can use it in your app.
Let's create a stream.
```go theme={"theme":{"light":"github-light","dark":"dark-plus"}}
package main
import (
"context"
livepeer "github.com/livepeer/livepeer-go"
"github.com/livepeer/livepeer-go/models/components"
"log"
)
func main() {
lpClient := livepeer.New(
livepeer.WithSecurity(""),
)
ctx := context.Background()
res, err := lpClient.Stream.Create(ctx, components.NewStreamPayload{
Name: "test_stream",
})
if err != nil {
log.Fatal(err)
}
if res.Stream != nil {
log.Printf("Stream created successfully")
}
}
```
See an example on GitHub.
## Next steps
Checkout Livepeer [API Reference](/api-reference) to learn more about the
Livepeer API and the Go SDK.
# SDKs
Source: https://docs.livepeer.org/v1/sdks/introduction
Explore developer SDKs, pre-built UI components, and tools for interacting with the Livepeer Studio API.
## Server-side SDKs
Server-side SDKs reduce the amount of work required to use the Livepeer Studio
API. Install a language-specific SDK into your application, initialize with your
API key and get started with just 2 lines of code.
## React Components
Build with composable React primitives for both broadcasting and playback.
Fully customizable video player component for seamless playback
Full-featured broadcast component with controls, settings, and device
selection
# JavaScript
Source: https://docs.livepeer.org/v1/sdks/javascript
Learn how to create your first stream using the Livepeer Javascript SDK.
To get the most out of this guide, you’ll need to:
* [Create an API key](https://livepeer.studio/dashboard/developers/api-keys)
Get the Livepeer Javascript SDK.