# How to Integrate Bolt.new with Getty Images API

- Tool: Bolt.new
- Difficulty: Intermediate
- Time required: 25 minutes
- Last updated: April 2026

## TL;DR

Connect Bolt.new to the Getty Images API by applying for developer access at developer.gettyimages.com, using your API key to search and display watermarked preview images via a Next.js API route, and implementing the licensing flow for purchasing rights to high-resolution images. Getty Images is the premium source for editorial and news photography. All API calls must go through a server-side route — the API key is a credential that should never be exposed in the browser.

## Build a Getty Images Search and Licensing App with Bolt.new

Getty Images is the world's largest premium stock photography agency, with an archive of over 500 million assets including editorial news photography, creative stock images, sports and entertainment photography, and archival historical images. The Getty Images API gives developers programmatic access to search this collection, display watermarked previews, and license images for specific uses. For media companies, news apps, editorial tools, and content platforms built in Bolt.new, the Getty API provides access to the most comprehensive library of editorial photography available.

Getting started with the Getty Images API requires creating a developer account at developer.gettyimages.com and submitting an API application. Unlike many APIs that offer instant access, Getty reviews applications to understand your use case — this typically takes 1-3 business days. Once approved, you receive an API key that authenticates your search and preview requests. The API key approach is straightforward: include it in the Api-Key header on all requests. For licensed downloads (purchasing rights to use images without watermarks), Getty uses OAuth 2.0 — a separate credential layer that requires user authentication. The search and preview tier works with just the API key and is what most developers need for building image galleries, search tools, and content discovery features.

Getty's image collection has an important distinction: editorial content versus creative content. Editorial images document real events — news photography, celebrity events, sports, politics. They can only be used in editorial contexts (news reporting, educational content) and not for commercial advertising. Creative images are cleared for commercial use in advertising, products, and marketing. When building search features, you should filter by this asset_type to show users only the content they are licensed to use for their purpose. Displaying editorial images in a commercial context without the correct license is a legal issue that Getty actively enforces.

## Before you start

- A Getty Images developer account at developer.gettyimages.com with an approved API key
- A Bolt.new project using Next.js (required for server-side API routes that keep the API key out of the browser)
- Understanding of Getty Images' editorial vs creative content distinction for proper licensing
- Optional: a Getty Images account with licensing credits for the download/licensing use case
- Basic understanding of image pagination and lazy loading for large result sets

## Step-by-step guide

### 1. Apply for Getty Images API Access

Navigate to developer.gettyimages.com and click 'Get API Access'. You will need to create a Getty developer account (separate from a regular Getty Images account) and fill out an application form describing your project. Getty wants to understand your use case: what type of application you are building, how you will display images, whether you intend to offer licensing to end users, and your estimated monthly API call volume. Provide specific, honest answers — vague responses slow down approval. Common approved use cases include media company tools, news aggregators, editorial content platforms, creative agency asset browsers, and developer demos/portfolios. After submitting, approval typically takes 1-3 business days. Getty sends your API key by email once approved. The API key looks like a long alphanumeric string and is associated with your developer account. There are two tiers: the Developers tier (free, rate-limited, returns watermarked previews only, no licensing capabilities) and the Partners tier (requires a Getty commercial agreement, enables licensed downloads and higher rate limits). For building and testing, the Developers tier is sufficient. Add the API key to your .env file as GETTY_API_KEY. Getty's API base URL is https://api.gettyimages.com/v3 and all endpoints require the Api-Key header (note: 'Api-Key' with a capital K, not 'Authorization: Bearer'). Test your key by calling the /search/images endpoint — a 200 response confirms the key is working.

```
// lib/getty.ts
export async function gettyRequest<T>(
  endpoint: string,
  queryParams: Record<string, string | number | boolean> = {}
): Promise<T> {
  const apiKey = process.env.GETTY_API_KEY;

  const params = new URLSearchParams();
  Object.entries(queryParams).forEach(([key, value]) => {
    if (value !== undefined && value !== null && value !== '') {
      params.append(key, String(value));
    }
  });

  const url = `https://api.gettyimages.com/v3${endpoint}${params.toString() ? '?' + params.toString() : ''}`;

  const response = await fetch(url, {
    headers: {
      'Api-Key': apiKey!,
      'Accept-Language': 'en-US',
      'Content-Type': 'application/json',
    },
  });

  if (!response.ok) {
    const errorText = await response.text();
    throw new Error(`Getty API error ${response.status}: ${errorText}`);
  }

  return response.json() as Promise<T>;
}
```

**Expected result:** The Getty API connection is verified. The gettyRequest helper is ready to use in API routes throughout the app. A test search returns Getty image data.

### 2. Build the Image Search API Route and Gallery Component

With your API key configured, build the core search functionality. The Getty Images search endpoint is GET /v3/search/images and accepts numerous filtering parameters. The key ones for most applications: phrase (search keywords), page and page_size (pagination, max 100 per page), asset_type (editorial vs creative — critical for correct licensing), orientations (horizontal, vertical, square), number_of_people (none, one, small_group, large_group), and sort_order (best_match, most_popular, newest, oldest). The response includes a result_count (total matching images) and an images array. Each image object contains the id, title, caption, date_created, artist (photographer), asset_type, display_sizes (array of preview URLs at different sizes), and keywords array. The display_sizes array contains objects with a name (comp, preview, thumb) and uri (the image URL). 'thumb' is the smallest (170px), 'preview' is medium (340px), and 'comp' is the largest watermarked preview suitable for layout comping. All of these URLs include Getty's watermark overlay. Use the 'thumb' URIs for grid thumbnails and 'comp' or 'preview' for enlarged image views. During development in Bolt's WebContainer, outbound API calls to Getty Images work correctly from Next.js API routes. You can build and test the full search and gallery interface in the Bolt preview.

```
// app/api/images/search/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { gettyRequest } from '@/lib/getty';

interface GettyImage {
  id: string;
  title: string;
  caption: string;
  artist: string;
  asset_type: string;
  date_created: string;
  display_sizes: Array<{ name: string; uri: string }>;
  keywords: Array<{ text: string }>;
}

interface GettySearchResponse {
  result_count: number;
  images: GettyImage[];
}

export async function GET(request: NextRequest) {
  const { searchParams } = new URL(request.url);
  const q = searchParams.get('q') || '';
  const page = parseInt(searchParams.get('page') || '1');
  const pageSize = Math.min(parseInt(searchParams.get('pageSize') || '20'), 100);
  const assetType = searchParams.get('assetType') || 'creative';
  const orientation = searchParams.get('orientation') || '';

  if (!q) {
    return NextResponse.json({ images: [], totalCount: 0 });
  }

  const data = await gettyRequest<GettySearchResponse>('/search/images', {
    phrase: q,
    page,
    page_size: pageSize,
    asset_type: assetType,
    ...(orientation && { orientations: orientation }),
    fields: 'id,title,caption,artist,asset_type,date_created,display_sizes,keywords',
    sort_order: 'best_match',
  });

  const getDisplayUrl = (sizes: Array<{ name: string; uri: string }>, name: string) =>
    sizes.find((s) => s.name === name)?.uri || '';

  const images = (data.images || []).map((img) => ({
    id: img.id,
    title: img.title,
    caption: img.caption,
    artist: img.artist,
    assetType: img.asset_type,
    dateCreated: img.date_created,
    thumbUrl: getDisplayUrl(img.display_sizes, 'thumb'),
    previewUrl: getDisplayUrl(img.display_sizes, 'preview'),
    compUrl: getDisplayUrl(img.display_sizes, 'comp'),
    keywords: img.keywords?.slice(0, 8).map((k) => k.text) || [],
  }));

  return NextResponse.json({ images, totalCount: data.result_count, page, pageSize });
}
```

**Expected result:** The search API route returns formatted image results with watermarked preview URLs. The gallery component displays a grid of Getty Images thumbnails with photographer credits.

### 3. Display Image Details and Implement the Licensing Workflow

When a user clicks a gallery image, show a detail view with the full caption, photographer name, date taken, Getty image ID, and usage rights information. The detail page should clearly show whether the image is editorial (news use only) or creative (commercial use allowed). Include a direct link to the image's licensing page on Getty's website — this is the standard approach for developers on the free API tier. The Getty image detail URL follows the pattern: https://www.gettyimages.com/detail/photo/{image-id}. For developers with a Getty partner agreement and OAuth credentials, the licensing API lets you download licensed images programmatically. This requires OAuth 2.0 authentication where the user logs in with their Getty account, authorizes your app, and you exchange the authorization code for tokens to call the /downloads endpoint. The OAuth flow requires a deployed redirect URI — it cannot work with Bolt's WebContainer preview URL since incoming OAuth callbacks need a stable public HTTPS URL. Build the OAuth flow in Bolt but test it after deployment to Netlify. For the detail page accessible to all visitors, display watermarked comp-size images and link to Getty's own licensing UI. The important thing is to never serve un-watermarked Getty images without proper licensing — Getty actively monitors for unauthorized image use and enforces licensing violations.

```
// app/images/[id]/page.tsx
import { gettyRequest } from '@/lib/getty';
import { notFound } from 'next/navigation';

interface GettyImageDetail {
  id: string;
  title: string;
  caption: string;
  artist: string;
  date_created: string;
  asset_type: string;
  display_sizes: Array<{ name: string; uri: string; is_watermarked: boolean }>;
  keywords: Array<{ text: string; type: string }>;
}

type Props = { params: { id: string } };

export async function generateMetadata({ params }: Props) {
  const image = await gettyRequest<GettyImageDetail>(`/images/${params.id}`)
    .catch(() => null);
  if (!image) return { title: 'Image Not Found' };
  return {
    title: `${image.title} | Getty Images`,
    description: image.caption?.slice(0, 155),
  };
}

export default async function ImageDetailPage({ params }: Props) {
  const image = await gettyRequest<GettyImageDetail>(`/images/${params.id}`, {
    fields: 'id,title,caption,artist,date_created,asset_type,display_sizes,keywords',
  }).catch(() => null);

  if (!image) notFound();

  const compImage = image.display_sizes?.find((s) => s.name === 'comp');
  const gettyLicenseUrl = `https://www.gettyimages.com/detail/photo/${image.id}`;

  return (
    <div className="max-w-4xl mx-auto px-4 py-8">
      <div className="relative aspect-video bg-gray-100 rounded-lg overflow-hidden mb-6">
        {compImage && (
          <img
            src={compImage.uri}
            alt={image.caption || image.title}
            className="w-full h-full object-contain"
          />
        )}
        <span className="absolute top-2 right-2 text-xs bg-black/60 text-white px-2 py-1 rounded">
          {image.asset_type === 'editorial' ? 'Editorial Use Only' : 'Creative'}
        </span>
      </div>
      <h1 className="text-2xl font-bold mb-2">{image.title}</h1>
      <p className="text-gray-600 mb-4">{image.caption}</p>
      <div className="flex gap-4 text-sm text-gray-500 mb-6">
        <span>Photo by: {image.artist}</span>
        <span>Date: {new Date(image.date_created).toLocaleDateString()}</span>
        <span>ID: {image.id}</span>
      </div>
      <a
        href={gettyLicenseUrl}
        target="_blank"
        rel="noopener noreferrer"
        className="inline-flex items-center gap-2 bg-blue-600 text-white px-6 py-3 rounded-lg hover:bg-blue-700"
      >
        License on Getty Images
      </a>
    </div>
  );
}
```

**Expected result:** Clicking any gallery image shows the detail page with the watermarked comp-size image, full caption, photographer info, and a clear link to license the image on Getty's website.

## Best practices

- Never call Getty Images API directly from browser-side code — CORS will block it and the API key would be exposed in network requests; always proxy through a Next.js API route
- Store only Getty image IDs in your database, not the display URLs — Getty's signed preview URLs expire and storing them long-term leads to broken images
- Always display the editorial vs creative asset_type badge on images — editorial images can only be used in news/editorial contexts, not for commercial advertising or marketing
- Link to Getty's own licensing page (gettyimages.com/detail/photo/{id}) rather than trying to implement licensing on the free API tier — Getty's terms require proper licensing flow
- Request specific fields in the Getty API 'fields' parameter to reduce response payload size — the full image object contains dozens of fields you may not need
- Handle Getty API rate limits gracefully with retry logic — the free developer tier has strict rate limits and may return 429 Too Many Requests under high traffic
- During development in Bolt's WebContainer, Getty API calls via your Next.js API route work correctly — Getty's API is accessible over standard HTTP and does not require special network configuration

## Use cases

### Editorial News Photography Search Tool

Build an internal image search tool for a news or media organization that allows journalists and editors to search Getty's editorial archive, preview watermarked images, and initiate licensing for approved images. Filter by event type, date range, and orientation.

Prompt example:

```
Build a Getty Images search interface for editorial photography. Create a Next.js API route at app/api/images/search/route.ts that accepts a GET with query params: q (search term), page, pageSize, asset_type (editorial or creative). Call the Getty Images API search endpoint with the Api-Key header. Return the images array with: id, title, caption, display_sizes (preview URL), and asset_type. Build a search page with a search input, image grid (watermarked previews), and pagination. Each image card shows the preview photo, caption, and photographer credit.
```

### Stock Photo Browser for Creative Teams

Build a creative stock photo browser that filters Getty's creative library by orientation, color, and people count. Team members can search, save favorites to a collection, and share shortlists with each other before initiating licensing through Getty's platform.

Prompt example:

```
Build a creative stock photo browser using the Getty Images API. Add filters for: orientation (horizontal/vertical/square), number_of_people (none/one/small_group), and minimum_quality_rank (1-3). Search creative images only (asset_type=creative). Display results in a masonry grid layout. Add a 'Save to Favorites' button that stores the image ID and preview URL in Supabase favorites table (linked to the current user). Build a /favorites page that shows all saved images with their Getty image IDs for licensing reference.
```

### Automated Press Release Image Matching

Build a tool that analyzes press release text and automatically suggests relevant Getty Images to accompany the story. Take a press release as input, extract key people, events, and topics, search Getty Images for matching editorial content, and return a curated selection of appropriate images.

Prompt example:

```
Build a press release image matcher. Input: a text area for pasting press release content. On submit, extract the top 3 search terms from the text (company names, people, topics — use simple keyword extraction). For each search term, call the Getty Images search API (via our API route) and return the top 3 results. Display a grid of 9 suggested images (3 per search term, labeled with the keyword that found them) with preview images, captions, and Getty image IDs. Add a 'Copy Image ID' button for each image to use when licensing.
```

## Troubleshooting

### Getty API returns 401 Unauthorized for all requests

Cause: The Api-Key header is missing, misspelled (wrong capitalization), or the API key itself has not been approved yet — Getty reviews API applications before granting access.

Solution: Verify the header is exactly 'Api-Key' (capital A and K) in your request. Check that GETTY_API_KEY in your .env file matches the key from developer.gettyimages.com exactly. If your application is still under review, you will not be able to make successful API calls until approval.

```
// Correct Getty header format:
headers: { 'Api-Key': process.env.GETTY_API_KEY }

// WRONG formats that cause 401:
headers: { 'api-key': process.env.GETTY_API_KEY }
headers: { 'Authorization': `Bearer ${process.env.GETTY_API_KEY}` }
```

### Image URLs (thumbUrl, previewUrl, compUrl) return 403 Forbidden when accessed in an img tag

Cause: Getty Images display URLs include a short-lived token in the URL that expires after a period of time, or the URL is being hotlinked from a domain that is not registered with Getty.

Solution: Fetch fresh image URLs from the Getty API for each page load rather than caching URL strings long-term. Do not store Getty preview URLs in your database — store only the Getty image ID and re-fetch the display URLs when needed. Getty's URLs are signed and expire.

```
// Store only the Getty image ID, not the URL:
await supabase.from('favorites').insert({ getty_image_id: image.id, user_id: userId });

// When displaying: fetch fresh URLs from Getty API using the stored ID
const freshImage = await gettyRequest(`/images/${savedImageId}`, { fields: 'display_sizes' });
```

### Search returns no results for certain queries even though images exist on Getty's website

Cause: The asset_type filter may be excluding results — editorial images will not appear in creative searches and vice versa. Or the free developer API tier may have restrictions on certain content types.

Solution: Try removing the asset_type filter to search both editorial and creative images simultaneously. If searching for specific events or news photography, use asset_type=editorial. If the Developers tier does not return expected results, some content may only be accessible to Partners with a Getty commercial agreement.

```
// Search across both asset types by omitting the asset_type filter
const data = await gettyRequest('/search/images', {
  phrase: q,
  page,
  page_size: pageSize,
  // Remove asset_type to search all content
  fields: 'id,title,caption,artist,asset_type,display_sizes',
});
```

### Getty Images API calls work in Bolt's preview but fail with CORS errors if called from the browser

Cause: Getty's API does not allow direct browser-to-API calls (CORS is blocked) — all calls must go through a server-side API route. If you accidentally called Getty's API directly from a React component (using fetch in a useEffect), the browser's CORS policy will block the request.

Solution: Move all Getty API calls to a Next.js API route (app/api/...) and have your React components call your own API route instead. Never call https://api.gettyimages.com directly from client-side code.

```
// WRONG — calling Getty directly from browser (CORS error):
const data = await fetch('https://api.gettyimages.com/v3/search/images?phrase=nature');

// CORRECT — call your own API route from the browser:
const data = await fetch('/api/images/search?q=nature');
// The /api/images/search route calls Getty server-side with the API key
```

## Frequently asked questions

### How do I get access to the Getty Images API?

Go to developer.gettyimages.com and apply for API access. Fill out the application form describing your project and use case — Getty reviews applications before granting API keys, typically within 1-3 business days. Once approved, you receive an API key by email. The free Developers tier provides access to search and watermarked preview endpoints. Licensed downloads require a Getty Partners agreement.

### Do Getty Images API calls work in Bolt's WebContainer during development?

Yes, when called from a Next.js API route (server-side). Getty's API is accessible over HTTPS from Bolt's WebContainer. However, Getty's API blocks direct browser-to-API calls due to CORS restrictions — you must proxy all calls through a Next.js API route. Never call Getty's API from client-side React code.

### What is the difference between Getty's editorial and creative images?

Editorial images document real events — news photography, celebrity events, sports, politics — and can only be used in editorial contexts (news articles, educational content, editorial commentary). They cannot be used for advertising, product promotion, or commercial purposes. Creative images are cleared for commercial use including advertising and marketing. Always filter by asset_type and display this distinction to users to help them choose appropriately licensed images.

### Can I display full-resolution Getty Images on my website?

No — without a license, you can only display Getty's watermarked preview images (comp, preview, and thumb sizes). The watermarks are both visible and invisible (digital steganography). Serving un-watermarked Getty images without proper licensing violates Getty's terms of service, and Getty actively enforces licensing through reverse image search and legal action. Always link users to Getty's licensing page for purchasing rights.

### Can I store Getty preview image URLs in my database?

No — Getty's preview URLs are signed and time-limited. Storing them leads to broken image links after the URLs expire. Instead, store only the Getty image ID in your database and re-fetch the display URLs from the Getty API each time you need to display the image. Getty's API response time is fast enough that fetching URLs on demand is practical.

---

Source: https://www.rapidevelopers.com/bolt-ai-integrations/getty-images-api
© RapidDev — https://www.rapidevelopers.com/bolt-ai-integrations/getty-images-api
