# Vimeo

- Tool: Bubble
- Difficulty: Beginner
- Time required: 45–60 minutes
- Last updated: July 2026

## TL;DR

Connect Bubble to Vimeo by adding the API Connector plugin, setting your personal access token in a Private Authorization header, and calling GET /me/videos to build a professional video gallery. Vimeo personal tokens never expire, so there is no refresh workflow to maintain — making this the cleanest video API integration available for Bubble apps.

## Why Vimeo Is the Easiest Video API for Bubble

Bubble developers often start with YouTube, then discover the daily quota system, API key restrictions, and complex playlist hierarchy. Vimeo takes a different approach: generate one personal access token at developer.vimeo.com/apps, paste it into an API Connector header marked Private, and you are authenticating immediately. No OAuth consent flow, no token exchange endpoint, no scheduled refresh workflow. The token is permanent until you revoke it yourself.

Vimeo's API at api.vimeo.com covers everything a professional video Bubble app needs: listing your video library with privacy controls, fetching thumbnails and statistics, and updating video metadata directly from a Bubble admin page. The player itself lives in an HTML iframe element pointed at player.vimeo.com.

The one entry requirement is a Vimeo Pro plan or above — Vimeo Basic (free) accounts cannot generate API tokens. This is the single most common reason founders hit 403 errors when trying this integration for the first time. Confirm your Vimeo plan before starting.

Bubble's server-side API Connector proxy handles all calls, so CORS is not an issue and your token is never exposed in browser network requests. The integration fits well within Bubble's free and paid plans because it uses standard API Connector calls rather than Backend Workflows.

## Before you start

- A Vimeo Pro, Business, or Premium account — Vimeo Basic (free) accounts cannot generate API tokens and will receive 403 on all API calls
- A Bubble app on any plan (free plan works for read-only API Connector calls; Backend Workflows for advanced automation require a paid Bubble plan)
- The API Connector plugin installed in your Bubble app (Plugins tab → Add plugins → search 'API Connector' by Bubble)
- A developer.vimeo.com account to register your app and generate a personal access token

## Step-by-step guide

### 1. Register Your App and Generate a Personal Access Token

Open developer.vimeo.com/apps in your browser and sign in with your Vimeo Pro (or higher) account. Click 'Create a new app' in the top-right corner. Give your app a name such as 'Bubble Integration' and a brief description — this is for your records only and does not affect functionality. Click 'Create app.'

Once the app is created, you land on the app settings page. Click the 'Authentication' tab. Scroll to the section labeled 'Generate an Access Token.' Under 'Scopes,' select the following: Public (read public video data), Private (read private videos), Edit (update video metadata), Video Files (access downloadable file URLs), and Stats (read view count and engagement data). Select only what your Bubble app needs — you can always revoke and regenerate with different scopes later.

Click 'Generate' to create your personal access token. Copy the token immediately — Vimeo will not display it again after you leave this page. Store it somewhere secure (a password manager or a local notes file) before continuing. Note the scopes you selected alongside the token for future reference.

Important: this is a personal access token tied to your Vimeo account, not user-specific OAuth. Every API call made with this token acts as your account. If you need user-specific access (letting visitors access their own private Vimeo libraries), you would need to build a full OAuth 2.0 flow — but for the most common Bubble use case (showing your own videos), this personal token is the correct and simplest approach.

**Expected result:** You have a personal access token string (starting with a long alphanumeric sequence) copied to your clipboard and saved securely.

### 2. Add the API Connector and Configure Shared Headers

In your Bubble app editor, click the Plugins tab in the left sidebar. Click 'Add plugins,' search for 'API Connector' (published by Bubble), and click Install. Close the plugin search modal.

With the API Connector installed, click the Plugins tab again and select API Connector from the list. Click 'Add another API' to create a new API definition. Name it 'Vimeo API.'

In the 'Shared headers' section, add two headers that will apply to every call you create under this API definition:

Header 1:
- Key: Authorization
- Value: Bearer YOUR_PERSONAL_ACCESS_TOKEN (replace with the token you copied in Step 1)
- Check the 'Private' checkbox — this is critical. Marking it Private tells Bubble to keep this header on the server and never send it to the browser.

Header 2:
- Key: Accept
- Value: application/vnd.vimeo.*+json;version=3.4

The Accept header pins the Vimeo API to version 3.4, ensuring consistent JSON response structure. Without it, Vimeo may return different field layouts as their API evolves.

Set the 'Authentication' dropdown to 'None' — you are handling auth manually through the header. Leave 'Development base URL' blank for now; you will set the full endpoint URL on each individual call.

```
{
  "shared_headers": {
    "Authorization": "Bearer <private>",
    "Accept": "application/vnd.vimeo.*+json;version=3.4"
  }
}
```

**Expected result:** The Vimeo API entry appears in your API Connector with both shared headers configured, the Authorization header marked Private, and no authentication dropdown selection.

### 3. Create the GET /me/videos Call and Initialize It

Inside your Vimeo API Connector definition, click 'Add another call.' Configure the call as follows:

- Name: Get My Videos
- Method: GET
- URL: https://api.vimeo.com/me/videos

In the 'Parameters' section (URL parameters), add these fields. Bubble will append them as query string parameters:
- fields: uri,name,description,duration,created_time,stats,privacy,link,pictures  (marks this as optional=no, with no default value — you will set it to this string in the call configuration)
- per_page: 25 (optional, default 25)
- page: 1 (optional, default 1)
- sort: modified_time (optional)
- direction: desc (optional)

The fields parameter is critical for performance. A full Vimeo video object without field filtering can be 20KB or more per video due to extensive metadata. Specifying only the fields your Bubble app displays reduces response size significantly — important for WU efficiency and page load speed.

Scroll to the bottom of the call configuration and click 'Initialize call.' Bubble will make a live request to the Vimeo API using your real token. If your Vimeo account has at least one video, Bubble will receive a response and automatically detect the fields in the data array.

After a successful response, change 'Use as' to 'Data' so Bubble can use this call to populate repeating groups. Review the detected fields — you should see entries for name, description, duration, uri, link, and nested objects for stats and pictures. If Bubble did not auto-detect nested fields you need, click the pencil icon next to the response definition and define them manually using JSON path notation.

```
{
  "method": "GET",
  "url": "https://api.vimeo.com/me/videos",
  "headers": {
    "Authorization": "Bearer <private>",
    "Accept": "application/vnd.vimeo.*+json;version=3.4"
  },
  "params": {
    "fields": "uri,name,description,duration,created_time,stats,privacy,link,pictures",
    "per_page": "25",
    "page": "1",
    "sort": "modified_time",
    "direction": "desc"
  }
}
```

**Expected result:** Bubble shows a green success indicator after initializing the call, and the response definition panel displays detected fields including name, uri, duration, created_time, and nested stats/pictures objects. The 'Use as' dropdown is set to Data.

### 4. Extract the Video ID from Vimeo's URI Field

Vimeo's API does not return a standalone numeric video ID in its responses. Instead, it returns a uri field with a value like /videos/12345678. To embed a video or construct player URLs, you need just the numeric portion: 12345678.

In Bubble, you can extract this number using text expressions without any custom code. Wherever you need the video ID — in an iframe URL, in a PATCH call, or in a custom state — apply this expression chain to the uri field from the API response:

1. Start with the API call's uri field value (example: /videos/12345678)
2. Apply :split by '/' — this creates a list: ['', 'videos', '12345678']
3. Apply :last item — this gives you '12345678'

In the Bubble expression editor, this looks like:
Get My Videos's data uri:split by "/":last item

Create a Custom State on the repeating group's parent page named 'selected_video_id' with type text. When a user clicks a row in the repeating group, trigger a 'Set state' action that sets selected_video_id to this uri-extracted value. The HTML iframe element for the player will then use this state value to construct the embed URL dynamically.

You can also store this extracted ID in a Bubble database field if you are caching video metadata for faster page loads — but remember that caching thumbnail URLs (which come from Vimeo's pictures object) is not recommended, as those pre-signed CDN URLs can expire. Store only the video ID and metadata; always fetch thumbnails fresh from the API.

**Expected result:** You can reliably extract a numeric video ID string from any Vimeo uri field value, and a Custom State on the page holds the currently selected video ID.

### 5. Build the Video Library Repeating Group

Add a Repeating Group to your Bubble page. In the repeating group's Data source, select 'Get data from an external API,' choose your 'Vimeo API - Get My Videos' call, and set the response list to the data array returned by the API. Bubble will recognize this as a list of video objects.

Inside the repeating group cell, add the following elements:

Thumbnail image: Add an Image element. Set its data source to Current Cell's Get My Videos's data's pictures. Vimeo returns a pictures object with a sizes array — navigate to sizes, and use an index of 3 or 4 to get a medium-resolution thumbnail (approximately 640px wide). The exact Bubble expression: Current Cell's Vimeo API - Get My Videos's data pictures sizes:item #4 link.

Video title: Add a Text element. Set its content to Current Cell's data name.

Duration: Vimeo returns duration in seconds as an integer. Format it for display using Bubble's :formatted as expression or a calculated field that divides by 60 and rounds.

Privacy badge: Vimeo's privacy object includes a view field with values such as 'anybody,' 'nobody,' 'password,' and 'unlisted.' Display this as a conditional text or color-coded badge using Bubble's :is operator.

View count: Navigate to stats.plays to display the view count. stats is a nested object; in Bubble's API Connector response definition, ensure stats.plays is defined as a number field.

Click action: Add a 'When this cell is clicked' workflow. The action should be 'Set state' on the page's Custom State selected_video_id, with the value set to the uri-extracted video ID (from Step 4). This triggers the iframe player to update below the repeating group.

**Expected result:** The repeating group populates with video thumbnails, titles, duration, privacy badges, and view counts from your Vimeo library. Clicking a cell updates the Custom State with the video's numeric ID.

### 6. Embed the Vimeo Player with an HTML Element

Bubble has no native Vimeo video element, so you embed the player using an HTML element with an iframe. This is the standard and fully supported method for Vimeo playback in Bubble.

Add an HTML element to your page below the repeating group. In the HTML editor, enter the following iframe markup:

<iframe
  src="https://player.vimeo.com/video/VIDEOID?autoplay=0&title=1&byline=0&portrait=0"
  width="100%"
  height="100%"
  frameborder="0"
  allow="autoplay; fullscreen; picture-in-picture"
  allowfullscreen>
</iframe>

Replace VIDEOID with a dynamic value from your Custom State. In Bubble's HTML element, click the 'Insert dynamic data' button to insert the selected_video_id Custom State into the src URL at the correct position.

For additional admin functionality — updating a video's title or privacy setting from a Bubble form — add a second API Connector call for PATCH /videos/{id}:
- Method: PATCH
- URL: https://api.vimeo.com/videos/[Dynamic video ID] (use Bubble's dynamic path syntax)
- Body type: JSON
- Body: {"name": "[new title]", "privacy": {"view": "nobody"}}
- Use as: Action

Wire the PATCH call to a Bubble form workflow. This lets an admin change video titles and privacy levels from inside your Bubble app without opening Vimeo's dashboard. If you want RapidDev's team to help design a complete video management panel for Bubble — including privacy toggling, bulk metadata updates, and viewer analytics dashboards — book a free scoping call at rapidevelopers.com/contact.

```
<iframe
  src="https://player.vimeo.com/video/[VIDEOID]?autoplay=0&title=1&byline=0&portrait=0"
  width="100%"
  height="100%"
  frameborder="0"
  allow="autoplay; fullscreen; picture-in-picture"
  allowfullscreen>
</iframe>
```

**Expected result:** When a user clicks a video in the repeating group, the Vimeo player iframe below it loads that video and is ready to play. The PATCH admin call successfully updates video metadata from a Bubble form without opening Vimeo's dashboard.

## Best practices

- Always mark the Authorization header Private in Bubble's API Connector — this is the only step that keeps your Vimeo token server-side and out of browser network requests.
- Use the fields URL parameter in every GET /me/videos call to request only the fields your Bubble app displays. A full video object without field filtering can exceed 20KB per video, increasing WU consumption and page load time.
- Never cache Vimeo thumbnail URLs in your Bubble database. Vimeo returns pre-signed CDN URLs in the pictures.sizes array that can expire. Always fetch thumbnails fresh from the API response and bind them directly to Image elements.
- Audit your token scopes at developer.vimeo.com/apps → Authentication tab before launching. Remove scopes your app does not use — if Bubble only displays videos, you only need Public and Private, not Edit or Video Files.
- Add a privacy badge to your repeating group displaying the video's privacy.view value. This helps admins immediately see which videos are public, private, or password-protected without opening Vimeo's dashboard.
- Set up Bubble's Data tab → Privacy rules on any Bubble database records that store Vimeo video metadata. Without privacy rules, any user can query these records through Bubble's data API.
- Test the iframe embed with at least one video set to privacy 'unlisted' or 'anybody' to confirm playback works before building the full UI. Some Vimeo privacy settings require domain-level embed allowlisting that must be configured in Vimeo's video settings.
- For video course platforms where individual videos should be visible only to specific users, do not rely solely on Vimeo's privacy controls. Implement access checks in your Bubble workflows so the iframe is only rendered after confirming the current user has the appropriate enrollment record.

## Use cases

### Professional Video Course Platform

Build a Bubble learning platform where instructors upload videos to Vimeo with privacy set to 'only people with the link,' then your Bubble app lists and embeds those videos for enrolled students using the Vimeo API. Students never see the direct Vimeo URL — only the embedded player on your branded Bubble page.

Prompt example:

```
Show me how to build a Bubble page that lists course videos from a Vimeo account in a repeating group, displays each video's title and duration, and embeds the selected video in an iframe when a student clicks a thumbnail.
```

### Client Video Portal with Privacy Controls

Create a Bubble portal where each client logs in and sees only their own review videos hosted on Vimeo. Use the Vimeo API's privacy.view field to confirm video access settings, and display the player inline so clients can watch deliverables without leaving your branded portal or needing a Vimeo account.

Prompt example:

```
How do I build a Bubble client portal that pulls videos from a specific Vimeo folder for each client and embeds them with the Vimeo player, showing title, upload date, and a download link?
```

### Video Portfolio Admin Panel

Build a Bubble admin page that lists all videos in a Vimeo account with their current privacy setting and view count, and lets an admin change the privacy level directly from Bubble using PATCH /videos/{id} — without the admin needing to open Vimeo's own dashboard.

Prompt example:

```
Can you show me how to create a Bubble admin panel that fetches all videos from Vimeo, displays their privacy status and stats, and lets me toggle a video between public and private using the Vimeo API?
```

## Troubleshooting

### 403 Forbidden on every API call, even with the correct token

Cause: Vimeo API access requires at least a Pro plan. Vimeo Basic (free) accounts cannot generate API tokens, and any token generated before a plan downgrade will return 403 on all calls.

Solution: Log in to vimeo.com and check your current plan under Account Settings. If you are on Basic, upgrade to Pro or higher. If you recently downgraded, upgrade your plan and regenerate your token.

### 401 Unauthorized despite pasting the token correctly

Cause: The Authorization header value is missing the 'Bearer ' prefix (including the space), or the token was copied with extra whitespace or a newline character.

Solution: In the API Connector, open the shared header and confirm the value is exactly 'Bearer YOURTOKEN' — the word Bearer, a single space, then the token string with no leading or trailing spaces. Delete and retype the header value to eliminate invisible characters.

### 'There was an issue setting up your call' when clicking Initialize call

Cause: The Initialize call makes a live request to Vimeo. This error appears when the request fails — most commonly due to a 401/403 (token issue, wrong scopes, free plan) or when the Vimeo account has no videos to return (empty response cannot be auto-detected).

Solution: First verify the API call manually by copying the full URL and headers into a tool like Hoppscotch or Postman and confirming you get a 200 response with video data. If your account has no videos, upload at least one test video to Vimeo before initializing. Then retry the Initialize call in Bubble.

### Thumbnail images appear broken or the Image element shows a placeholder

Cause: Vimeo's pictures.sizes array index may vary by video — some videos have fewer size variants, causing an out-of-bounds index access to return nothing. Alternatively, the API response definition in Bubble's API Connector may not have correctly mapped the nested pictures path.

Solution: In the API Connector response definition, expand the pictures object and confirm that sizes is defined as a list. Reduce the index from 4 to 3 or 2. Add a conditional on the Image element: if the dynamic source is empty, display a fallback placeholder image.

### Vimeo player iframe shows a blank area or the 'video not found' error

Cause: The video ID extracted from the URI is empty or incorrect, or the video's privacy setting ('nobody') prevents iframe embedding without a password or allowlist.

Solution: Verify the Custom State value by temporarily displaying it in a text element on the page — confirm it contains a numeric string like '12345678'. For privacy issues, check the video's privacy.view setting via the API response and ensure embeds are enabled on the Vimeo video settings page (embed permission must be set to 'Anywhere' or your specific domain).

## Frequently asked questions

### Do Vimeo personal access tokens expire?

No — Vimeo personal access tokens do not expire automatically. They remain valid until you manually revoke them in your Vimeo app settings at developer.vimeo.com/apps → Authentication tab. This is one of Vimeo's key advantages over Spotify (1-hour tokens) and Adobe APIs (24-hour tokens) — you do not need any scheduled refresh workflows in Bubble.

### Does this integration work on Bubble's free plan?

Yes, read-only API Connector calls (GET /me/videos, GET /videos/{id}) work on Bubble's free plan. Bubble's API Connector plugin is available on all plans. If you need Backend Workflows for automation — for example, automatically updating Vimeo video privacy when a course enrollment is created — those require a paid Bubble plan.

### Can I upload videos to Vimeo from Bubble?

Vimeo's upload API uses a multi-step process: create an upload slot with POST /me/videos to get an upload_link, then PUT the video file to that upload_link (a tus.io protocol URL), then optionally PATCH /videos/{id} to set metadata. File uploads from Bubble to external APIs are complex because Bubble handles files through its own storage. This workflow is advanced and typically requires custom JavaScript or an intermediate storage step. It is possible but outside the scope of a standard Bubble API Connector tutorial — contact RapidDev at rapidevelopers.com/contact for a custom scoping conversation.

### Why does my Vimeo video not play when embedded in the Bubble HTML element?

The two most common reasons are: (1) the video's embed settings in Vimeo restrict playback to specific domains — open the video in Vimeo's dashboard, go to Settings → Embed, and ensure your Bubble app domain is in the allowlist or set to 'Anywhere'; (2) the video's privacy is set to 'nobody' which prevents public embedding entirely. Check the privacy.view value in the API response and adjust the Vimeo video settings if needed.

### How do I show only specific videos to specific users in Bubble?

Vimeo's API returns all videos in your account. To control which videos a specific Bubble user sees, store a mapping in your Bubble database: a table that links User records to Vimeo video URIs (or extracted IDs). On the video page, fetch only the video IDs from this table for the current user, then pass those IDs to GET /videos/{id} calls. Do not rely on Vimeo privacy controls alone for per-user access in a Bubble app — enforce access logic in Bubble workflows.

### What is the correct Vimeo API version to use in Bubble?

Set the Accept header to 'application/vnd.vimeo.*+json;version=3.4' in your Bubble API Connector shared headers. This pins the API to version 3.4 and ensures consistent JSON response field structure. Without this header, Vimeo may return different field layouts as they release updates, which could break your Bubble API Connector response definitions unexpectedly.

---

Source: https://www.rapidevelopers.com/bubble-integrations/vimeo
© RapidDev — https://www.rapidevelopers.com/bubble-integrations/vimeo
