Migrate a Video Library to Wistia with the Upload API

So you've got a library of videos living on another platform, Vimeo, Vidyard, Brightcove, YouTube, or your own storage, and you want to move it into Wistia. This guide covers when you can do that yourself with the Upload API, what you'll need, how to import in bulk, and what does (and doesn't) come along for the ride.

📝

Which sources are assisted?

Wistia's CSM-assisted migration covers Vimeo, Vidyard, and Brightcove only. For YouTube or any other source, the path is self-serve: get the video files (or direct file URLs) yourself, then upload them to Wistia with the Upload API as described below.

Two ways to migrate

There are two distinct paths, and which one you use depends on whether your videos are reachable at a public URL.

PathUse it whenWho runs it
Self-serve via the Upload APIYour videos can be downloaded from a public (or signed) URL, or you can upload the files directly.You
CSM-assisted migrationYour videos live behind a source platform's API, Vimeo, Vidyard, or Brightcove, and aren't individually downloadable, or you're moving thousands of videos.Wistia, using a token you provide

This page is about the self-serve API path. If your source videos aren't reachable as direct file URLs, which is common for platforms like Vimeo, Vidyard, and Brightcove that gate downloads behind their own API, Wistia offers a CSM-assisted migration for those platforms (see When to involve Wistia below).

Before you start

You'll need:

  • An API access token with the Upload scope. Create one in the API tab of your Account Settings. When creating the token, enable the "Upload videos" permission. Only the Account Owner can create tokens.
  • A destination project ID. Every uploaded media lands in a project. Create the project from the Create menu in your account first, then grab the hashed ID from the project page URL (e.g. bgdrq7qysq in https://home.wistia.com/projects/bgdrq7qysq).
  • A publicly accessible URL for each video (for URL import) or the video files themselves (for direct upload).
📝

Folders vs. projects

In the app and the modern Data API, these containers are called folders. The Upload API parameter is still named project_id it's the same container, just the older name. Pass the folder's hashed ID as project_id.

📘

Tokens belong in server-side code only

Never put an upload token in client-side code or commit it to a repository. For browser-based uploads, use the Wistia Uploader with an expiring token instead.

Importing from a URL

The fastest way to migrate is to point Wistia at each video's public URL and let Wistia pull it in. Send a POST to https://upload.wistia.com/ with the url parameter:

curl -X POST "https://upload.wistia.com/" \
  -H "Authorization: Bearer YOUR_TOKEN_HERE" \
  -d "url=https://example.com/videos/launch-recap.mp4" \
  -d "project_id=bgdrq7qysq" \
  -d "name=Launch Recap" \
  -d "description=Q3 product launch highlights" \
  -d "low_priority=true"

A successful request returns the new media's hashed_id, id, name, and a progress value between 0 and 1. Hold on to the hashed_id That's how you'll reference the media everywhere else in Wistia's APIs.

Uploading a local file

If your videos aren't reachable at a URL, upload the file directly with multipart/form-data:

curl -X POST "https://upload.wistia.com/" \
  -H "Authorization: Bearer YOUR_TOKEN_HERE" \
  -F "file=@/path/to/launch-recap.mp4" \
  -F "project_id=bgdrq7qysq" \
  -F "name=Launch Recap"

Bulk migrations: use low_priority

When you're importing a whole library, set low_priority=true on each request. This tells Wistia's encoding service to treat the import as lower priority than interactive uploads, so a large migration doesn't crowd out the day-to-day uploads happening elsewhere in your account. It's the recommended setting for any bulk or migration job. (Setting it to false has no effect, it's opt-in only.)

Keep these limits in mind when scripting a bulk run:

  • Rate limit: 600 requests/minute to upload.wistia.com and api.wistia.com combined. Above that, you'll get an HTTP 429 with a Retry-After header back off for the number of seconds it specifies.
  • Account video limits apply. If your import would push you past your plan's media limit, the upload returns 400 with an upload_failed error. Check your plan's capacity before a large migration.

A simple loop is usually all you need: read your source list, POST each URL with low_priority=true, record the returned hashed_id, and re-try any 429s after the indicated delay.

What carries over and what doesn't

The Upload API moves the video file and a small amount of metadata. Everything else has to be set after the fact.

Carries over at upload time (pass these as parameters):

  • name - display name
  • description - media description

Does not carry over automatically:

  • Captions/subtitles. Download the SRT/VTT from your source platform and add it to the media in Wistia after upload - there's no caption import through the Upload API.
  • Thumbnails, chapters, custom player settings, and embed configurations. These are Wistia-side settings; configure them after the media exists.
  • View counts and historical analytics. Analytics start fresh in Wistia from the import date.
  • Folder/category structure from the source platform. You control the destination structure with project_id — decide your project layout up front and import each video into the right project.

To set additional metadata after upload, use the Data API with the hashed_id returned by the import.

When to involve Wistia

Wistia offers a CSM-assisted migration from Vimeo, Vidyard, and Brightcove for accounts with a Customer Success Manager. You provide your source-platform API token to your CSM, and Wistia runs the import. Contact your Wistia CSM to start.

Reach for the assisted migration instead of self-serving when:

  • Your source videos live on Vimeo, Vidyard, or Brightcove and can't be exposed as direct file URLs (these platforms gate downloads behind their own API).
  • You're moving a very large library (thousands of videos) and want Wistia to manage the import.