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.
| Fact | Value |
|---|---|
| Tool | Vimeo |
| Category | Media & Content |
| Method | Bubble API Connector |
| Difficulty | Beginner |
| Time required | 45–60 minutes |
| Last updated | July 2026 |
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.
Integration method
Bubble API Connector hitting the Vimeo API with a permanent personal access token in a Private Authorization header.
Prerequisites
- 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
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.
Pro tip: Choose scopes conservatively. If your Bubble app only displays videos, you only need Public and Private scopes. Add Edit and Stats only when you need those capabilities — following the principle of least privilege.
Expected result: You have a personal access token string (starting with a long alphanumeric sequence) copied to your clipboard and saved securely.
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.
1{2 "shared_headers": {3 "Authorization": "Bearer <private>",4 "Accept": "application/vnd.vimeo.*+json;version=3.4"5 }6}Pro tip: The 'Private' checkbox on the Authorization header is the key security step. Without it, the Bearer token would be visible in browser network requests, allowing anyone inspecting your Bubble app's network traffic to extract your Vimeo credentials.
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.
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.
1{2 "method": "GET",3 "url": "https://api.vimeo.com/me/videos",4 "headers": {5 "Authorization": "Bearer <private>",6 "Accept": "application/vnd.vimeo.*+json;version=3.4"7 },8 "params": {9 "fields": "uri,name,description,duration,created_time,stats,privacy,link,pictures",10 "per_page": "25",11 "page": "1",12 "sort": "modified_time",13 "direction": "desc"14 }15}Pro tip: The Initialize call step requires a real successful response from Vimeo. If you see 'There was an issue setting up your call,' the most common cause is a 403 from Vimeo (Basic account) or a 401 (incorrect token format — confirm the header value starts with 'Bearer ' followed by your token, with a space between the word and the token).
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.
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.
Pro tip: Test the :split by '/' + :last item chain by temporarily dropping a text element on a test page and displaying the expression result. Confirm you see a numeric string like '12345678' before wiring it into your iframe and Custom State.
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.
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.
Pro tip: If thumbnail images appear broken, check whether the pictures.sizes array index you chose (3 or 4) is within bounds for your videos. Some Vimeo videos may have fewer size variants. Add a conditional: if the image source is empty, fall back to a placeholder image URL.
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.
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.
1<iframe2 src="https://player.vimeo.com/video/[VIDEOID]?autoplay=0&title=1&byline=0&portrait=0"3 width="100%"4 height="100%"5 frameborder="0"6 allow="autoplay; fullscreen; picture-in-picture"7 allowfullscreen>8</iframe>Pro tip: Set autoplay=0 in the iframe src parameters by default. Autoplay with sound is blocked by most browsers unless triggered by a direct user gesture. If you want autoplay, add a user-initiated play button that updates the Custom State (which refreshes the iframe src) rather than setting autoplay=1 statically.
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.
Common 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.
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.
Copy this prompt to try it in Bubble
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.
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?
Copy this prompt to try it in Bubble
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.
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?
Copy this prompt to try it in Bubble
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).
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.
Alternatives
YouTube is better for public-reach video content targeting large audiences via organic search and YouTube's own discovery algorithm. However, it requires daily quota management (10,000 units/day free), Google Cloud project setup, and API key restrictions. Vimeo is better for professional, private, or client-facing video hosting where per-video privacy controls matter and you want a cleaner integration with no quota system.
SoundCloud is audio-only and uses a simple client_id URL parameter for public data — even simpler than Vimeo's personal token. It targets independent artist catalogs and music player features. Vimeo is the right choice when your Bubble app needs professional video hosting with privacy controls rather than audio streaming.
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.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation