# How to Integrate Retool with Shutterstock API

- Tool: Retool
- Difficulty: Intermediate
- Time required: 20 minutes
- Last updated: April 2026

## TL;DR

Connect Retool to the Shutterstock API by adding a REST API Resource with OAuth 2.0 Client Credentials authentication using your Shutterstock app credentials. Once configured, build queries to search images, manage licenses, download assets, and track collection usage. Setup takes about 20 minutes and gives your creative and marketing teams a custom asset procurement dashboard.

## Why Connect Retool to Shutterstock?

Marketing teams, creative agencies, and content operations teams that license Shutterstock images at high volume often need tools beyond Shutterstock's native website — custom search workflows that enforce brand guidelines, approval queues for image selection before licensing, budget tracking dashboards, and collection management panels. Connecting Shutterstock's API to Retool lets you build exactly these internal tools, tailored to your team's specific procurement process, without custom development.

The Shutterstock API covers the full asset lifecycle: searching and previewing images, licensing individual assets or bulk-licensing through subscription plans, downloading licensed assets, managing collections and lightboxes, and accessing detailed license history for compliance audits. For enterprise accounts on volume licensing plans, the API also exposes editorial images, vectors, video clips, and music tracks. This breadth makes it possible to build a unified asset management tool in Retool that serves as a single interface for all Shutterstock procurement across your organization.

A particularly valuable pattern is building an internal approval workflow: search results are shown to creative leads who can add images to a review collection, managers approve or reject selections in the Retool interface, and approved images are automatically licensed and downloaded to your cloud storage. This structured process replaces ad-hoc browsing on Shutterstock.com, creates an audit trail of asset decisions, and ensures licensing compliance — especially important for large teams where individual contributors may otherwise license images without oversight.

## Before you start

- A Shutterstock account with API access (requires a Shutterstock subscription plan or API credits — free developer accounts have limited access)
- A registered Shutterstock developer application with Client ID and Client Secret from developers.shutterstock.com
- A Retool account (Cloud or self-hosted) with permission to add Resources
- Understanding of OAuth 2.0 Client Credentials flow — Shutterstock uses this for non-user-interactive server-to-server API access
- For licensing operations: an active Shutterstock subscription or on-demand credits on your account

## Step-by-step guide

### 1. Register a Shutterstock developer app and get credentials

To access the Shutterstock API programmatically, you must create a registered developer application. Navigate to developers.shutterstock.com and log in with your Shutterstock account credentials. Click on 'My Apps' in the top navigation, then click 'Create New App'.

In the app creation form, fill in:
- Application Name: something descriptive like 'Retool Internal Tool' or your company name
- Description: briefly describe what you're building
- Website: your company's website URL
- Redirect URI: for OAuth 2.0 Client Credentials (server-to-server flow), you can enter a placeholder like https://localhost since no actual redirect happens in this flow

After creating the app, Shutterstock displays your Client ID and Client Secret. Copy both values immediately and store them securely — the Client Secret will not be shown again without resetting it.

In your Retool account, navigate to Settings → Configuration Variables and create two secret variables:
- SHUTTERSTOCK_CLIENT_ID: paste your Client ID
- SHUTTERSTOCK_CLIENT_SECRET: paste your Client Secret

Note that Shutterstock API access levels depend on your subscription: Standard subscriptions provide access to search and download of licensed content only, while Enterprise agreements unlock bulk licensing endpoints, editorial content, and higher rate limits. Check your account's API tier in the developer portal to understand which endpoints are available to you.

**Expected result:** You have a Shutterstock developer app with Client ID and Client Secret, both stored as secret configuration variables in Retool, ready for resource configuration.

### 2. Add a Shutterstock REST API Resource with authentication

Open Retool and navigate to the Resources tab. Click Add Resource and select REST API.

In the configuration form:
- Name: 'Shutterstock API'
- Base URL: https://api.shutterstock.com — this is Shutterstock's versioned API root
- Authentication: Select Basic Auth from the Authentication dropdown. Set Username to {{ environment.variables.SHUTTERSTOCK_CLIENT_ID }} and Password to {{ environment.variables.SHUTTERSTOCK_CLIENT_SECRET }}. Shutterstock accepts Basic Auth (Base64-encoded Client ID:Secret) for most read operations including image search, which is the simplest authentication method.

For operations requiring user-specific access (license management, collection management, download access) that need OAuth 2.0, you have two options:
1. Configure Custom Auth in the resource to perform the token exchange and set the Bearer token dynamically
2. Create a separate query that obtains an access token (POST /v2/oauth/access_token with grant_type: client_credentials) and store the token in a Retool variable, then reference it in subsequent query headers

For most teams, starting with Basic Auth for search and adding OAuth dynamically for licensing is the pragmatic approach. Click Save Changes to finalize the resource.

Test the resource by creating a query with Method GET and URL /v2/images/search?query=technology&per_page=5. A successful response returns an array of image objects with IDs, descriptions, and preview URLs.

```
// Query to obtain Shutterstock OAuth access token
// Use this as a setup query that stores the token in a Retool variable
// Method: POST, URL: /v2/oauth/access_token
// Body (x-www-form-urlencoded):
{
  "grant_type": "client_credentials",
  "client_id": "{{ environment.variables.SHUTTERSTOCK_CLIENT_ID }}",
  "client_secret": "{{ environment.variables.SHUTTERSTOCK_CLIENT_SECRET }}"
}
// Store the result: token.data.access_token in a Retool variable named 'sstk_token'
// Reference in subsequent query headers: Authorization: Bearer {{ sstk_token.value }}
```

**Expected result:** A Shutterstock API Resource appears in your Resources list. A test image search query returns Shutterstock image data with IDs, descriptions, preview URLs, and contributor information.

### 3. Build a Shutterstock image search interface

Create the core search experience in your Retool app. The Shutterstock image search endpoint (GET /v2/images/search) accepts a rich set of query parameters that enable filtering by many criteria.

Add the following components to your Retool canvas:
- A Text Input labeled 'Search Keywords' (component name: searchQuery)
- A Select labeled 'Orientation' with options: any, horizontal, vertical, square (component name: orientationSelect)
- A Select labeled 'Image Type' with options: photo, illustration, vector (component name: imageTypeSelect)
- A Select labeled 'Safe Search' with options: safe, moderate, off — for most enterprise environments, keep this as 'safe' (component name: safeSearch)
- A Number Input labeled 'Results per page' defaulting to 20 (component name: perPage)
- A 'Search' button

Create a query with Method GET and URL /v2/images/search. In the Params section, add:
- query: {{ searchQuery.value }}
- orientation: {{ orientationSelect.value !== 'any' ? orientationSelect.value : '' }}
- image_type: {{ imageTypeSelect.value }}
- safe: {{ safeSearch.value || 'safe' }}
- per_page: {{ perPage.value || 20 }}
- page: {{ currentPage.value || 1 }}

Create a JavaScript transformer to extract the most useful fields from the response and create a gallery-friendly data structure:

Bind the transformer output to a Table component. To show image thumbnails in Retool, use the Custom Column feature on the asset_id column and set a cell renderer that embeds the preview URL. Alternatively, show the preview_url column as a clickable link that opens the image in a new tab for preview.

```
// JavaScript transformer for Shutterstock image search response
const response = data;
const images = response.data || [];

return images.map(img => ({
  asset_id: img.id,
  description: img.description || 'No description',
  contributor: img.contributor ? img.contributor.id : 'Unknown',
  image_type: img.image_type,
  media_type: img.media_type,
  preview_url: img.assets && img.assets.preview
    ? img.assets.preview.url
    : '',
  thumb_url: img.assets && img.assets.small_thumb
    ? img.assets.small_thumb.url
    : '',
  aspect_ratio: img.aspect || 'N/A',
  categories: img.categories
    ? img.categories.map(c => c.name).join(', ')
    : 'Uncategorized',
  has_model_release: img.has_model_release ? 'Yes' : 'No',
  has_property_release: img.has_property_release ? 'Yes' : 'No'
}));
```

**Expected result:** Entering keywords and clicking Search populates the results Table with Shutterstock image data. Columns show description, contributor, image type, categories, model release status, and a clickable preview URL link.

### 4. License and download Shutterstock assets

Licensing an image through the Shutterstock API requires an OAuth 2.0 user token (not just Client Credentials) that is authorized to the specific Shutterstock account with an active subscription or credits. The license endpoint (POST /v2/images/licenses) accepts an array of image IDs with the license type and subscription ID.

First, fetch the available subscriptions for your account to identify which subscription ID to use. Create a query with Method GET and URL /v2/user/subscriptions. This returns your active subscriptions with their IDs, remaining allotments, and coverage types (standard, enhanced, editorial).

Create a Select component populated with subscriptions from this query. When an operator selects an image from the search results and chooses a subscription, the license query can proceed.

Create the license query:
- Method: POST
- URL: /v2/images/licenses
- Body (JSON): pass the selected image ID and subscription ID

The license endpoint returns a download URL for the licensed asset. In the On Success event handler, trigger a follow-up query that opens this URL or stores it in your database. For enterprise workflows, also trigger a query that saves the license record — asset ID, license date, licensed by, subscription used — to your PostgreSQL database for audit purposes.

For licensing to work, the Authorization header must use an OAuth Bearer token (not Basic Auth). If you set up the access token query in the previous step, reference the stored token here: set a custom Header on this query with Name 'Authorization' and Value 'Bearer {{ sstk_token.value }}'.

```
// POST body for /v2/images/licenses
// Licenses a Shutterstock image from the selected search result
{
  "images": [
    {
      "image_id": "{{ searchResultsTable.selectedRow.asset_id }}",
      "subscription_id": "{{ subscriptionSelect.value }}",
      "format": "jpg",
      "size": "huge"
    }
  ]
}
```

**Expected result:** Selecting an image from the search results, choosing a subscription, and clicking 'License Asset' returns a download URL for the licensed image. The license is recorded in Shutterstock's history and optionally in your database.

### 5. Build a license history and usage tracking dashboard

Compliance and finance teams often need visibility into what Shutterstock assets have been licensed, when, by whom, and under what license type. The Shutterstock API provides a license history endpoint that returns all licensing activity for your account.

Create a query with Method GET and URL /v2/images/licenses. Add query parameters:
- start_date: {{ dateRange.startDate }} — ISO 8601 date string
- end_date: {{ dateRange.endDate }}
- per_page: 100
- page: {{ historyPage.value || 1 }}

The response includes an array of license objects with: image ID, license type, license date, download URL (if still active), user information, and subscription details.

Create a JavaScript transformer to format the license history data for the Table. Add a subscription_type column that shows whether each license was standard or enhanced, and flag licenses where the download URL has expired (null or unavailable).

Bind the transformer output to a Table component. Add a stat showing total licenses in the selected period and the total estimated spend (you'll need to look up per-license pricing from your Shutterstock contract to calculate this). Add a 'Download License Report' button that uses Retool's built-in CSV export feature on the Table component to export the filtered license history.

For ongoing compliance, set up a Retool Workflow that runs weekly, fetches the latest license history, and writes new records to your PostgreSQL database. The Retool dashboard then queries your database rather than calling the Shutterstock API on every page load — this is faster and doesn't count against your API rate limits.

```
// JavaScript transformer for Shutterstock license history
const response = data;
const licenses = response.data || [];

return licenses.map(license => ({
  image_id: license.image ? license.image.id : 'N/A',
  license_date: license.license_date
    ? new Date(license.license_date).toLocaleDateString()
    : 'Unknown',
  license_type: license.license || 'Standard',
  subscription_id: license.subscription_id || 'On Demand',
  user: license.user ? license.user.username : 'API User',
  download_available: license.download ? 'Yes' : 'Expired',
  image_format: license.image ? license.image.format : 'N/A'
}));
```

**Expected result:** The license history dashboard shows all Shutterstock assets licensed in the selected date range with license type, date, user, and subscription information. A CSV export button provides a downloadable compliance report.

## Best practices

- Store Shutterstock Client ID and Client Secret in Retool configuration variables marked as secret — never embed them in query bodies or expose them to the browser.
- Use Basic Auth for read-only search operations and OAuth Bearer tokens for licensing and user-specific operations — this separates concerns and simplifies authentication management.
- Always filter search results by has_model_release: true for images intended for commercial advertising use — model-released images have broader usage rights and reduce legal risk.
- Cache access tokens in a Retool database or configuration variable and refresh them on a schedule (weekly) using a Retool Workflow, rather than obtaining a new token on every page load.
- Build approval workflows before licensing — show search results for review, allow creative leads to select images, require management approval before triggering license API calls to prevent unnecessary license usage.
- Log all license operations to your own PostgreSQL database with asset ID, license date, licensed by, and subscription used — Shutterstock's native history view is limited and having your own audit trail simplifies compliance reporting.
- Set the search result page size to a reasonable number (20-50) and implement pagination rather than fetching maximum results — this reduces API calls and improves dashboard load time.

## Use cases

### Build a brand-filtered image search and procurement panel

Create a Retool dashboard where marketing team members search Shutterstock images using filters specific to your brand guidelines — approved color palettes, required orientations (landscape for web banners, portrait for social), and excluded categories. Display search results in a gallery view using an IFrame or custom component showing preview thumbnails. When an image is selected, show its licensing options and allow one-click licensing with automatic download to your S3 bucket.

Prompt example:

```
Build a Retool image procurement panel. Add a Text Input for search keywords, a Select for orientation (horizontal, vertical, square), a Select for image type (photo, illustration, vector), and a Number Input for max results. On 'Search' button click, call the Shutterstock /v2/images/search endpoint and display results in a Table with columns: thumbnail (IFrame component), description, contributor name, asset_id, and available licenses. A 'License & Download' button on the selected row calls the license endpoint and shows the download URL.
```

### Create a license history and compliance audit dashboard

Build a Retool compliance panel that queries the Shutterstock license history endpoint to retrieve all assets licensed by your organization, showing asset ID, image preview, license type, license date, licensed user, and subscription used. Allow filtering by date range, license type, and user. Export the filtered results as a CSV for compliance audits. Flag any images with licenses that are nearing expiration for renewal.

Prompt example:

```
Create a Retool license audit dashboard that queries Shutterstock's /v2/user/subscriptions and /v2/images/licenses endpoints. Display all licensed images in a Table with: asset ID, thumbnail URL, license type (standard, enhanced, editorial), license date, licensed by (username), and days since license. Add date range filters and a user filter. Include an Export CSV button. Show a summary stat for total licenses issued in the selected period.
```

### Build a collection management tool for creative teams

Create a Retool tool that lets creative leads manage Shutterstock collections (lightboxes) directly from an internal interface. List all team collections, show assets within each collection, allow adding assets to collections from search results, and remove assets that have been rejected. Include a workflow where a collection can be 'approved for licensing' which triggers automatic licensing of all assets in the collection.

Prompt example:

```
Build a Retool collection manager. Show all Shutterstock collections from the /v2/images/collections endpoint in a left-panel list. When a collection is selected, show its assets in a gallery Table on the right. Add an 'Add Asset' button that takes an asset ID from a Text Input and adds it to the selected collection via the collection items endpoint. Add a 'Remove' button per row. Include a 'License All' button that loops through all assets in the collection and licenses each one.
```

## Troubleshooting

### Image search returns 401 Unauthorized even with correct Client ID and Secret in Basic Auth

Cause: The Shutterstock API requires the Client ID and Secret to be combined in the format ClientID:ClientSecret and Base64-encoded for Basic Auth. Retool's Basic Auth configuration does this automatically, but if the credentials contain special characters or are incorrectly formatted, encoding can fail.

Solution: Verify that the SHUTTERSTOCK_CLIENT_ID and SHUTTERSTOCK_CLIENT_SECRET configuration variables contain only the credential values with no extra whitespace or quotes. Test by creating a query that logs {{ btoa(environment.variables.SHUTTERSTOCK_CLIENT_ID + ':' + environment.variables.SHUTTERSTOCK_CLIENT_SECRET) }} to verify the Base64 encoding. Alternatively, switch to obtaining an OAuth access token (POST /v2/oauth/access_token) and use that as a Bearer token instead of Basic Auth.

### License endpoint returns 403 Forbidden with 'Insufficient permissions' or 'No subscription found'

Cause: The OAuth access token used for the license request doesn't have the required scopes, the Shutterstock account has no active subscription with remaining downloads, or the token was obtained via Client Credentials (server-to-server) rather than a user-authorized OAuth flow that has access to the licensing subscription.

Solution: Check your Shutterstock subscription status in your account dashboard to confirm you have remaining licenses or credits. Verify that the subscription ID used in the license request matches an active subscription returned by the /v2/user/subscriptions endpoint. For some licensing operations, Shutterstock requires user-level OAuth authorization rather than Client Credentials — check Shutterstock's API documentation for the specific endpoint's scope requirements.

### Search results are empty even with a valid search query

Cause: The query parameter may be URL-encoded incorrectly, or the safe parameter is filtering out most results, or the specific combination of filters (orientation + image_type + safe) returns no matches.

Solution: Test with a minimal query that only includes the query parameter and no other filters. Confirm the search term is a common English word. If that works, add filters one at a time to identify which combination is producing empty results. For editorial images, ensure your account has editorial access — editorial content is separate from commercial stock and requires a specific license type.

### Rate limit errors (429 Too Many Requests) on image search queries

Cause: Shutterstock's API enforces rate limits that vary by plan. Developer accounts and Basic plans have lower limits than Enterprise API agreements. Auto-running search queries or queries triggered on every keystroke can quickly exhaust rate limits.

Solution: Set the search query to Manual trigger mode and add a 'Search' button rather than running on every input change. Add debouncing to search inputs by using a Text Input with a 'blur' event handler rather than 'change'. For Retool Workflows that process batch image data, add Wait blocks between sequential API calls.

## Frequently asked questions

### Does Shutterstock have a native Retool connector?

No. Shutterstock connects to Retool via a generic REST API Resource. You configure the resource with Shutterstock's base URL (https://api.shutterstock.com) and either Basic Auth credentials (Client ID and Secret) or an OAuth Bearer token. All Shutterstock API endpoints — image search, licensing, collections, and downloads — are then accessible from Retool's visual query builder.

### Can I download licensed Shutterstock images directly to my S3 bucket from Retool?

Yes, though it requires a multi-step Retool Workflow. First license the image to obtain a download URL from Shutterstock. Then use a JavaScript Code block to fetch the image content from that URL and pass it to an Amazon S3 PUT request in a subsequent Resource Query block. This automated download pipeline keeps your licensed assets in your own storage, independent of Shutterstock's hosted URLs which may expire.

### What is the difference between Shutterstock's Standard and Enhanced licenses?

Standard licenses cover most digital uses: websites, social media, presentations, and digital ads with up to 500,000 views. Enhanced licenses cover print runs over 500,000, merchandise for resale, broadcast TV and film, and advertising campaigns without view limits. In your Retool license interface, display the license type clearly and guide users to select Enhanced licenses for high-reach or print-focused use cases. The license type is specified in the license request's license parameter.

### How do I handle Shutterstock editorial images in Retool?

Editorial images (news photography, celebrity, and event imagery) have a different license type and cannot be used for commercial purposes — they are for editorial use only (news articles, blog posts, educational content). Shutterstock's search API returns an is_editorial field on image objects. In your Retool search interface, display this clearly as a column in the results Table and add a warning when operators attempt to license editorial images for commercial contexts.

---

Source: https://www.rapidevelopers.com/retool-integrations/shutterstock-api
© RapidDev — https://www.rapidevelopers.com/retool-integrations/shutterstock-api
