# Render videos in Go

> Render a video template as an MP4 and follow its progress with the Go SDK.

Canonical: https://bannerify.co/docs/sdk/go/apis/render-video

A video template renders as an MP4. Each second of the video counts as one generation, and as two at 60 fps. [Generate videos](https://bannerify.co/docs/essentials/generate-videos) explains how to design one.

`RenderVideo` and `RenderAndWaitVideo` take a context, a template id, and the modifications.

<ParamField body="templateID" type="string" required>
  The id of a video template, for example `tpl_xxx`.
</ParamField>

<ParamField body="modifications" type="[]bannerify.Modification">
  The values to put into the template's layers. A video layer takes a `Src`, and an audio track takes a `src` with its name. [Modifications](https://bannerify.co/docs/essentials/modifications) lists the fields each layer accepts.
</ParamField>

## Render and wait for the URL

`RenderAndWaitVideo` returns the URL of the MP4. The error is an `*ErrorResponse`.

```go
headline := "Summer sale"
url, err := client.RenderAndWaitVideo(ctx, "tpl_xxx", []bannerify.Modification{
	{Name: "headline", Text: &headline},
})
if err != nil {
	log.Fatal(err)
}

fmt.Println(url)
```

## Follow the progress

`RenderVideo` returns an `iter.Seq[RenderVideoEvent]`. The last event is `done` or `error`.

```go
for event := range client.RenderVideo(ctx, "tpl_xxx", nil) {
	switch event.Type {
	case "queued":
		fmt.Printf("%d videos before this one\n", event.Ahead)
	case "progress":
		fmt.Printf("%.0f%%\n", event.Progress*100)
	case "done":
		fmt.Println(event.URL)
	case "error":
		fmt.Println(event.Error)
	}
}
```

| Event | Fields |
| --- | --- |
| `created` | `ID`: the id of the video, for example `vid_xxx` |
| `queued` | `Ahead`: the number of videos before this one |
| `progress` | `Frame`, `TotalFrames`, and `Progress` from 0 to 1 |
| `done` | `URL`: the URL of the MP4 |
| `error` | `Error`: `Code`, `Message`, and `RequestID` |

A refused request, such as an invalid API key or a used-up quota, gives one `error` event. The client timeout does not apply to a render, because a video can wait in line for minutes. Cancel `ctx` to stop.

## Reconnect after a dropped connection

The video renders to its end, even when the connection drops. Then `RenderVideo` reads the same video again by the id from the `created` event, and it continues to yield events. It never sends the render again, so you do not pay for a second video.

| Attempt | Wait before it |
| --- | --- |
| 1 | 1 second |
| 2 | 2 seconds |
| 3 | 4 seconds |
| 4 | 8 seconds |

When the attempts run out, or the connection drops before the `created` event, the last event is an `error` with the code `TIMEOUT_ERROR`. `RenderAndWaitVideo` reconnects in the same way.

## Start a video without waiting

`CreateVideo` starts the video and returns its id at once. It does not wait for the render. Then read the video with `GetVideo` or `WatchVideo`. The error is an `*ErrorResponse`.

```go
created, err := client.CreateVideo(ctx, "tpl_xxxxxxxxx", nil)
if err != nil {
	log.Fatal(err)
}

fmt.Println(created.ID) // vid_xxx, with the status queued
```

`CreateVideo` sends the render only once. A second request renders a second video.

## Read a video again

Keep the id from the `created` event. `GetVideo` returns the status of the video, and its URL when it is done. The error is an `*ErrorResponse`.

```go
video, err := client.GetVideo(ctx, "vid_xxx")
if err != nil {
	log.Fatal(err)
}

fmt.Println(video.Status, video.URL)
```

`Status` is `queued`, `rendering`, `done`, or `failed`. A failed video has an `Error` string. An unknown id gives an error with the code `NOT_FOUND`.

`WatchVideo` yields the events of the video again, from the latest one. It has no `created` event, and it reconnects as `RenderVideo` does.

```go
for event := range client.WatchVideo(ctx, "vid_xxx") {
	if event.Type == "done" {
		fmt.Println(event.URL)
	}
}
```

## Related

- [Previous: Create images and PDFs in Go](https://bannerify.co/docs/sdk/go/apis/create-image)
- [Next: Signed URLs in Go](https://bannerify.co/docs/sdk/go/apis/signed-url)
- [Documentation index](https://bannerify.co/docs/llms.txt)
