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

# Transcode with 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).

<Warning>
  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).
</Warning>

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 <livepeer-studio-did-key> | 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:

<Tabs>
  <Tab title="Node.js">
    ```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);
    });
    ```
  </Tab>

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

    client = livepeer.Livepeer(
        api_key="<YOUR_BEARER_TOKEN_HERE>",
    )

    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
    ```
  </Tab>

  <Tab title="Go">
    ```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("<YOUR_BEARER_TOKEN_HERE>"),
       )

      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
      }
    }
    ```
  </Tab>
</Tabs>

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)
