HomeDocumentationAPI Reference
Documentation

Download a highlight reel from a test result.

Learn how to list the highlight reels available for a test result, request a selected highlight reel by ID, poll while the reel is being generated, and download the reel when a temporary URL is returned.

Introduction

This tutorial shows how to use the Results API to download highlight reels from a test result. A test result can have zero highlight reels or many highlight reels.

Start by listing the highlight reels for the test result, then request a specific highlight reel by ID. The highlight reel download endpoint starts a generation process when a generated reel file is not already available, so clients must poll until the response says the reel is ready.

Use this workflow when you want to archive highlight reels in your own storage, feed research videos into downstream analysis, or make selected research moments available to another internal system.


You’ll use two endpoints:

GET /api/v2/testResults/{testId}/highlightreels
GET /api/v2/testResults/{testId}/highlightreels/{reelId}

A highlight reel download URL is temporary. When the reel is ready, the API returns a pre-signed reelUrl that expires after 15 minutes.

What you will build

A repeatable highlight reel download flow that:

  1. Uses a known testId to list every highlight reel available for that test result.
  2. Stores the uuid for each highlight reel returned GET /testResults/{testId}/highlightreels.
  3. Calls GET /testResults/{testId}/highlightreels/{reelId} for a selected highlight reel.
  4. Polls the same highlight reel endpoint while generation is in progress.
  5. Downloads the highlight reel immediately when a temporary reelUrl is returned.

Target audience

  • Data engineers
  • Research operations teams
  • Analytics engineers
  • AI or ML teams preparing research media for downstream analysis
  • External developers building integrations with UserTesting video assets

Prerequisites

  • A valid access token (ACCESS_TOKEN).
  • A known test result ID (TEST_ID).
  • A client that can retry and poll with backoff.
  • Optional object storage, such as S3 or GCS, if you want to keep a permanent copy of each downloaded highlight reel.

Use the external base URL:

https://api.use2.usertesting.com/api/v2

Steps


Step 1 - List highlight reels for the test result

Endpoint:

GET /api/v2/testResults/{testId}/highlightreels

Example:

curl --location \
  "https://api.use2.usertesting.com/api/v2/testResults/TEST_ID/highlightreels" \
  --header "Authorization: Bearer ACCESS_TOKEN" \
  --header "Content-Type: application/json"

Why this matters:

  • Not every test result has highlight reels.
  • A test result can have more than one highlight reel.
  • The highlight reel list response gives you the uuid values needed for download.
  • The response also indicates whether the study has clips available.

Example response:

{
  "reels": [
    {
      "uuid": "8fdc898f-3b2b-4f45-91a2-2a6b618bc987",
      "name": "Checkout highlights",
      "durationMs": 120000,
      "lastUpdatedAtMs": 1766051123000,
      "numClips": 4,
      "areAllClipsInReel": true
    }
  ],
  "studyWithClips": true
}

Key fields to store:

  • reels[].uuid
  • reels[].name
  • reels[].durationMs
  • reels[].lastUpdatedAtMs
  • reels[].numClips
  • reels[].areAllClipsInReel

Best practice: If reels is an empty array, treat the test result as valid but skip highlight reel download for that test result.


Step 2 - Request a specific highlight reel

Endpoint:

GET /api/v2/testResults/{testId}/highlightreels/{reelId}

Example:

curl --location \
  "https://api.use2.usertesting.com/api/v2/testResults/highlightreels/8fdc898f-3b2b-4f45-91a2-2a6b618bc987" \
  --header "Authorization: Bearer ACCESS_TOKEN" \
  --header "Content-Type: application/json"

Important behavior:

  • This endpoint starts highlight reel generation when no ready generated file exists.
  • The first response can return GENERATING, which means the API has accepted the request and the highlight reel file is not ready yet.
  • Poll the same endpoint until the response returns GENERATED.
  • Only download the highlight reel when status is GENERATED and reelUrl is present.

Example response while generation is in progress:

{
  "reelId": "8fdc898f-3b2b-4f45-91a2-2a6b618bc987",
  "status": "GENERATING",
  "reelUrl": null
}

Example response when the highlight reel is ready:

{
  "reelId": "8fdc898f-3b2b-4f45-91a2-2a6b618bc987",
  "status": "GENERATED",
  "reelUrl": "https://example-presigned-url"
}

Best practice: Do not store reelUrl as the permanent identifier. Treat it as a temporary download URL. Download the highlight reel immediately, then store your own object storage path and metadata.

Step 3 - Poll until the highlight reel is ready

Poll with a bounded retry policy. Do not tight-loop. Start with a short delay, increase the delay between attempts, and stop after a maximum wait time.

Example pseudo-code:

const sleep = (delayMs) =>
  new Promise((resolve) => setTimeout(resolve, delayMs));

async function waitForHighlightReelDownloadUrl({
  reelId,
  accessToken,
}) {
  const maxAttempts = 10;
  const initialDelayMs = 3000;

  for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
    const response = await getHighlightReel({
      reelId,
      accessToken,
    });

    if (response.status === "GENERATED" && response.reelUrl) {
      return response.reelUrl;
    }

    if (response.status === "ERROR") {
      throw new Error(`Highlight reel generation failed for ${reelId}`);
    }

    await sleep(initialDelayMs * attempt);
  }

  throw new Error(`Timed out waiting for highlight reel ${reelId}`);
}

Recommended polling behavior:

  • Poll one highlight reel at a time or use limited concurrency.
  • Use exponential or linear backoff.
  • Stop polling after a fixed number of attempts.
  • Retry later if the highlight reel is still GENERATING after your timeout window.
  • Apply your normal handling for rate limit responses such as 429.

The API is designed to let clients call the same highlight reel endpoint multiple times while the reel is in GENERATING status. Still, clients should poll once every few seconds instead of sending requests in a tight loop.


Step 4 - Download and store the highlight reel


Once reelUrl is available, download the media file immediately. The download URL is temporary and expires after 15 minutes.

Example:

curl --location "REEL_URL" --output "REEL_ID.mp4"

Because pre-signed URLs can contain special characters, always quote the reelUrl value when using command-line tools.

Best practice: Store the downloaded video file in your own storage if you need long-term access. Do not rely on the reelUrl after the 15-minute expiration window.

End-to-end code example

async function downloadTestResultHighlightReels({
  testId,
  accessToken,
}) {
  const reelList = await getHighlightReels({
    testId,
    accessToken,
  });

  for (const reel of reelList.reels) {
    const reelUrl = await waitForHighlightReelDownloadUrl({
      reelId: reel.uuid,
      accessToken,
    });

    const storagePath = await downloadAndStoreHighlightReel({
      reelUrl,
      reelId: reel.uuid,
    });

    await saveHighlightReelMetadata({
      testId,
      reelId: reel.uuid,
      reelName: reel.name,
      durationMs: reel.durationMs,
      lastUpdatedAtMs: reel.lastUpdatedAtMs,
      numClips: reel.numClips,
      areAllClipsInReel: reel.areAllClipsInReel,
      storagePath,
      downloadedAt: new Date().toISOString(),
    });
  }
}

Common errors and troubleshooting

StatusMeaningSuggested handling
400Invalid testId or reelId formatValidate UUIDs before calling the API.
401Invalid or missing access tokenRefresh the access token and retry.
404Test result or highlight reel was not found, or the caller does not have accessConfirm the reel ID came from the test result highlight reel list.
429Rate limit exceededBack off and reduce polling or concurrency.
5xxTemporary service or generation issueRetry with backoff; stop after a bounded timeout.

Status values

StatusMeaningSuggested handling
GENERATINGThe highlight reel file is not ready yet.Wait a few seconds, then call the same endpoint again.
GENERATEDThe highlight reel file is ready.Download the file from reelUrl.
ERRORThe highlight reel could not be generated.Retry after a short delay. If the error continues, stop retrying and handle the failure.

Security and caching considerations

The reelUrl is a pre-signed URL with limited-time access to the generated highlight reel file.

Follow these recommendations:

  • Do not log the full reelUrl.
  • Do not expose the reelUrl to users or systems that should not access the video.
  • Do not store the reelUrl as a permanent download link.
  • Do not cache API responses that contain signed URLs.
  • Download the file within 15 minutes of receiving the URL.

For responses that contain a signed URL, use private, no-store caching behavior in your application.

Cache-Control: private, no-store

Summary

The highlight reel download workflow is a two-step read plus generation flow:

  1. Call GET /api/v2/testResults/{testId}/highlightreels to discover highlight reel IDs.
  2. Call GET /api/v2/testResults/highlightreels/{reelId} for each selected highlight reel.
  3. Poll while the highlight reel status is GENERATING.
  4. Download the highlight reel only after the status is GENERATED and reelUrl is present.

Because highlight reel generation is asynchronous, clients should treat the highlight reel detail endpoint as a request-or-status endpoint, not as a guaranteed immediate file download.