# Adobe Creative Cloud

- Tool: Bubble
- Difficulty: Advanced
- Time required: 2–3 hours
- Last updated: July 2026

## TL;DR

Connect Bubble to Adobe Creative Cloud by building a Backend Workflow that exchanges client credentials for an Adobe IMS access token, then use the API Connector to call the CC Libraries API and Photoshop API. Adobe's Photoshop jobs are asynchronous — a recursive Backend Workflow polls job status until the processed image is ready. Paid Bubble plan required for Backend Workflows.

## Adobe Creative Cloud in Bubble: Powerful but Multi-Step

Adobe Creative Cloud integration with Bubble is the most technically demanding in the media and content category — not because of Bubble's limitations, but because Adobe's API surface is intentionally fragmented across several services with different base URLs. The Creative Cloud Content API at cc-libraries.adobe.io handles asset library access. The Photoshop API at image.adobe.io processes images asynchronously. Firefly AI generation lives at a third endpoint. All three share the same authentication token from Adobe's Identity Management System.

This fragmentation is the defining characteristic of the Adobe integration pattern in Bubble. You will configure multiple API Connector entries — one per base URL — and share authentication through App Data rather than through a single API Connector's shared header (since the base URLs differ).

The other defining characteristic is asynchronous job processing. Unlike every other API you might connect to Bubble — where you POST data and immediately receive a result — the Photoshop API always returns a job object with a status URL, never an immediate output. Your Bubble app must check that status URL in a polling loop until the job is done. This is the 'recursive Backend Workflow' pattern: each iteration schedules the next iteration with a 5-second delay until status reaches 'succeeded.'

Before you start: Adobe Photoshop API and Firefly API require separate API entitlements on top of an Adobe Creative Cloud subscription. A CC subscription alone does not grant programmatic API access — apply at developer.adobe.com. The CC Libraries API may have different access requirements. Verify current availability at Adobe's developer portal before building.

Also required: a paid Bubble plan. This integration uses Backend Workflows (token exchange and job polling) and Scheduled API Workflows (token refresh every 23 hours), neither of which are available on Bubble's free plan.

## Before you start

- A paid Bubble plan — this integration uses Backend Workflows and Scheduled API Workflows, which are not available on Bubble's free tier
- An Adobe Developer Console account at console.adobe.io to create a project and obtain client credentials
- An Adobe Creative Cloud subscription with API access entitlements — the Photoshop API and Firefly API require separate entitlements beyond a standard CC subscription; verify current requirements at developer.adobe.com
- The API Connector plugin installed in your Bubble app (Plugins tab → Add plugins → search 'API Connector' by Bubble)
- A Bubble App Data 'Settings' table or equivalent to store the Adobe access token and its expiry timestamp between Bubble workflow runs

## Step-by-step guide

### 1. Create an Adobe Developer Console Project and Get Client Credentials

Open console.adobe.io in your browser and sign in with your Adobe ID. Click 'Create new project' or 'New project' on the Projects overview page.

In the new project, click 'Add API' to add the services your Bubble app will use. You will typically add one or more of: Creative Cloud Libraries API (for asset library access), Photoshop API (for async image processing), and Firefly API (for AI image generation). Select each API you need and click through the configuration screens.

For each API, choose 'Service Account (OAuth Server-to-Server)' as the credential type. This is the service-to-service flow that does not require a user to log in — your Bubble Backend Workflow authenticates as the application, not as an individual user.

After completing the setup, navigate to your project's 'Credentials' section. Under 'OAuth Server-to-Server,' click on your credential to view the details. Note down:
- Client ID
- Client Secret (click 'Retrieve client secret' — you may need to confirm your identity)
- The scopes listed for this credential

Copy both values to a secure location. Your Bubble Backend Workflow will use these to obtain an access token from Adobe IMS.

Important: the Photoshop API and Firefly API may require additional approval steps before your credentials are authorized. Check the credential status in the Adobe Developer Console — if any API shows a 'Needs approval' badge, follow Adobe's entitlement request process before proceeding.

**Expected result:** You have a Client ID and Client Secret from Adobe Developer Console for an OAuth Server-to-Server credential with the APIs you selected added to the project.

### 2. Create the Adobe Token Refresh Backend Workflow

In your Bubble app, go to the Workflows tab and open the Backend Workflows section. If you do not see this section, confirm your Bubble app is on a paid plan and that Backend Workflows are enabled under Settings → API.

Click 'New API workflow' to create a workflow named 'Refresh Adobe Token.' Set it as an API Workflow (not an endpoint — this is triggered programmatically by a Scheduled API Workflow, not by external HTTP calls).

Before building this workflow, you need a place to store the token. In Bubble's Data tab, create a new data type called 'App Settings' (or use an existing one) with these fields:
- adobe_access_token (text)
- adobe_token_expires_at (date)

Ensure there is always exactly one row in this table — create one manually in the Data tab now.

Back in the Backend Workflow, add a step: 'Make an API call.' Choose 'API Connector' and create a temporary API Connector call for the token endpoint. Configure it:
- Method: POST
- URL: https://ims-na1.adobelogin.com/ims/token/v3
- Body type: application/x-www-form-urlencoded
- Body fields: client_id=[your Client ID], client_secret=[your Client Secret], grant_type=client_credentials, scope=openid,AdobeID
- Mark client_id and client_secret as Private
- Use as: Action

Initialize this call to get Bubble to detect the response shape (access_token, token_type, expires_in fields).

Add a second step in the Backend Workflow: 'Make changes to a thing.' Select the App Settings row and set:
- adobe_access_token = result of step 1's access_token
- adobe_token_expires_at = Current date/time + 86400 seconds (24 hours, expressed as 'Current date/time + 24 hours' in Bubble's duration math)

Trigger this workflow once manually to populate the token before setting up the scheduled refresh.

```
{
  "method": "POST",
  "url": "https://ims-na1.adobelogin.com/ims/token/v3",
  "headers": {
    "Content-Type": "application/x-www-form-urlencoded"
  },
  "body": {
    "client_id": "<private>",
    "client_secret": "<private>",
    "grant_type": "client_credentials",
    "scope": "openid,AdobeID"
  }
}
```

**Expected result:** The 'Refresh Adobe Token' Backend Workflow runs successfully and writes an access_token string and an expiry timestamp to your App Settings record. You can verify this in Bubble's Data tab by checking the App Settings row.

### 3. Schedule Automatic Token Refresh Every 23 Hours

Adobe IMS tokens for client credentials are valid for 24 hours. To ensure your Bubble app always has a valid token, set up a Scheduled API Workflow that runs the 'Refresh Adobe Token' Backend Workflow every 23 hours — a 1-hour buffer before expiry.

In Bubble's backend workflow editor, click 'New scheduled API workflow.' Name it 'Adobe Token Scheduler.' In the workflow configuration, add a step: 'Schedule API Workflow.' Set the workflow to run 'Refresh Adobe Token' and set the scheduled time to 'Current date/time + 23 hours.'

At the end of the 'Refresh Adobe Token' workflow itself, add a final step: 'Schedule API Workflow.' Schedule itself ('Refresh Adobe Token') to run again in 23 hours. This creates a self-perpetuating refresh chain.

To start the chain: trigger 'Refresh Adobe Token' once manually from Bubble's backend workflow panel (the Run button). This performs the first token fetch and schedules the next one 23 hours later, which will then schedule the one after that, and so on.

If the Bubble app is restarted or the chain breaks, you can restart it by triggering the workflow manually again. Add this as a note in your Bubble app's development documentation so your team knows how to restart the token refresh if the app goes through a prolonged downtime period.

Also add a Bubble Logs check: in the Logs tab, filter to Backend Workflows and confirm the 'Refresh Adobe Token' workflow appears with a 'Successful' status and a next scheduled time approximately 23 hours from now.

**Expected result:** The Scheduled API Workflow is running and you can see it in Bubble's Logs tab. The next scheduled run appears approximately 23 hours from the last run. Your App Settings record always has an adobe_token_expires_at in the future.

### 4. Configure API Connector Entries for CC Libraries and Photoshop APIs

Adobe's API ecosystem uses multiple base URLs: cc-libraries.adobe.io for Creative Cloud Libraries, image.adobe.io for Photoshop and Firefly. Each needs a separate API Connector entry in Bubble because Bubble's API Connector does not support dynamic base URLs across calls within a single entry.

Go to Plugins tab → API Connector. Click 'Add another API' and create an entry named 'Adobe CC Libraries.'

For the Authorization header: set it to 'Bearer [dynamic token from App Settings].' In Bubble's API Connector, you cannot directly reference a database field in shared headers during setup — instead, set the Authorization header value to a placeholder and set 'Use as: Action' on each call, passing the token as a dynamic parameter at call time. Alternatively, fetch the token in a workflow step before the API call and pass it as a call parameter. The cleanest pattern: on each API call, add a parameter named 'token' (Private), and in the Authorization header reference this parameter: 'Bearer [token]'.

Create a GET call for CC Libraries:
- Name: List Libraries
- Method: GET
- URL: https://cc-libraries.adobe.io/api/v1/libraries
- Header: Authorization: Bearer [token] (Private)
- Header: x-api-key: [your Client ID] (Private)
- Use as: Data
- Initialize: run the call with a real token from your App Settings record and your Client ID

Create a second GET call for Library Elements:
- Name: List Library Elements
- URL: https://cc-libraries.adobe.io/api/v1/libraries/[library_id]/elements
- Parameters: library_id (path parameter), limit=20, offset=0
- Use as: Data

For Photoshop: click 'Add another API' and create a second entry named 'Adobe Photoshop API' with base URL https://image.adobe.io. Create a POST call for rendition jobs:
- Name: Create Rendition
- Method: POST
- URL: https://image.adobe.io/pie/psdService/rendition
- Body type: JSON
- Use as: Action
- Body: see code block below

```
{
  "inputs": [
    {
      "href": "<dynamic:input_psd_url>",
      "storage": "adobe"
    }
  ],
  "outputs": [
    {
      "href": "<dynamic:output_url>",
      "storage": "adobe",
      "type": "image/jpeg",
      "quality": 90,
      "overwrite": true
    }
  ]
}
```

**Expected result:** You have two API Connector entries — 'Adobe CC Libraries' and 'Adobe Photoshop API' — each initialized successfully with calls returning real data from Adobe's APIs. The List Libraries call returns at least one library object with name, id, and type fields.

### 5. Build a Repeating Group for CC Library Assets

With the 'List Libraries' call initialized, you can now populate a Bubble repeating group with Creative Cloud Library assets.

First, build a two-stage UI: a library selector followed by an asset browser. On your Bubble page, add a Dropdown element populated by the 'List Libraries' API call (Use as: Data). The dropdown display field should be the library name field from the response; the value field should be the library id.

When a user selects a library from the dropdown, store the selected library id in a Custom State named selected_library_id.

Add a Repeating Group below the dropdown. Set its data source to 'Get data from an external API' → Adobe CC Libraries - List Library Elements call. Pass the selected_library_id Custom State value as the library_id parameter. Set 'Use as: Data.'

Inside the repeating group cell, display:
- Asset name: Current Cell's List Library Elements data name
- Asset type: Current Cell's data type (values: color, characterstyle, layerstyle, brush, graphic, etc.)
- Thumbnail: Current Cell's data representation.content.source (this is the thumbnail URL for graphic-type assets)
- Created date: formatted from Current Cell's data created_at

Note that not all asset types have thumbnails. Color swatches, character styles, and brushes do not have image thumbnails — use the type field to conditionally show a color swatch element (Bubble shape with dynamic background color from the asset's value field) instead of an image for those types.

Add a 'Download' button or link wired to Current Cell's data representation.content.source for graphic assets. Users can open this URL directly to download the asset file.

**Expected result:** The Bubble page shows a library selector dropdown populated from Adobe CC. Selecting a library loads its assets into the repeating group with names, types, and thumbnails for graphic assets. The page feels like a lightweight version of the CC Libraries panel in Adobe applications.

### 6. Build the Recursive Backend Workflow for Async Photoshop Jobs

The Photoshop API's async pattern requires a polling loop in Bubble. Here is how to build it correctly without infinite loops or excessive WU consumption.

Step 1 — Submit the job: Build a regular Bubble workflow (on button click or form submit) that calls the 'Create Rendition' API Connector action from Step 4. The response includes a _links.self.href field — this is the job status URL. Store this URL in a Bubble database record: create a data type 'Processing Job' with fields: job_status_url (text), status (text, options: pending / succeeded / failed), output_url (text), iteration_count (number), and created_by (user). Create a new Processing Job record and write the job_status_url and set status to 'pending.'

Step 2 — Build the polling Backend Workflow: Create a Backend Workflow named 'Poll Photoshop Job.' Add a parameter: job_id (text, the Bubble database ID of the Processing Job record). In the workflow:

Action 1: Make an API call — GET the job_status_url from the Processing Job record's job_status_url field. This calls the Adobe job status endpoint: https://image.adobe.io/pie/psdService/status/{job_id}. Use as: Action. Define the response to detect the status field and outputs array.

Action 2: Make changes to this Processing Job — set status to the API response status field value.

Action 3 (conditional, only run when status = 'succeeded'): Make changes to this Processing Job — set output_url to the response's outputs:first item href field.

Action 4 (conditional, only run when status = 'running' or 'pending' AND iteration_count < 20): Schedule API Workflow 'Poll Photoshop Job' in 5 seconds, passing the same job_id. Also increment iteration_count by 1 on the record.

The iteration_count < 20 guard prevents infinite loops if Adobe's API returns a stuck job — after 100 seconds (20 × 5s) the polling stops and you can mark the job as 'failed' with a timeout reason.

Step 3 — Trigger the polling workflow: In the original button-click workflow (Step 1), after creating the Processing Job record, add a step: 'Schedule API Workflow → Poll Photoshop Job' in 5 seconds, passing the new record's unique ID.

If you want RapidDev's team to help design a complete Photoshop API automation pipeline in Bubble — including file storage integration, batch processing, and user notification workflows — book a free scoping call at rapidevelopers.com/contact.

```
{
  "photoshop_job_polling_pattern": {
    "step_1_submit": "POST /pie/psdService/rendition → store _links.self.href in Processing Job record",
    "step_2_poll": "GET job_status_url → check status field",
    "step_3_conditions": {
      "if_succeeded": "write outputs[0].href to output_url field, mark status=succeeded",
      "if_running_or_pending": "schedule Poll workflow again in 5 seconds, increment iteration_count",
      "if_iteration_gt_20": "mark status=failed, stop scheduling"
    }
  }
}
```

**Expected result:** Clicking 'Process Image' in Bubble creates a Processing Job record, calls the Photoshop API, and the recursive polling Backend Workflow runs every 5 seconds. Within 30–60 seconds, the record's status updates to 'succeeded' and the output_url field contains the processed image URL. Displaying that URL in a Bubble Image element shows the Photoshop-processed result.

## Best practices

- Use a dedicated App Settings table in Bubble's database to store the Adobe access token and its expiry timestamp. Always check the expiry before sensitive workflows — if the token is within 5 minutes of expiry, trigger a manual refresh before making the API call to avoid a mid-workflow 401 error.
- Keep client_id and client_secret marked as Private in all Bubble API Connector calls. Never hard-code these values in page-level JavaScript or client-side Bubble actions where they could be exposed in browser network requests.
- Set an iteration_count guard on your recursive Photoshop polling Backend Workflow. Without a cap (such as iteration_count < 20), a stuck Adobe job will generate infinite Backend Workflow runs consuming Workload Units until you manually stop it.
- Use separate API Connector entries for each Adobe base URL (cc-libraries.adobe.io and image.adobe.io). Trying to combine them under one entry with dynamic base URL overrides is error-prone and makes debugging harder in Bubble's workflow logs.
- Set up Bubble's Data tab → Privacy rules on all data types that store Adobe asset metadata or Processing Job records. Without rules, any logged-in user can read other users' processing jobs through Bubble's data API.
- Monitor Bubble Workload Units in the Logs tab when running Photoshop polling loops. Each polling iteration, the initial Photoshop POST, and the CC Libraries list calls all consume WU. For apps with high image processing volume, consider increasing polling intervals (10–15 seconds) to reduce WU consumption.
- Verify Adobe API entitlement status in the Developer Console before going to production. The Photoshop API and Firefly API require separate approval processes from a standard CC subscription — a credential that works in development may be restricted once you apply for production entitlement.
- Store processed image output URLs (from Photoshop API job results) in Bubble's database after retrieval. The output href from Adobe Cloud Storage may not be permanently accessible — download the processed file to Bubble's file storage or another permanent store (AWS S3, Cloudflare R2) immediately after the job succeeds.

## Use cases

### Brand Asset Library in Bubble

Surface your Creative Cloud Library assets — logos, brand colors, fonts, approved photography — inside a Bubble internal tool or client portal. Marketing and sales team members can browse and download approved brand assets without needing Adobe CC seats, using the CC Libraries API to list elements from specific libraries and display thumbnails and download URLs.

Prompt example:

```
How do I build a Bubble page that lists all assets from a specific Creative Cloud Library, displays their thumbnails and names, and shows their type (color, image, character style)?
```

### Automated Image Processing Pipeline

Build a Bubble app where users upload a product photo, and your Bubble Backend Workflow sends it to the Photoshop API to apply a background removal rendition or resize transformation. The recursive polling workflow checks job status every 5 seconds and writes the processed image URL to the Bubble database when the job completes, triggering a notification to the user.

Prompt example:

```
Can you show me how to build a Bubble workflow that sends an image URL to the Adobe Photoshop API for background removal, polls the job status until it succeeds, and saves the output image URL to a Bubble database record?
```

### Design Review and Asset Approval Portal

Create a Bubble portal where stakeholders can browse CC Library assets by type, mark items as approved or flagged for revision, and store approval status in Bubble's database. The portal reads library contents via the CC Content API and writes approval metadata to Bubble, allowing non-technical stakeholders to participate in design review workflows without a Figma or Adobe seat.

Prompt example:

```
How do I create a Bubble repeating group that shows all images in a Creative Cloud Library with their names, types, and dates, and lets me click an 'Approve' button that saves the approval to my Bubble database?
```

## Troubleshooting

### Adobe IMS token endpoint returns 400 Bad Request during the token refresh Backend Workflow

Cause: The request body format is incorrect. Adobe IMS requires application/x-www-form-urlencoded encoding, not JSON. Also verify that the scope parameter is included and that client_id and client_secret match the OAuth Server-to-Server credential — not a different credential type in your Adobe Developer Console project.

Solution: In the Bubble API Connector call for the token endpoint, confirm Body type is set to 'Form-url-encoded' (not JSON or None). Verify that all four body parameters are present: client_id, client_secret, grant_type=client_credentials, scope=openid,AdobeID. Re-initialize the call after fixing body type.

### CC Libraries API returns 403 Forbidden even with a valid token

Cause: Either the Creative Cloud Libraries API was not added to your Adobe Developer Console project, or the OAuth credential does not have the correct scopes for CC Libraries access, or your Adobe account does not have the required entitlement for this API.

Solution: Go to console.adobe.io, open your project, and verify that Creative Cloud Libraries API appears under 'Added APIs.' If it is missing, click 'Add API' and add it. Under your OAuth Server-to-Server credential, review the listed scopes and confirm that CC Libraries-specific scopes are included. Re-download client credentials after any changes.

### 'There was an issue setting up your call' when initializing the CC Libraries or Photoshop API Connector calls

Cause: Bubble's Initialize call requires a real successful response. This error most commonly occurs when the Adobe token stored in App Data is expired or not yet populated, or when the x-api-key header (Client ID) is missing from the call configuration.

Solution: Trigger the 'Refresh Adobe Token' Backend Workflow manually first to populate a fresh token in App Data. Then retry the Initialize call with the current valid token. Confirm the x-api-key header is present with your Client ID — Adobe's APIs require both the Bearer token and the Client ID as separate headers.

### Photoshop API POST returns a job URL but polling never finds status 'succeeded' — status stays 'running' indefinitely

Cause: Either the input PSD file URL is inaccessible to Adobe's servers (it must be a public URL or an Adobe Cloud Storage URL), or the Photoshop API job encountered an internal error that Adobe did not surface as 'failed' — some job errors result in a prolonged 'running' state rather than an explicit failure status.

Solution: Check the full job status URL response in Bubble's Logs tab — look for an errors array in the status payload beyond the top-level status field. Verify that the input href in your rendition request body points to a publicly accessible URL (not a Bubble file storage URL that requires auth). If using Adobe Cloud Storage, ensure the file path is correct and the token has storage access.

### Backend Workflows section is not visible in Bubble's Workflows tab

Cause: Backend Workflows are not available on Bubble's free plan. The section only appears after upgrading to a paid Bubble plan and enabling the Workflow API under Settings → API.

Solution: Upgrade your Bubble app to a paid plan. Then go to Settings → API → check 'Expose the Workflow API' and save. Backend Workflows and Scheduled API Workflows will then appear in the Workflows tab.

## Frequently asked questions

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

No. This integration requires Backend Workflows (for token exchange and async job polling) and Scheduled API Workflows (for the 23-hour token refresh), which are only available on Bubble's paid plans. You cannot build the Adobe IMS token management or Photoshop polling pattern on Bubble's free tier. Upgrade to at least Bubble's Starter plan before starting this integration.

### Do I need a paid Adobe Creative Cloud plan to use the CC Libraries API?

You need an Adobe Creative Cloud subscription to access CC Libraries (the libraries are tied to CC accounts). The Photoshop API and Firefly API require separate API entitlements beyond a standard CC subscription — they are not automatically available just because you have a Creative Cloud subscription. Apply for API access at developer.adobe.com and verify current entitlement requirements before building.

### How long does an Adobe IMS token last, and how does Bubble refresh it?

Adobe IMS tokens for service-to-service client credentials are valid for 24 hours — a much longer window than many APIs. In Bubble, a Scheduled API Workflow triggers the 'Refresh Adobe Token' Backend Workflow every 23 hours (providing a 1-hour safety buffer). The refresh workflow POSTs new credentials to the IMS token endpoint and updates the access token in your App Settings database record. All API calls read the current token from that record.

### Why does the Photoshop API never return an image directly?

Adobe designed the Photoshop API for server-side image processing tasks that can take anywhere from a few seconds to several minutes depending on file complexity and server load. To avoid HTTP timeout issues, all Photoshop API endpoints return a job object immediately with a status URL, then process the image asynchronously. Your Bubble app must poll that status URL until the job status is 'succeeded,' then read the output URL from the response. This is different from every other API in this category but is the only supported pattern for Photoshop API.

### Can I use this integration to let Bubble app users access their own Adobe CC Libraries?

The pattern described here uses service-to-service client credentials, which authenticate as your application (your Adobe account's libraries). To access individual users' CC Libraries, you would need to implement user-delegated OAuth 2.0 — a multi-step flow similar to the Canva OAuth pattern, where each user authorizes your app and receives a separate user-specific access token. This is significantly more complex and requires separate OAuth credential setup in Adobe Developer Console.

### How many Workload Units does this integration consume in Bubble?

Each step in a Bubble Backend Workflow consumes WU. A single Photoshop job might trigger 3–6 polling Backend Workflow runs (at roughly 10–30 seconds per job), plus the initial job submission call and the CC Libraries list call for display. The 23-hour token refresh adds one Backend Workflow run per day. For apps processing dozens of images per day, monitor WU consumption in Bubble's Logs tab and consider increasing polling intervals to reduce WU costs.

---

Source: https://www.rapidevelopers.com/bubble-integrations/adobe-creative-cloud
© RapidDev — https://www.rapidevelopers.com/bubble-integrations/adobe-creative-cloud
