Bubble Screenshot API — Capture Websites from Your No-Code App

Add website screenshots to your Bubble app using the API Connector. Full-page captures, PDFs, element screenshots. Server-side rendering that works where plugins fail.

Vitalii Holben Updated

Bubble's API Connector lets you call the ScreenshotRun API with a single GET request. Pass a URL, get back a hosted image. The screenshot shows up in an attachment field, an image element, or wherever your workflow needs it. No Bubble plugin to install. No client-side html2canvas. Just a screenshot API that works.

If you've tried screenshot plugins in Bubble before, you already know the pain. They capture the DOM from inside the browser using JavaScript libraries like html2canvas, and the results are rough: missing images, broken SVGs, fonts falling back to system defaults, 10-pixel offsets nobody can explain. The Bubble forum thread titled "Is there a screenshot plugin that REALLY works?" has been open for years, and there's still no consensus answer. A server-side API call sidesteps all of it. The API loads pages in real Chromium, waits for JavaScript to finish, then captures what a human visitor would actually see.

This guide covers the full setup: API Connector configuration, storing screenshots in your database, automating captures with backend workflows, plus a few use cases that come up constantly in Bubble apps.

Set up the API Connector in five minutes

You need two things before starting: a ScreenshotRun API key from the dashboard (free plan, 200 captures per month) and the API Connector plugin installed in your Bubble app. The API Connector comes pre-installed on most plans, but if you don't see it, go to Plugins, search "API Connector," and add it.

Open the API Connector plugin settings and click "Add another API." Name it something like "ScreenshotRun" (the name doesn't matter technically, but you'll reference it in workflows later).

Set up auth first. Set "Authentication" to "Private key in header" and enter your API key. Bubble will send it as a Bearer token in the Authorization header on every request. Your key never touches the client side.

Now add your first API call. Click "Add another call" and set it up like this:

  • Name: capture_screenshot
  • Method: GET
  • URL: https://api.screenshotrun.com/v1/screenshots/capture?url=[url]&format=png&width=1280&block_cookies=true
  • Data type: JSON

The square brackets around [url] tell Bubble this is a dynamic parameter. When you use this call in a workflow, Bubble will ask you to fill in the URL from your app's data. You can add more dynamic parameters the same way: &full_page=[full_page], &device=[device], &dark_mode=[dark_mode].

Click "Initialize call" with a test URL (try https://example.com). Bubble sends the request, gets back JSON, then maps the response fields automatically. You should see screenshot_url in the response. That's the hosted image URL you'll save to your database or display directly.

Why this works better than Bubble screenshot plugins

Most Bubble screenshot plugins run in the user's browser. They traverse the DOM, try to reconstruct what's on screen, and spit out a PNG. The library doing the heavy lifting is almost always html2canvas (or its fork, dom-to-image). These tools are clever but fundamentally limited.

Cross-origin images won't render because the browser's security model blocks canvas access to external resources. Web fonts loaded from Google Fonts or Adobe get replaced with Arial or Times New Roman. CSS properties like backdrop-filter, mix-blend-mode, and complex box-shadows are partially supported at best. And if your page has a repeating group with 50 items, the plugin might capture the container background but skip the contents entirely (there's a forum thread about exactly this bug).

The screenshot API approach sends your URL to ScreenshotRun's servers. We open a real Chromium instance, load the page, wait for network requests to settle, render fonts and images like a normal browser, then capture the viewport. Cross-origin images work. SVGs render. Shadows look correct. The output matches what you'd see if you opened the page yourself and hit Cmd+Shift+4.

There's a practical advantage too: server-side API calls don't depend on the user's browser or device. A visitor on a 2019 Android phone gets the same screenshot quality as someone on a MacBook Pro. The capture happens on our infrastructure, not theirs.

Save screenshots to your Bubble database

Once the API call returns a screenshot_url, you need to store it. Bubble handles this in a workflow action.

Say you have a "Websites" data type with fields for URL (text) and Screenshot (image). In your workflow (triggered by a button click, a new record, or whatever fits your app):

  1. Add action: "Plugins > ScreenshotRun - capture_screenshot"
  2. Set the url parameter to the current thing's URL field
  3. Add a second action: "Make changes to a thing"
  4. Set the Screenshot field to "Result of step 1's screenshot_url"

Bubble downloads the image from that URL and stores its own permanent copy. Even after ScreenshotRun's temporary URL expires, your database keeps the image. You can display it with an Image element bound to the current cell's Screenshot field.

For Gallery views or Repeating Groups, this is where it clicks. Each record gets a visual thumbnail of the website it references. Directory apps, CRM tools, portfolio sites, competitor trackers (these all benefit from inline screenshots instead of bare URLs that nobody clicks).

Automate captures with backend workflows

Button-triggered screenshots cover the interactive case, but the real power is automation. Bubble's backend workflows let you run API calls on a schedule or in response to database changes, without any user sitting in front of the app.

Go to the Backend Workflows section (you need a paid Bubble plan for this). Create a new API workflow called "capture_and_save." Add a parameter: record_id (text). Inside the workflow:

  1. Search for the Website record matching the ID
  2. Call the ScreenshotRun API with that record's URL
  3. Update the record's Screenshot field with the result

Now you can trigger this workflow from anywhere. A "When a thing is created" trigger fires it automatically for new records. A recurring workflow processes a batch of records every hour. An API endpoint lets external services kick off captures. The pattern is the same every time: pass a record ID, the backend workflow handles the rest.

For bulk processing, schedule the workflow with a list. If you've got 200 URLs to capture, loop through them with Bubble's "Schedule API workflow on a list" action, spacing each call a few seconds apart. At that rate you'll process the entire batch in under 15 minutes. The free tier's 200 monthly captures fit this exactly. Need more volume? Paid plans start at $9/month.

Generate dynamic OG images for your Bubble pages

This one comes up on the Bubble forum constantly. You've built a marketplace on Bubble. Maybe a directory site, maybe a SaaS tool. Each listing or page has unique content. But when someone shares a link on Twitter or LinkedIn, the preview card shows a generic OG image (or worse, nothing at all) because Bubble doesn't generate per-page social previews natively.

The fix: create a "card" page in Bubble that renders a styled template with dynamic data (listing title, price, hero image, branding). Then call the ScreenshotRun API with that page's URL, passing the dynamic parameters via query string. The API captures the rendered card and returns an image URL you store as the listing's OG image.

Your Bubble page's SEO settings can reference this image dynamically. When social platforms crawl the link, they pull the OG image tag, which points to a unique visual card for each listing. Click-through rates on social shares jump when the preview actually shows what the page contains instead of a generic logo.

The OG preview tool lets you test how the generated image will look on different platforms before you wire it into production.

Full-page captures and element screenshots

Two parameters worth knowing about if you're doing anything beyond basic viewport captures.

full_page=true scrolls the entire page and stitches everything into one tall image. Useful for archiving long-form content or capturing entire product pages. You can also use it to generate visual diffs when a page changes. The API handles lazy-loaded images automatically (scrolls to trigger Intersection Observer, waits for images to load, then captures).

The selector parameter does the opposite: captures just one element. Pass a CSS selector like .pricing-table or #hero-banner and the API crops the screenshot to that element's bounding box. In a Bubble context, this is handy for capturing a specific section of an external page without the navigation, footer, or cookie banners cluttering up the image. The element screenshot feature page covers the details.

PDF export from any URL

Bubble has no built-in PDF export. The plugins that attempt it (Page to PDF, various Zeroqode tools) are client-side. They struggle with page breaks, dynamic content height, headers that repeat on every page. They also require the page to be open in the user's browser.

Change format=png to format=pdf in your API call and ScreenshotRun returns a PDF document instead. The page doesn't need to be open in anyone's browser. You can generate PDFs from backend workflows. Run them on a schedule, fire them from webhooks, trigger them on button clicks. The PDF parameters (pdf_landscape, pdf_page_format, pdf_margin_top, etc.) give you control over page size and margins that client-side plugins can't match.

Course certificates, invoices, compliance reports, dashboard exports: all the same pattern. Build a template page in Bubble with dynamic data, point the API at it, get a PDF back. The PDF feature page has the full parameter list.

Advanced parameters for Bubble workflows

Every API parameter works through the API Connector. Add them as dynamic or static query params depending on whether you need them to change per request.

device=mobile switches the viewport to phone dimensions (390px wide) with a mobile user-agent. Good for responsive design previews or capturing how your Bubble app looks on smaller screens. Pair it with device=tablet for iPad-sized captures.

dark_mode=true triggers the site's own prefers-color-scheme: dark CSS media query. Sites that support dark mode will render their dark theme. Not all sites do, but the ones that do (GitHub, Notion, most modern SaaS tools) look good captured this way.

stealth=true makes the browser fingerprint look like a regular visitor session. Some sites (behind Cloudflare, Akamai, or custom bot detection) block headless browsers. Stealth mode gets past most of these without extra setup on your end.

delay=3 waits three seconds after page load before capturing. SPAs built with React or Vue sometimes need a moment for client-side rendering to settle. If your screenshots look half-loaded, adding a 2-3 second delay usually fixes it.

block_ads=true and block_chats=true strip display ads and floating support widgets (Intercom, Drift, Crisp) before capture. Cleaner screenshots without writing CSS selectors to hide specific elements. See the ad blocking page for what gets removed.

cache_ttl=3600 caches the screenshot for one hour. If the same URL gets requested again within that window, the API returns the cached version instantly. In a Bubble app where multiple users might trigger captures for the same URL, this saves API calls and speeds up response times.

Troubleshooting common Bubble issues

API Connector throws an error when you try to initialize. Check that your API key is entered in the auth section (not pasted directly into the URL). The key goes in the "Key value" field under "Private key in header." Also verify the key matches what's in your ScreenshotRun dashboard. Copy-paste errors with API keys happen more often than you'd think.

Screenshots are blank or show a spinner. The target page hasn't finished loading before the capture fires. Add &delay=3 to your URL to wait three seconds, or use &wait_for_selector=.main-content to wait for a specific element. JavaScript-heavy pages (React, Vue, Angular apps) almost always need one of these.

The image doesn't display in Bubble. Make sure your Image element's data source is set to the screenshot field (type: image), not to the raw URL text. Bubble stores API-fetched images as files internally. If you're using a Text element to display the URL, switch to an Image element with dynamic source.

Workflow runs but the screenshot field stays empty. Check your workflow's Step 2 (the "Make changes" action). The field should reference "Result of step 1's screenshot_url" specifically. If you reference the wrong field from the API response, Bubble writes null without an error message.

You're hitting the 200/month free tier limit. The cache_ttl parameter helps here. Setting it to 86400 (24 hours) means repeated captures of the same URL within a day count as one API call. For Bubble apps where users screenshot popular URLs, caching can cut your usage by half or more.

What about Zapier or Make.com as middleware?

If your Bubble plan doesn't include backend workflows (or you'd rather avoid the API Connector entirely), route the workflow through Zapier or Make.com. The setup: Bubble triggers a Zapier zap when a new record is created, Zapier calls the ScreenshotRun API, then updates the Bubble record with the screenshot URL. The whole thing takes five minutes, zero code. No API Connector setup at all.

The tradeoff is speed and cost. Zapier adds 1-5 seconds of latency per trigger, and you're paying for both Zapier and ScreenshotRun. For most Bubble apps, the direct API Connector approach is faster, cheaper, with full control over every parameter. But if you're already running Zapier for other integrations, adding screenshots to an existing workflow takes about two minutes.

Written by

Vitalii Holben

Co-founder and CEO of ScreenshotRun. Full-stack developer building screenshot API tools that help developers capture, automate, and monitor web pages at scale. Based in Europe, shipping code since 201...

Screenshot API in a few clicks

Free plan includes 200 screenshots every month. No credit card required.

Sign up → copy your key → make your first call