Skip to main content
Run bunny skills install --global so AI coding agents, such as Claude Code, Cursor, and Codex, can run this migration for you. Then ask your agent: “Migrate my Vimeo videos to Bunny Stream.”
bunny stream import is in Public Preview and still in development. Commands, flags, and output may change, so what you see can differ from the examples in this guide. To report a bug, open an issue on the Bunny CLI repository.
Bunny Stream bills only for the storage and bandwidth you use. See the Bunny Stream pricing page for current rates.

Overview

Diagram of the Bunny CLI listing Vimeo folders and videos and Bunny Stream fetching each file directly from Vimeo
The Bunny CLI lists every video on your Vimeo account and hands each one to Bunny Stream, which fetches the best available file directly from Vimeo. Nothing is downloaded to your machine. Each Vimeo folder becomes a Bunny Stream collection with the same name. Each imported video is tagged with its Vimeo video ID under the vimeoId metatag, so running the import again skips videos that are already imported.

Scope

The import copies the video files, their titles, descriptions, and tags, and your folder structure. Settings that control who can watch your videos and where stay on Vimeo, so plan to set up their Bunny equivalents.
Private and unlisted videos are not private on Bunny. The import copies every video your token can read, including private, unlisted, and password-protected ones, but not their privacy settings. Every imported video follows the security settings of its Bunny library, and a new library allows playback from any site. On Bunny, a video that was private or unlisted on Vimeo plays for anyone with its URL until you protect the library. Before you publish the new URLs, set up Allowed domains to replace Vimeo’s embed domain restrictions, and turn on embed view token authentication or CDN token authentication for videos that only signed-in viewers should see. If the videos that need protection are in their own Vimeo folders, you can import those folders into a separate library with --folder and give that library stricter settings.

Prerequisites

  • A bunny.net account
  • A Vimeo account on a plan that allows video file access: Standard, Advanced, or Enterprise, or a legacy Plus, Pro, Business, or Premium plan. Free and Starter plans cannot download video files through the API.

Migrate your videos

1

Install and authenticate the Bunny CLI

Install the Bunny CLI with the shell installer or npm:
The installer downloads a prebuilt binary for your platform and places it on your PATH.
See Installation for more options. Then authenticate the CLI with your bunny.net account:
bunny login opens your browser to complete authentication and stores the credentials locally. The first time you log in from an interactive terminal, it also offers to install the agent skill for AI coding tools. On a remote machine or in CI without a browser, run bunny login --api-key "$BUNNYNET_API_KEY" instead, with a key from Account Settings > API key.
2

Create a Bunny Stream library

Create a library for the imported videos, or skip this step to use an existing one:
DE is always the main storage region. Replicate to the regions closest to your audience, from UK, SE, NY, LA, SG, SYD, BR, and JH. You can’t remove a replication region later.
Set encoding options, such as --resolutions or --encoding-tier, when you create the library. Changes you make later apply only to new uploads, not to videos that are already imported. Run bunny stream libraries create --help to see every option, or read Encoding.
When the CLI asks how to add videos, choose Later. You start the import in the next steps.Copy the library ID from the output. You pass it to --library in the import commands. The flag also accepts the library’s name, and --lib works as a short alias.
3

Create a Vimeo access token

The Bunny CLI needs a Vimeo personal access token with these scopes:
  • Public and Private: to read every video on your account, including private and unlisted ones
  • Video Files: to read the download links for each video
Open My Apps on the Vimeo developer site. If you don’t have an app yet, click Create an app. Enter an app name, such as migrate-to-bunny, and a brief description, select No for whether people besides you will access the app, accept the Vimeo terms, and click Create App.
The Create a new app form on the Vimeo developer site
On the app’s page, select Generate Access Token under Authentication in the left-hand navigation:
The Vimeo app page with Generate Access Token selected in the navigation
Choose Authenticated (you), so the token can read the private videos on your account. Under Scopes, Public is already checked, so also check Private and Video Files. Click Generate.
The Generate Access Token form in Vimeo with the Public, Private, and Video Files scopes checked
The new token appears under Personal Access Tokens with the scopes private, video_files, and public. Copy the value from the Token column.
The Personal Access Tokens list in Vimeo showing the new token and its scopes
4

Preview the migration with a dry run

Run the import with --dry-run, using the library ID from step 2:
--dry-run prints the import plan without making any changes to either platform.The CLI then prompts for your Vimeo access token. Paste it at the Access Token prompt:
Once Vimeo accepts the token, the CLI offers to save it so later runs skip this prompt. Press Enter to accept:
The CLI stores saved credentials in ~/.config/bunnynet/stream-import-credentials.json (or under $XDG_CONFIG_HOME/bunnynet/ when it is set). Only your user account can read the file, and it is separate from the main Bunny CLI config. Saved credentials belong to the active Bunny CLI profile. If Vimeo later rejects them, for example after you revoke the token, the CLI deletes them and prompts again on the next run. If you answer no, the CLI prompts on every run.The VIMEO_ACCESS_TOKEN environment variable always takes priority over a saved token.
The dry run then prints a summary and the import plan:
Already imported counts videos that are already in the library, and To import counts the ones a real run would import. The size comes from Vimeo’s download links, so if the summary has no Size row, check that your plan allows video file access and that the token has the Video Files scope.The plan groups videos by the collection they will land in. Each Vimeo folder maps to a collection of the same name, and videos outside any folder are listed under (no collection).Bunny Stream accepts sources up to 2160p (3840x2160, or 2160x3840 in portrait) and up to 72 hours long, while Vimeo hosts videos up to 8K. The dry run warns about any video beyond those limits, as it will fail on Bunny:
5

Run the import

Run the same command without --dry-run:
The CLI prints the same summary, then asks for confirmation. Type y and press Enter to start:
The CLI creates a collection for each folder, skips videos that are already imported, hands the rest to Bunny three at a time, and tags each video with vimeoId, along with its Vimeo description and tags. It returns once every video is queued. Bunny then fetches each file directly from Vimeo and encodes it.
Collection names match without regard to case, so Vimeo folders named Webinars and webinars land in one collection. Rename one of them in Vimeo before the import to keep them separate.The import command also accepts these flags:
  • --wait keeps the command running, with a live encoding progress indicator, until Bunny has encoded every video.
  • --force skips the confirmation prompt and the offer to retry failed videos, for unattended or CI runs.
  • --concurrency N sets how many videos the CLI passes to Bunny in parallel, from 1 to 20.
  • --clean-failed deletes the failed Bunny copies of videos before importing them again, including videos that Bunny rejected.
  • --retry-stalled deletes and imports again any video stuck at zero bytes on Bunny.
  • --request-timeout sets how many seconds one request to Vimeo or Bunny can take before it gives up (default 30).
  • --video-timeout sets how many seconds the hand-off of one video to Bunny, or with --wait its encoding, can take before it gives up (default 5400).
Run bunny stream import --help for the full list.To migrate a large account one folder at a time, list the folders and their IDs:
Preview a folder’s videos with --folder, then pass the same ID to the import:
The import works the same way, limited to that folder’s videos and its collection.
6

Watch encoding progress

The import returns before Bunny finishes encoding. Check progress with the status command:
It prints one row per queued video, with its status on Bunny, encode percentage, size, and when it was queued:
Run it again until the last line reports 0 processing. The command exits with a non-zero code when any video has failed, so you can also use it as a check in scripts.
7

Verify in the bunny.net dashboard

Open the bunny.net dashboard and go to Stream > Your library > Manage library. Each Vimeo folder appears as a collection, and every migrated video is listed under Latest videos.
The Manage library page in the bunny.net dashboard showing the imported collections and videos
Set up the library’s security settings if you have not already, then replace the Vimeo embeds (player.vimeo.com iframes) and links in your site with their Bunny Stream equivalents. See Embedding videos for the embed and player options.

Troubleshooting

When videos fail during an interactive import, the CLI lists each failure and offers to retry them:
Answer y to retry them in the same run. If the import was interrupted, or you declined the retry, run it again with --resume:
--resume retries failed videos, processes any that were still outstanding, and re-applies the vimeoId tag to videos Bunny fetched before the run stopped. When the interrupted run was limited to one folder, the resume continues that folder. It stops retrying a video after three failed attempts and skips videos that Bunny rejected. To retry those too, add --clean-failed, which deletes their Bunny copies first.Running the import again is always safe. Videos that already carry the vimeoId tag are skipped, and the CLI reports Everything is already imported once nothing is left.
Vimeo returned no downloadable file for that video. This happens when your Vimeo plan does not allow video file access, when the token is missing the Video Files scope, or when the video was deleted from Vimeo after the import started.
Vimeo rejected the token. Check that you copied the whole value, then run the command again to re-enter it.
If bunny stream import status reports videos stuck at zero bytes, run the import again with --retry-stalled to delete and fetch them again.
Last modified on November 5, 2026