> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.twelvelabs.io/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.twelvelabs.io/_mcp/server.

# Analyze videos

> Analyze videos to generate text based on their content, including quality control of AI-generated video, such as checking a clip against its prompt and detecting visual defects.

The platform uses a multimodal approach to analyze videos and generate text, processing visuals, sounds, spoken words, and text to provide a comprehensive understanding. This method captures nuances that unimodal interpretations might miss, allowing for accurate and context-rich text generation based on video content.

**Key features**:

* **Multimodal analysis**: Processes visuals, sounds, spoken words, and text for a holistic understanding of video content.
* **Customizable prompts**: Allows tailored outputs through instructive, descriptive, or question-based prompts.
* **Flexible text generation**: Supports various tasks, including summarization, chaptering, and open-ended text generation.
* **Segment videos**: Extract structured, timestamped segments from your videos by defining custom segment types and fields.

**Use cases**:

* **Content structuring**: Organize and structure content for e-learning platforms to improve usability.
* **SEO optimization**: Optimize content to rank higher in search engine results.
* **Highlight creation**: Create short, engaging video clips for media and broadcasting.
* **Incident reporting**: Record and report incidents for security and law enforcement purposes.
* **Generative video QA**: Check AI-generated clips against their prompt or flag visual defects before you use them.

On the Free plan, analyzed video hours count toward a shared limit that also covers indexing. On paid plans, you pay based on how much video you process and how many segment definitions you include — see the [Frequently asked questions](/v1.3/docs/resources/frequently-asked-questions#how-is-video-segmentation-priced) page for examples.

For details on how your usage is measured and billed, see the [Pricing](https://www.twelvelabs.io/pricing) page.

# Key concepts

This section explains the key concepts and terminology used in this guide:

* **Asset**: Your uploaded content. Once created, you can reference the same asset across multiple operations without uploading the file again.
* **Analysis task**: An asynchronous operation for processing your video and generating text. Contains a status and the resulting text when complete.

# Workflow

This guide shows how to upload your video as an asset and analyze it asynchronously. You can also pass a URL or base64-encoded data directly to the analysis call instead of creating an asset.

For videos under 1 hour, synchronous processing returns results immediately without polling and also supports streaming responses. For an example, see the [Short videos (synchronous)](#short-videos-synchronous) section. Both modes accept the same input formats (asset ID, URL, or base64). For a full comparison, see [Processing modes](/v1.3/docs/concepts/upload-methods#processing-modes).

**Customize text generation**

You can configure the temperature to control output randomness, set the maximum response length, and request [structured JSON responses](/v1.3/docs/guides/analyze-videos/structured-responses) for programmatic processing. To extract timestamped segments with custom fields, see the [Segment videos](/v1.3/docs/guides/segment-videos) page.

# Prerequisites

* To use the platform, you need an API key:

  If you don't have an account, [sign up](https://playground.twelvelabs.io/) for a free account.

  Go to the [API Keys](https://playground.twelvelabs.io/dashboard/api-keys) page.

  If you need to create a new key, select the **Create API Key** button. Enter a name and set the expiration period. The default is 12 months.

  Select the **Copy** icon next to your key to copy it to your clipboard.

* Depending on the programming language you are using, install the TwelveLabs SDK by entering one of the following commands:

  **`Python`**

  ```shell Python
  pip install --upgrade twelvelabs
  ```

  **`Node.js`**

  ```shell Node.js
  yarn add twelvelabs-js@latest # or npm install twelvelabs-js@latest
  ```

* Your videos must meet the following requirements:
  * **Upload limits**: Public video URLs up to 4 GB or local videos up to 200 MB. For a video up to 10 GB, use multipart uploads. See the [Upload and processing methods](/v1.3/docs/concepts/upload-methods) page for details.

  * **Analysis method**: The video can be up to 2 hours long, or up to 4 hours when you analyze only a portion of it. You can analyze between 1 second and 2 hours (asynchronous approach). For videos under 1 hour, see the [synchronous approach](#short-videos-synchronous) below.

  * **Model capabilities**: See the complete [requirements](/v1.3/docs/concepts/models/pegasus#video-file-requirements) for resolution, aspect ratio, and supported formats.

# Complete example

Copy and paste the code below, replacing the placeholders surrounded by `<>` with your values.

**`Python`**

```Python Python maxlines=12
import time
from twelvelabs import TwelveLabs
from twelvelabs.types import VideoContext_AssetId, VideoContext_Url, VideoContext_Base64String, AnalyzePromptV2, SmeMediaSource

# 1. Initialize the client
client = TwelveLabs(api_key="<YOUR_API_KEY>")

# 2. Upload a video
asset = client.assets.create(
    method="url",
    url="<YOUR_VIDEO_URL>" # Use direct links to raw media files. Video hosting platforms and cloud storage sharing links are not supported
    # Or use method="direct" and file=open("<PATH_TO_VIDEO_FILE>", "rb") to upload a local file up to 200 MB
)
print(f"Created asset: id={asset.id}")

# 3. Check the status of the asset
print("Waiting for asset to be ready...")
while True:
    asset = client.assets.retrieve(asset.id)
    if asset.status == "ready":
        print("Asset is ready")
        break
    if asset.status == "failed":
        raise RuntimeError(f"Asset processing failed: id={asset.id}")
    time.sleep(5)

# 4. Analyze your video
video = VideoContext_AssetId(asset_id=asset.id)
# Or instead of creating an asset, pass video inline:
# video = VideoContext_Url(url="<YOUR_VIDEO_URL>")
# video = VideoContext_Base64String(base_64_string="<YOUR_BASE64_DATA>")
task = client.analyze_async.tasks.create(
    model_name="pegasus1.5",
    video=video,
    prompt_v_2=AnalyzePromptV2(
        input_text="<YOUR_PROMPT>",  # To use reference images: "Is there a <@product> in this video?"
        # media_sources=[
        #     SmeMediaSource(name="product", media_type="image", url="<YOUR_IMAGE_URL>"),
        # ],
    ),
    # temperature=0.2,
    # max_tokens=1024,
    # You can also use `response_format` to request structured JSON responses
)
print(f"Task ID: {task.task_id}")

# 5. Monitor the status
while True:
    task = client.analyze_async.tasks.retrieve(task.task_id)

    if task.status == "ready":
        print("Task completed")
        break
    elif task.status in ("failed", "canceled"):
        message = task.error.message if task.error else f"Task ended with status: {task.status}"
        raise RuntimeError(message)
    else:
        print("Task still processing...")
        time.sleep(5)

# 6. Process the results
print(f"{task.result.data}")
```

**`Node.js`**

```JavaScript Node.js maxlines=12
import { TwelveLabs } from "twelvelabs-js";
// Uncomment the next line if uploading a local file
// import fs from 'fs';

// 1. Initialize the client
const client = new TwelveLabs({ apiKey: "<YOUR_API_KEY>" });

// 2. Upload a video
const asset = await client.assets.create({
  method: "url",
  url: "<YOUR_VIDEO_URL>", // Use direct links to raw media files. Video hosting platforms and cloud storage sharing links are not supported
  // Or use method: "direct" and file: fs.createReadStream("<PATH_TO_VIDEO_FILE>") to upload a local file up to 200 MB
});
console.log(`Created asset: id=${asset.id}`);

// 3. Check the status of the asset
console.log("Waiting for asset to be ready...");
let readyAsset = await client.assets.retrieve(asset.id);
while (readyAsset.status !== "ready" && readyAsset.status !== "failed") {
  await new Promise((resolve) => setTimeout(resolve, 5000));
  readyAsset = await client.assets.retrieve(asset.id);
}
if (readyAsset.status === "failed") {
  throw new Error(`Asset processing failed: id=${asset.id}`);
}
console.log("Asset is ready");

// 4. Analyze your video
const { taskId } = await client.analyzeAsync.tasks.create({
  modelName: "pegasus1.5",
  video: { type: "asset_id", assetId: asset.id },
  // Or instead of creating an asset, pass video inline:
  // video: { type: "url", url: "<YOUR_VIDEO_URL>" }
  // video: { type: "base64_string", base64String: "<YOUR_BASE64_DATA>" }
  promptV2: {
    inputText: "<YOUR_PROMPT>",  // To use reference images: "Is there a <@product> in this video?"
    // mediaSources: [
    //   { name: "product", mediaType: "image", url: "<YOUR_IMAGE_URL>" },
    // ],
  },
  // temperature: 0.2,
  // maxTokens: 1024,
  // You can also use `responseFormat` to request structured JSON responses
});
console.log(`Task ID: ${taskId}`);

// 5. Monitor the status
let task = await client.analyzeAsync.tasks.retrieve(taskId);
while (!["ready", "failed", "canceled"].includes(task.status)) {
  console.log("Task still processing...");
  await new Promise((resolve) => setTimeout(resolve, 5000));
  task = await client.analyzeAsync.tasks.retrieve(taskId);
}

if (task.status !== "ready") {
  throw new Error(task.error?.message ?? `Task ended with status: ${task.status}`);
}
console.log("Task completed");

// 6. Process the results
console.log(`${task.result.data}`);
```

# Code explanation

#### Python

#### Import the SDK and initialize the client

Create a client instance to interact with the TwelveLabs Video Understanding Platform.\

**Function call**: You call the [constructor](/v1.3/sdk-reference/python/the-twelve-labs-class#the-initializer) of the `TwelveLabs` class.\

**Parameters**:

* `api_key`: The API key to authenticate your requests to the platform.\


**Return value**: An object of type `TwelveLabs` configured for making API calls.

#### Upload a video

Upload a video to create an asset.\

**Function call**: You call the [`assets.create`](/v1.3/sdk-reference/python/upload-content/direct-uploads#create-an-asset) function.\

**Parameters**:

* `method`: The upload method for your asset. Use `url` for a publicly accessible or `direct` to upload a local file. This example uses `url`.
* `url` or `file`: The publicly accessible URL of your video or an opened file object in binary read mode. This example uses `url`.

**Return value**: An object of type `Asset`. This object contains, among other information, a field named `id` representing the unique identifier of your asset.

> **Note**
>
> For local files larger than 200 MB, use [multipart uploads](/v1.3/api-reference/upload-content/multipart-uploads). Multipart uploads support automatic retry, progress tracking, parallel chunk uploads, and improved reliability, performance, and observability.

#### Check the status of the asset

Asset processing is asynchronous. Poll the status of the asset until it is `ready` before you use it.\

**Function call**: You call the [`assets.retrieve`](/v1.3/sdk-reference/python/manage-assets#retrieve-an-asset) function.\

**Parameters**:

* `asset_id`: The unique identifier of your asset.\


**Return value**: An object of type `Asset` containing, among other information, a field named `status` representing the current status of the asset. Check this field until its value is `ready`.

#### Analyze your video

Create an analysis task to start processing your video. This operation is asynchronous.\

**Function call**: You call the [`analyze_async.tasks.create`](/v1.3/sdk-reference/python/analyze-videos/async-analysis#create-an-async-analysis-task) method.\

**Parameters**:

* `video`: An object that specifies the source of the video. Provide one of the following:

  * `asset_id`: The unique identifier of an asset from a previous upload.
  * `url`: The publicly accessible URL of the video file.
  * `base_64_string`: The base64-encoded video data.

  This example uses the asset ID from the previous step.

* `prompt_v_2`: A structured prompt. Set `input_text` to your prompt text. To include reference images, add entries to `media_sources` and use `<@name>` placeholders in `input_text`. See the commented lines in the code example above.

* *(Optional)* `temperature`: Controls the randomness of the text output. A higher value generates more creative text, while a lower value produces more deterministic output.

* *(Optional)* `max_tokens`: The maximum response length, in tokens.

* *(Optional)* `response_format`: Use this parameter to request structured JSON responses. For instructions, examples, and best practices, see the [Structured responses](/v1.3/docs/guides/analyze-videos/structured-responses) page.\


**Return value**: An object of type `CreateAnalyzeTaskResponse` containing a field named `task_id`, which represents the unique identifier of your analysis task. You can use this identifier to track the status of your task.

#### Monitor the status

The platform requires some time to process videos. Poll the status of the analysis task until processing completes. This example uses a loop to check the status every 5 seconds.\

**Function call**: You repeatedly call the [`analyze_async.tasks.retrieve`](/v1.3/sdk-reference/python/analyze-videos/async-analysis#retrieve-task-status-and-results) method until the task completes.\


**Parameters**:

* `task_id`: The unique identifier of your analysis task.\


**Return value**: An object of type `AnalyzeTaskResponse` containing, among other information, the following fields:

* `status`: The current status of the task. The possible values are:
  * `queued`: The task is waiting to be processed.
  * `pending`: The task is queued and waiting to start.
  * `processing`: The platform is analyzing the video.
  * `ready`: Processing is complete. Results are available in the `result` field.
  * `failed`: The task failed.
  * `canceled`: The task was canceled. No result is available.
* `result`: When the status is `ready`, this field contains the generated text and usage information.

#### Process the results

This example prints the generated text to the standard output.

#### Node.js

#### Import the SDK and initialize the client

Create a client instance to interact with the TwelveLabs Video Understanding Platform.\

**Function call**: You call the [constructor](/v1.3/sdk-reference/node-js/the-twelve-labs-class#the-constructor) of the `TwelveLabs` class.\

**Parameters**: You pass all parameters as properties of a single object.

* `apiKey`: The API key to authenticate your requests to the platform.\


**Return value**: An object of type `TwelveLabs` configured for making API calls.

#### Upload a video

Upload a video to create an asset.\

**Function call**: You call the [`assets.create`](/v1.3/sdk-reference/node-js/upload-content/direct-uploads#create-an-asset) function.\

**Parameters**: You pass all parameters as properties of a single object.

* `method`: The upload method for your asset. Use `url` for a publicly accessible or `direct` to upload a local file. This example uses `url`.
* `url` or `file`: The publicly accessible URL of your video or an opened file object in binary read mode. This example uses `url`.

**Return value**: An `HttpResponsePromise` that resolves to an object of type `Asset`. This object contains, among other information, a field named `id` representing the unique identifier of your asset.

> **Note**
>
> For local files larger than 200 MB, use [multipart uploads](/v1.3/api-reference/upload-content/multipart-uploads). Multipart uploads support automatic retry, progress tracking, parallel chunk uploads, and improved reliability, performance, and observability.

#### Check the status of the asset

Asset processing is asynchronous. Poll the status of the asset until it is `ready` before you use it.\

**Function call**: You call the [`assets.retrieve`](/v1.3/sdk-reference/node-js/manage-assets#retrieve-an-asset) function.\

**Parameters**: You pass the parameter as a positional argument.

* `assetId`: The unique identifier of your asset.\


**Return value**: An `HttpResponsePromise` that resolves to an object of type `Asset` containing, among other information, a field named `status` representing the current status of the asset. Check this field until its value is `ready`.

#### Analyze your video

Create an analysis task to start processing your video. This operation is asynchronous.\

**Function call**: You call the [`analyzeAsync.tasks.create`](/v1.3/sdk-reference/node-js/analyze-videos/async-analysis#create-an-async-analysis-task) method.\

**Parameters**: You pass all parameters as properties of a single object.

* `video`: An object that specifies the source of the video. Provide one of the following:

  * `assetId`: The unique identifier of an asset from a previous upload.
  * `url`: The publicly accessible URL of the video file.
  * `base64String`: The base64-encoded video data.

  This example uses the asset ID from the previous step.

* `promptV2`: A structured prompt. Set `inputText` to your prompt text. To include reference images, add entries to `mediaSources` and use `<@name>` placeholders in `inputText`. See the commented lines in the code example above.

* *(Optional)* `temperature`: Controls the randomness of the text output. A higher value generates more creative text, while a lower value produces more deterministic output.

* *(Optional)* `maxTokens`: The maximum response length, in tokens.

* *(Optional)* `responseFormat`: Use this parameter to request structured JSON responses. For instructions, examples, and best practices, see the [Structured responses](/v1.3/docs/guides/analyze-videos/structured-responses) page.\


**Return value**: An `HttpResponsePromise` that resolves to an object of type `CreateAnalyzeTaskResponse`. This example destructures `taskId` from the response — the unique identifier of your analysis task. You can use this identifier to track the status of your task.

#### Monitor the status

The platform requires some time to process videos. Poll the status of the analysis task until processing completes. This example uses a loop to check the status every 5 seconds.\

**Function call**: You repeatedly call the [`analyzeAsync.tasks.retrieve`](/v1.3/sdk-reference/node-js/analyze-videos/async-analysis#retrieve-task-status-and-results) method until the task completes.\


**Parameters**:

* `taskId`: The unique identifier of your analysis task.\


**Return value**: An `HttpResponsePromise` that resolves to an object of type `AnalyzeTaskResponse` containing, among other information, the following fields:

* `status`: The current status of the task. The possible values are:
  * `queued`: The task is waiting to be processed.
  * `pending`: The task is queued and waiting to start.
  * `processing`: The platform is analyzing the video.
  * `ready`: Processing is complete. Results are available in the `result` field.
  * `failed`: The task failed.
  * `canceled`: The task was canceled. No result is available.
* `result`: When the status is `ready`, this field contains the generated text and usage information.

#### Process the results

This example prints the generated text to the standard output.

# Short videos (synchronous)

For videos that are shorter than one hour, you can use a synchronous approach that returns results immediately without creating an analysis task.

**Response methods**

#### Streaming responses

Streaming responses deliver text fragments in real-time as they are generated, enabling immediate processing and feedback. This method is the default behavior of the platform and is ideal for applications requiring incremental updates.\


* **Response format**: A stream of JSON objects in NDJSON format, with three event types:
  * `stream_start`: Marks the beginning of the stream.
  * `text_generation`: Delivers a fragment of the generated text.
  * `stream_end`: Signals the end of the stream.\

* **Response handling**:
  * Iterate over the stream to process text fragments as they arrive.\

* **Advantages**:
  * Real-time processing of partial results.
  * Reduced perceived latency.
* **Use case**: Live transcription, real-time analysis, or applications needing instant updates.

#### Non-streaming responses

Non-streaming responses deliver the complete generated text in a single response, simplifying processing when the full result is needed.

* **Response format**: A single string containing the full generated text.
* **Response handling**:
  * Access the complete text directly from the response.
* **Advantages**:
  * Simplicity in handling the full result.
  * Immediate access to the entire text.
* **Use case**: Generating reports, summaries, or any scenario where the whole text is required at once.

Copy and paste the code below, replacing the placeholders surrounded by `<>` with your values.

#### Streaming responses

**`Python`**

```Python Python maxlines=12
import time
from twelvelabs import TwelveLabs
from twelvelabs.types import VideoContext_AssetId, AnalyzePromptV2, SmeMediaSource

# 1. Initialize the client
client = TwelveLabs(api_key="<YOUR_API_KEY>")

# 2. Upload a video
asset = client.assets.create(
    method="url",
    url="<YOUR_VIDEO_URL>" # Use direct links to raw media files. Video hosting platforms and cloud storage sharing links are not supported
    # Or use method="direct" and file=open("<PATH_TO_VIDEO_FILE>", "rb") to upload a local file up to 200 MB
)
print(f"Created asset: id={asset.id}")

# 3. Check the status of the asset
print("Waiting for asset to be ready...")
while True:
    asset = client.assets.retrieve(asset.id)
    if asset.status == "ready":
        print("Asset is ready")
        break
    if asset.status == "failed":
        raise RuntimeError(f"Asset processing failed: id={asset.id}")
    time.sleep(5)

# 4. Analyze your video
video = VideoContext_AssetId(asset_id=asset.id)
text_stream = client.analyze_stream(
    model_name="pegasus1.5",
    video=video,
    prompt_v_2=AnalyzePromptV2(
        input_text="<YOUR_PROMPT>",  # To use reference images: "Is there a <@product> in this video?"
        # media_sources=[
        #     SmeMediaSource(name="product", media_type="image", url="<YOUR_IMAGE_URL>"),
        # ],
    ),
    # temperature=0.2,
    # max_tokens=1024,
    # You can also use `response_format` to request structured JSON responses
)

# 5. Process the results
for text in text_stream:
    if text.event_type == "text_generation":
        print(text.text)
```

**`Node.js`**

```JavaScript Node.js maxlines=12
import { TwelveLabs } from "twelvelabs-js";
// Uncomment the next line if uploading a local file
// import fs from 'fs';

// 1. Initialize the client
const client = new TwelveLabs({ apiKey: "<YOUR_API_KEY>" });

// 2. Upload a video
const asset = await client.assets.create({
  method: "url",
  url: "<YOUR_VIDEO_URL>", // Use direct links to raw media files. Video hosting platforms and cloud storage sharing links are not supported
  // Or use method: "direct" and file: fs.createReadStream("<PATH_TO_VIDEO_FILE>") to upload a local file up to 200 MB
});
console.log(`Created asset: id=${asset.id}`);

// 3. Check the status of the asset
console.log("Waiting for asset to be ready...");
let readyAsset = await client.assets.retrieve(asset.id);
while (readyAsset.status !== "ready" && readyAsset.status !== "failed") {
  await new Promise((resolve) => setTimeout(resolve, 5000));
  readyAsset = await client.assets.retrieve(asset.id);
}
if (readyAsset.status === "failed") {
  throw new Error(`Asset processing failed: id=${asset.id}`);
}
console.log("Asset is ready");

// 4. Analyze your video
const textStream = await client.analyzeStream({
  modelName: "pegasus1.5",
  video: { type: "asset_id", assetId: asset.id },
  promptV2: {
    inputText: "<YOUR_PROMPT>",  // To use reference images: "Is there a <@product> in this video?"
    // mediaSources: [
    //   { name: "product", mediaType: "image", url: "<YOUR_IMAGE_URL>" },
    // ],
  },
  // temperature: 0.2,
  // maxTokens: 1024,
  // You can also use `responseFormat` to request structured JSON responses
});

// 5. Process the results
for await (const text of textStream) {
  if ("text" in text) {
    console.log(text.text);
  }
}
```

#### Non-streaming responses

**`Python`**

```Python Python maxlines=12
import time
from twelvelabs import TwelveLabs
from twelvelabs.types import VideoContext_AssetId, AnalyzePromptV2, SmeMediaSource

# 1. Initialize the client
client = TwelveLabs(api_key="<YOUR_API_KEY>")

# 2. Upload a video
asset = client.assets.create(
    method="url",
    url="<YOUR_VIDEO_URL>" # Use direct links to raw media files. Video hosting platforms and cloud storage sharing links are not supported
    # Or use method="direct" and file=open("<PATH_TO_VIDEO_FILE>", "rb") to upload a local file up to 200 MB
)
print(f"Created asset: id={asset.id}")

# 3. Check the status of the asset
print("Waiting for asset to be ready...")
while True:
    asset = client.assets.retrieve(asset.id)
    if asset.status == "ready":
        print("Asset is ready")
        break
    if asset.status == "failed":
        raise RuntimeError(f"Asset processing failed: id={asset.id}")
    time.sleep(5)

# 4. Analyze your video
video = VideoContext_AssetId(asset_id=asset.id)
text = client.analyze(
    model_name="pegasus1.5",
    video=video,
    prompt_v_2=AnalyzePromptV2(
        input_text="<YOUR_PROMPT>",  # To use reference images: "Is there a <@product> in this video?"
        # media_sources=[
        #     SmeMediaSource(name="product", media_type="image", url="<YOUR_IMAGE_URL>"),
        # ],
    ),
    # temperature=0.2,
    # max_tokens=1024,
    # You can also use `response_format` to request structured JSON responses
)

# 5. Process the results
print(f"{text.data}")
```

**`Node.js`**

```JavaScript Node.js maxlines=12
import { TwelveLabs } from "twelvelabs-js";
// Uncomment the next line if uploading a local file
// import fs from 'fs';

// 1. Initialize the client
const client = new TwelveLabs({ apiKey: "<YOUR_API_KEY>" });

// 2. Upload a video
const asset = await client.assets.create({
  method: "url",
  url: "<YOUR_VIDEO_URL>", // Use direct links to raw media files. Video hosting platforms and cloud storage sharing links are not supported
  // Or use method: "direct" and file: fs.createReadStream("<PATH_TO_VIDEO_FILE>") to upload a local file up to 200 MB
});
console.log(`Created asset: id=${asset.id}`);

// 3. Check the status of the asset
console.log("Waiting for asset to be ready...");
let readyAsset = await client.assets.retrieve(asset.id);
while (readyAsset.status !== "ready" && readyAsset.status !== "failed") {
  await new Promise((resolve) => setTimeout(resolve, 5000));
  readyAsset = await client.assets.retrieve(asset.id);
}
if (readyAsset.status === "failed") {
  throw new Error(`Asset processing failed: id=${asset.id}`);
}
console.log("Asset is ready");

// 4. Analyze your video
const text = await client.analyze({
  modelName: "pegasus1.5",
  video: { type: "asset_id", assetId: asset.id },
  promptV2: {
    inputText: "<YOUR_PROMPT>",  // To use reference images: "Is there a <@product> in this video?"
    // mediaSources: [
    //   { name: "product", mediaType: "image", url: "<YOUR_IMAGE_URL>" },
    // ],
  },
  // temperature: 0.2,
  // maxTokens: 1024,
  // You can also use `responseFormat` to request structured JSON responses
});

// 5. Process the results
console.log(`${text.data}`);
```

The `video` parameter and all optional parameters (`model_name`, `temperature`, `max_tokens`, `response_format`, etc) function the same as in the asynchronous approach above.

# Troubleshooting

## Truncated responses

When the response reaches the maximum response length or the [context window](/v1.3/docs/concepts/models/pegasus#context-window), the platform returns the partial output and sets `finish_reason` to `"length"`. A warning appears in the `error` field. This can happen for two reasons:

* The response reached the maximum response length. To fix this, increase the `max_tokens` value.
* The combined input and response reached the context window. To fix this, reduce the input (shorter prompt, shorter video clip, fewer reference images) or lower the `max_tokens` value.

Check `usage.input_tokens` and `usage.output_tokens` in the response to determine which limit was reached. For truncation error messages, see [Error codes](/v1.3/api-reference/error-codes#the-analyze-endpoint).

### Stay within the context window

Reduce input size:

* Keep prompts focused, especially for longer videos.
* Use `start_time` and `end_time` to analyze a portion of the video.
* Reduce the number or size of reference images.

Control output size:

* Set the `max_tokens` parameter to the length your application needs.
* Request only the fields your application requires.

Split large tasks:

* Break complex analysis into multiple requests.

# Generative video QA

Use TwelveLabs to quality-check AI-generated video. This helps an automated pipeline decide, before it composites a generated clip into a final cut, whether the clip matches what was requested and is free of visual defects.

The unit of work is a single generated clip. For each clip, run one or more of the QA prompts below through the [Sync analysis](/v1.3/api-reference/analyze-videos/analyze) endpoint with the `model_name` parameter set to `pegasus1.5`, then parse the verdict.

## Workflow

1. Provide the clip. Pass a public URL to the raw video file, or upload the clip as an asset and reference its asset identifier (`asset_id`). An asset must reach the `ready` state before analysis. See [Create an asset](/v1.3/api-reference/upload-content/direct-uploads/create).
2. Analyze the clip. Call the `POST /analyze` endpoint with the `model_name` parameter set to `pegasus1.5`, the video source, one QA prompt, the `stream` parameter set to `false`, and a low temperature (for example, `0.2`) for deterministic verdicts.
3. Read the result. The `data` field contains the findings and a `PASS` or `FAIL` verdict. Collect the timestamped findings across prompts into a QA report, and gate the clip on the verdicts.

Example call for the adherence check:

```bash
curl -X POST "https://api.twelvelabs.io/v1.3/analyze" \
  -H "x-api-key: <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "model_name": "pegasus1.5",
    "video": { "type": "url", "url": "https://example.com/generated-clip.mp4" },
    "prompt": "<one of the QA prompts below>",
    "stream": false,
    "temperature": 0.2,
    "max_tokens": 2000
  }'
```

## QA prompts

Each prompt casts the model as a strict reviewer and asks for timestamped, severity-rated findings and a `PASS` or `FAIL` verdict. Replace the bracketed text with your own values.

### 1. Did the video match the prompt (high level)

Replace `<generation prompt>` with the prompt the clip was generated from.

> You are a strict video QA critic. This clip was generated by an AI video model from the following prompt: "`<generation prompt>`". Evaluate how faithfully the video matches this prompt. Go element by element (setting, wardrobe, props, actions, lighting, atmosphere) and mark each as present, missing, or altered, citing the timestamp where you judged it. End with an overall verdict of PASS or FAIL and a one-line justification.

### 2. Visual defects of human features

> You are a strict realism reviewer inspecting AI-generated video for anatomical defects. Watch the people in this clip and report any human-feature glitches: extra, missing, or fused fingers; malformed or warped faces; incorrect numbers of limbs; eyes, teeth, or ears that look wrong; and bodies that morph or merge. For each issue, give the approximate timestamp, the person or region affected, and a severity of minor, moderate, or severe. If you find no defects, say so explicitly. End with a PASS or FAIL verdict.

### 3. Visual defects in physics

> You are a strict realism reviewer inspecting AI-generated video for physics violations. Report anything that could not happen in the real world: objects floating, morphing, or changing size; impossible or inconsistent motion; broken gravity, collisions, or reflections; and parts of the scene that clip through each other. For each issue, give the approximate timestamp, describe what is wrong, and rate severity as minor, moderate, or severe. If the physics are plausible throughout, say so. End with a PASS or FAIL verdict.

### 4. Visual defects in continuity, coherence, and character consistency

> You are a strict continuity supervisor reviewing AI-generated video. Track the main subject and the background across the whole clip and report any consistency breaks: characters or objects that appear or disappear, identities that drift (face, clothing, or color changing), flicker, and background elements that change between moments. For each issue, give the approximate timestamp, describe the break, and rate severity as minor, moderate, or severe. End with a PASS or FAIL verdict.

## Structured output

For a machine-readable verdict, set the `response_format` parameter to a `json_schema` type so the call returns structured JSON instead of prose. A shape that mirrors these prompts works well: a boolean pass flag, an overall verdict, and a list of findings, each with its timestamp, a description of the issue, and a severity. This makes it straightforward to gate a pipeline on the result. For the exact syntax, see [Structured responses](/v1.3/docs/guides/analyze-videos/structured-responses).