# Generate thumbnails

> Generate thumbnails from a video Source with an SDK.

Generate images for posters, preview cards, or timeline previews from a video Source. You do not need to create an Asset or transcode first.

<note>
Video Assets already include a poster and timeline previews. Use this guide to generate thumbnails directly from a Source, or see [Asset outputs](/docs/video-streaming/outputs#create-outputs) to add thumbnails to an existing Asset.
</note>

## Before you begin

You need a video Source in the same Project, a Project access token, and an [official SDK](/docs/integration/sdk). Replace the example token and Source ID. Keep the token on your server.

Use an existing Source, [create one from a hosted file](/docs/api-reference/sources/create-a-new-source), or [upload a video](/docs/integration/video-upload).

The example uses the Project's default output storage. For lasting files, configure your own storage and choose a distinct output path each time you generate thumbnails. Here, `thumbnails/video-123/thumb-%05d.jpg` is relative to the storage's `base_prefix`.

## Generate thumbnails

This example generates ten individual JPEG images across the video. The default size is 320 pixels on the longest edge, preserving the aspect ratio without upscaling.

<codegroup>
<codeblock lang="TypeScript">
```typescript
import Chunkify from '@chunkify/chunkify';

async function main() {
    const client = new Chunkify({
        projectAccessToken: 'My Project Access Token',
    });

    const thumbnail = await client.thumbnails.create({
        source_id: 'src_2G6MJiNz71bHQGNzGwKx5cJwPFS',
        count: 10,
        storage: {
            path: 'thumbnails/video-123/thumb-%05d.jpg',
        },
    });

    console.log(thumbnail.id, thumbnail.status);
}

main().catch((error) => {
    console.error(error);
    process.exitCode = 1;
});
```
</codeblock>
<codeblock lang="Python">
```python
from chunkify import Chunkify

client = Chunkify(
    project_access_token="My Project Access Token",
)

thumbnail = client.thumbnails.create(
    source_id="src_2G6MJiNz71bHQGNzGwKx5cJwPFS",
    count=10,
    storage={
        "path": "thumbnails/video-123/thumb-%05d.jpg",
    },
)

print(thumbnail.id, thumbnail.status)
```
</codeblock>
<codeblock lang="PHP">
```php
<?php

use Chunkify\Client;

require_once __DIR__ . '/vendor/autoload.php';

$client = new Client(
    projectAccessToken: 'My Project Access Token',
);

$thumbnail = $client->thumbnails->create(
    sourceID: 'src_2G6MJiNz71bHQGNzGwKx5cJwPFS',
    count: 10,
    storage: [
        'path' => 'thumbnails/video-123/thumb-%05d.jpg',
    ],
);

var_dump($thumbnail->id, $thumbnail->status);
```
</codeblock>
<codeblock lang="Go">
```go
package main

import (
	"context"
	"fmt"
	"log"

	"github.com/chunkifydev/chunkify-go"
	"github.com/chunkifydev/chunkify-go/option"
)

func main() {
	client := chunkify.NewClient(
		option.WithProjectAccessToken("My Project Access Token"),
	)

	thumbnail, err := client.Thumbnails.New(
		context.Background(),
		chunkify.ThumbnailNewParams{
			SourceID: "src_2G6MJiNz71bHQGNzGwKx5cJwPFS",
			Count:    chunkify.Int(10),
			Storage: chunkify.ThumbnailCreateStorageParam{
				Path: chunkify.String("thumbnails/video-123/thumb-%05d.jpg"),
			},
		},
	)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(thumbnail.ID, thumbnail.Status)
}
```
</codeblock>
</codegroup>

The response includes a `thm_` ID. Save it to match webhook notifications. Generation runs asynchronously; the images are available once `status` is `ready`.

## Choose when to capture thumbnails

Use exactly one sampling option:

| Option | Behavior |
| --- | --- |
| `count` | Choose 1 to 100 thumbnails, one from the middle of each equal section of the selected range. |
| `timestamps` | Choose 1 to 100 specific times in seconds, such as `[5, 15, 30]`. |

For example, `count: 3` on a 60-second video targets 10, 30, and 50 seconds. To use specific times, replace `count` with `timestamps`.

By default, sampling covers the whole Source. Set `range.start` and `range.end` to limit it. Times are always relative to the original Source, including when you select a range. The start is included and the end is excluded; every selected timestamp must fall within those bounds.

## Choose the output

Choose individual images for posters or preview cards, or sprite sheets to combine timeline thumbnails into fewer files. Both layouts include a WebVTT index that maps video times to images and, for sprites, their positions within each sheet.

| Setting | Options |
| --- | --- |
| `output` | `images` for individual files, or `sprites` for automatically arranged sprite sheets. Defaults to `images`. |
| `format` | `jpeg` or `webp`. Defaults to `jpeg`. |
| `size` | Maximum image or sprite-tile edge, from 64 to 1920 pixels. Defaults to 320. |

Images preserve the video's aspect ratio without cropping or upscaling. The `size` applies to each thumbnail, not the complete sprite sheet.

For customer storage, `storage.path` must contain one `%05d` placeholder and end in `.jpg` for JPEG or `.webp` for WebP. Chunkify replaces the placeholder with the image or sheet number, starting at 1. The example above produces filenames such as `thumb-00001.jpg`, plus `thumb.vtt` for the timeline index.

See [Create Thumbnails](/docs/api-reference/thumbnails/create-thumbnails) for all request settings.

## Get the result

Subscribe to `thumbnail.ready` and `thumbnail.failed` through a [verified webhook](/docs/integration/webhooks) so your application is notified when processing finishes.

On success, `files` lists the images or sprite sheets and the WebVTT index, while `samples` describes the frames produced.

Continue with [Outputs and lifecycle](/docs/thumbnails/lifecycle) for webhook details and file URLs.

## Pricing

Additional thumbnails are charged per published sample, including each thumbnail inside a sprite sheet. See [thumbnail pricing](/docs/video-streaming/pricing#captions-and-thumbnails) and [output transfer costs](/docs/video-streaming/storage#data-transfer-costs). The default Asset poster and timeline previews are included in streaming preparation.
