Bubble has no screenshot element, but its API Connector plugin can call the RenderScreenshot API and store the returned image in a field like any upload. This page gives you the exact call settings, shows how to bind the result to an image field, and covers the two mistakes that cost credits in Bubble: initializing too often, and running the call on page load. It is part of our integrations hub.
Status: written 2026-10-15 from the API's documented request and response shapes. The settings below have not been run in a live Bubble app yet, so there are no Bubble UI screenshots on this page. The API side (the GET URL, headers and responses) matches the GET endpoint reference.
What you can build
- A link directory with thumbnails. When a user submits a website, a workflow captures it and saves the image on the new Listing.
- Client approval boards. An agency app captures each staging page on request, so a client can compare versions side by side.
- Social cards for user pages. Each public profile gets a 1200x630 card in the
og_cardpreset, saved on the profile and used in the page's SEO settings.
Prerequisites
- A Bubble app with the API Connector plugin installed (by Bubble).
- A RenderScreenshot API key (
rs_live_...). Create a free account; no credit card is needed. - A data type with an image field, for example
Listingwithscreenshot(image).
Step 1: add the API
In Plugins → API Connector, click Add another API:
| Setting | Value |
|---|---|
| API Name | RenderScreenshot |
| Authentication | None or self-handled |
| Shared header | Authorization = Bearer rs_live_..., with Private ticked |
Private keeps the key on Bubble's server. Never put the key in a URL parameter in Bubble: client-side calls and logs can show URLs.
Step 2: add the call
Click Add another call and use these settings.
| Setting | Value |
|---|---|
| Name | Capture page |
| Use as | Action |
| Data type | Image |
| Method | GET |
| URL | https://api.renderscreenshot.com/v1/screenshot |
Then add the parameters. Untick Private on the ones that a workflow must set, so they appear as inputs on the action:
| Key | Value for initialization | Private | Notes |
|---|---|---|---|
url |
https://example.com |
No | The page to capture. Map it from the workflow. |
preset |
desktop_hd |
No | og_card for social cards, mobile for phone layout. See presets. |
format |
jpeg |
Yes | Smaller files in Bubble storage. Use png for text-heavy pages. |
block_cookies |
true |
Yes | Removes cookie banners before capture. |
block_ads |
true |
Yes | Removes ads. |
cache_available |
true |
Yes | Returns an identical earlier render for 0 credits. |
Click Initialize call. Bubble sends one real request, so initialization uses one credit. Initialize once; you do not need to initialize again when you change a parameter's value, only when you change the call's shape.
Why the data type is Image
With Data type: Image, Bubble treats the response body as a file and keeps a copy in your app's file storage. The result of the action is a normal Bubble image that you can save to a field. The alternative is a JSON response with a CDN link (send the header Accept: application/json). That link needs no key, but it expires when the cache entry expires: after 24 hours by default and after 30 days at most. A field that holds the CDN link breaks after that. The caching docs explain the TTL.
Step 3: bind the image in a workflow
- Create a workflow, for example When Button Capture is clicked.
- Add the action Plugins → RenderScreenshot – Capture page. Set
urltoInput URL's value. - Add Data → Make changes to a thing. Choose the Listing, and set
screenshot = Result of step 1. - Put an Image element on the page with the source
Current cell's Listing's screenshot.
For long lists or slow pages, run the capture in a backend workflow and schedule it, so the user does not wait on the page and a closed tab does not stop the capture.
Parameter mapping
| Bubble input | API query parameter | API field |
|---|---|---|
url |
url |
url |
preset |
preset |
preset |
width, height (optional, add as keys) |
width, height |
viewport.width, viewport.height |
full_page (optional) |
full_page=true |
capture.mode = full_page |
delay (optional) |
delay (ms, max 10000) |
wait.delay |
dark_mode (optional) |
dark_mode=true |
browser.dark_mode |
The GET endpoint takes these flat parameters. Options with nested structure, such as cookies or custom scripts, need the POST endpoint. In Bubble that is a second call with Method: POST and a JSON body; see POST /v1/screenshot.
Errors and retries in Bubble
When the API returns an error, the action fails and Bubble stops the workflow. Add an An unhandled error occurs event to show the user a message, and use a JSON test call to read the error body while you debug.
| Status and code | Cause | Fix in Bubble |
|---|---|---|
400 invalid_url |
The user typed acme.com |
Prefix https:// in the expression: https:// + Input's value when it has no scheme |
401 invalid_api_key |
Wrong key, or Bearer missing in the header |
Fix the shared header. Do not retry. |
403 insufficient_credits |
Monthly credits used | Hide the capture button and notify an admin |
422 screenshot_failed |
The page did not load in time | Retry once from a scheduled backend workflow, with delay added |
429 too_many_requests |
Many users clicked at once, or a "Schedule API workflow on a list" ran too fast | Space out the scheduled items by a few seconds |
Failed renders use no credits. A successful render that runs twice uses two, unless cache_available is true. The error handling guide lists every code.
Limits and costs
- Credits. One credit per fresh render; see pricing. Never run the capture on Page is loaded: every visitor would start a render.
- Bubble workload. API calls and file storage count toward your Bubble plan's workload and storage.
- Rate limits. Requests per minute depend on your RenderScreenshot plan; see rate limits.
Troubleshooting
- "There was an issue setting up your call" on initialize. The response was an error, not an image. Test the same URL with
Accept: application/jsonto read the message. - The image field stays empty. The call's data type is JSON, not Image, so the result has no file.
- The page in the image is the mobile layout. Set
presettodesktop_hd, or setwidthto 1280 or more.
For no-code site builders that only need a social card URL in their SEO settings, see the Webflow OG image setup. For automations outside your app, see Zapier screenshots.