# How to Integrate Getty Images API with V0

- Tool: V0
- Difficulty: Intermediate
- Time required: 30 minutes
- Last updated: March 2026

## TL;DR

To integrate the Getty Images API with V0 by Vercel, generate an image search UI with V0, create a Next.js API route that searches and retrieves embed codes from the Getty Images API using your API key, and store credentials in Vercel environment variables. Getty Images API access requires approval — the free tier provides embed-only access, while licensing images for download requires a paid Getty API plan.

## Premium Stock Photography in Your V0 App with Getty Images API

Getty Images is the gold standard for premium stock photography — the library includes over 477 million images, videos, and music tracks spanning editorial, creative, and archival content. For applications that need high-quality imagery that goes beyond what free platforms like Unsplash or Pixabay offer — sports photography, news events, exclusive celebrity photos, historical archives — the Getty Images API provides programmatic access to this catalog.

The Getty Images API has two distinct tiers with very different capabilities. The free Embed tier lets you display Getty images on your website using Getty's hosted iframe embed codes — the images include a Getty watermark and are intended for editorial use. This requires API access approval but no per-image fees. The full API access tier (requiring a partnership or licensing agreement with Getty) enables image downloads for commercial use, custom creative access, and removal of watermarks. Most developer tutorials and use cases involve the Embed tier.

For V0 developers, the most practical use cases are: building an editorial content platform that embeds Getty photos, creating an internal image search tool for a marketing team, or building a digital asset selection interface for a publication. The search API lets you query by keyword, orientation, image type (photo, illustration, vector), license type, and many other facets — returning rich metadata including editorial descriptions, capture dates, and the embed code for licensed display.

## Before you start

- A Getty Images developer account — apply at developers.gettyimages.com; API access requires approval (typically 1-3 business days for the embed tier)
- Getty Images API key and API secret — obtained after approval from your Getty Images developer portal
- Understanding of Getty's licensing model: Embed tier allows iframe embeds only (with watermark), full API requires a commercial licensing agreement
- A V0 account and Next.js project deployed to Vercel — Getty API credentials must be stored as server-side environment variables
- Familiarity with iframe embedding for the embed tier, as Getty-licensed images are displayed via hosted iframes rather than direct image URLs

## Step-by-step guide

### 1. Generate the Image Search UI with V0

Start with the search interface — this is where V0 shines for image-heavy applications. Prompt V0 to build a search page with a text input, filter controls, and a responsive image grid. The grid should handle varying image aspect ratios gracefully — use a masonry or fixed-aspect-ratio grid depending on your aesthetic preference.

For displaying Getty images, you have two options depending on your API tier: the embed tier uses iframes with Getty's hosted embed code (which includes the Getty watermark and copyright), while paid API tiers allow direct image URL display. Design your component to accept both cases — use an iframe container for embed codes and an img tag for direct URLs.

Include filter controls that map to Getty's search parameters: orientation (horizontal, vertical, square), image type (photography, illustration, vector), and editorial/creative flag. These filters significantly narrow results to match a user's intent. Also include a loading skeleton state for the search results — Getty API calls typically take 300-800ms, and users need visual feedback that the search is in progress.

Prompt V0 to add infinite scroll or pagination to the image grid — Getty's search returns up to 500 results per query and your users will want to browse beyond the first page. A 'Load More' button at the bottom of the grid is simpler to implement than infinite scroll and works well for this use case.

**Expected result:** A responsive image search page in V0 with search input, filter controls, an iframe grid layout, loading states, and pagination — ready to receive real Getty Images embed codes.

### 2. Create the Getty Images Search API Route

Build the Next.js API route that authenticates with the Getty Images API and searches the image catalog. Getty's API uses OAuth2 client credentials flow — you exchange your API key and secret for an access token, then use that token to make search requests. Access tokens are valid for 30 minutes.

The Getty Images REST API v3 base URL is https://api.gettyimages.com/v3. The search endpoint is GET /search/images with parameters for phrase (search keywords), fields (which data to return), page, page_size, orientations, image_type, and many more filters. By default, the API returns a large set of fields — specify only what you need using the fields parameter to improve performance.

For embed tier access, the most important field to return is embed_content_url — this is the iframe URL you display to end users. The response also includes id, title, caption, display_sizes (thumbnail URL array), artist, collection_name, and asset_family (editorial vs. creative).

Authentication uses HTTP Basic Auth for the token request: base64-encode 'api_key:api_secret' and pass as the Authorization header. The token endpoint is POST https://authentication.gettyimages.com/oauth2/token with grant_type=client_credentials. Cache the resulting token for its expiration period (typically 1800 seconds) to avoid repeated token requests.

```
import { NextResponse } from 'next/server';

const GETTY_API_KEY = process.env.GETTY_API_KEY!;
const GETTY_API_SECRET = process.env.GETTY_API_SECRET!;
const GETTY_BASE = 'https://api.gettyimages.com/v3';
const GETTY_AUTH_URL = 'https://authentication.gettyimages.com/oauth2/token';

// Simple in-memory token cache (resets on cold start)
let cachedToken: { value: string; expiresAt: number } | null = null;

async function getAccessToken(): Promise<string> {
  if (cachedToken && Date.now() < cachedToken.expiresAt - 60000) {
    return cachedToken.value;
  }

  const credentials = Buffer.from(`${GETTY_API_KEY}:${GETTY_API_SECRET}`).toString('base64');

  const response = await fetch(GETTY_AUTH_URL, {
    method: 'POST',
    headers: {
      Authorization: `Basic ${credentials}`,
      'Content-Type': 'application/x-www-form-urlencoded',
    },
    body: 'grant_type=client_credentials',
  });

  if (!response.ok) {
    throw new Error(`Getty auth failed: ${response.status}`);
  }

  const data = await response.json();
  cachedToken = {
    value: data.access_token,
    expiresAt: Date.now() + data.expires_in * 1000,
  };
  return data.access_token;
}

export async function GET(request: Request) {
  const { searchParams } = new URL(request.url);
  const phrase = searchParams.get('phrase') || '';
  const page = searchParams.get('page') || '1';
  const orientation = searchParams.get('orientation') || '';

  if (!phrase) {
    return NextResponse.json({ error: 'phrase parameter required' }, { status: 400 });
  }

  try {
    const token = await getAccessToken();

    const params = new URLSearchParams({
      phrase,
      page_size: '30',
      page,
      fields: 'id,title,caption,display_sizes,embed_content_url,artist,collection_name,asset_family',
      ...(orientation && { orientations: orientation }),
    });

    const response = await fetch(`${GETTY_BASE}/search/images?${params}`, {
      headers: {
        Authorization: `Bearer ${token}`,
        'Api-Key': GETTY_API_KEY,
      },
      next: { revalidate: 300 },
    });

    if (!response.ok) {
      return NextResponse.json(
        { error: 'Getty search failed' },
        { status: response.status }
      );
    }

    const data = await response.json();

    const images = data.images.map((img: any) => ({
      id: img.id,
      title: img.title,
      caption: img.caption,
      thumbnail: img.display_sizes?.find((s: any) => s.name === 'thumb')?.uri || '',
      embedUrl: img.embed_content_url || '',
      artist: img.artist,
      collection: img.collection_name,
      isEditorial: img.asset_family === 'editorial',
    }));

    return NextResponse.json({
      images,
      totalCount: data.result_count,
      page: parseInt(page),
    });
  } catch (error) {
    console.error('Getty API error:', error);
    return NextResponse.json({ error: 'Failed to search Getty Images' }, { status: 500 });
  }
}
```

**Expected result:** GET /api/getty/search?phrase=technology+office returns an array of Getty image objects with IDs, titles, thumbnails, and embed URLs.

### 3. Add Getty Images Credentials to Vercel Environment Variables

Store your Getty Images API key and API secret in Vercel's environment variable system. These credentials authenticate your entire application to the Getty Images API — if exposed, anyone could search the Getty catalog on your behalf and consume your API quota.

Go to your Getty Images developer account at developers.gettyimages.com, navigate to your application's API credentials page, and copy your API key and API secret. These are separate from your Getty Images account login credentials — they're generated when you create a developer application.

In Vercel Dashboard → Settings → Environment Variables, create two new variables: GETTY_API_KEY (your application's API key) and GETTY_API_SECRET (your application's secret key). Both should be server-only variables — do not add the NEXT_PUBLIC_ prefix, as these credentials must never reach the browser. Select all three scopes (Production, Preview, Development) and click Save.

For local development, add both variables to your .env.local file. Getty's sandbox and production environments use the same API key — there is no separate sandbox environment, but the developer tier restricts access to embed-only content automatically based on your API agreement tier. After adding the variables in Vercel, redeploy your application from the Deployments tab.

```
# .env.local
GETTY_API_KEY=your_getty_api_key_here
GETTY_API_SECRET=your_getty_api_secret_here
```

**Expected result:** GETTY_API_KEY and GETTY_API_SECRET are visible in Vercel environment variables, and the search API route returns real image results from the Getty catalog.

### 4. Display Getty Images with Embed Codes and Licensing Compliance

Getty Images has specific requirements for how images from the Embed API must be displayed. Images accessed via the embed tier must be shown using Getty's official iframe embed code — you cannot display them as plain img tags or download the image files. The iframe includes Getty's watermark and a link back to Getty Images, which is a licensing requirement.

In your React component, replace the img tags in your gallery with iframe elements using the embedUrl from the API response. Getty's embed iframes are designed to be responsive — set width to 100% and let the height be determined by the iframe content, or use a fixed aspect ratio container.

Update your V0-generated component to render iframes for embed-tier images. Use the embedUrl from your API response as the iframe src. Add a title attribute for accessibility. The Getty iframe handles its own loading state, but you can show a loading skeleton in the container div before the iframe loads by listening to the iframe's onLoad event.

For applications that need direct image URLs (for use as CSS backgrounds, canvas drawing, or server-side processing), you must have a full commercial API licensing agreement with Getty. The embed tier is explicitly for web display only via their hosted iframe player. This is important to communicate in your app's terms of service.

```
// components/GettyImageCard.tsx
interface GettyImageCardProps {
  id: string;
  title: string;
  caption?: string;
  embedUrl: string;
  artist?: string;
  isEditorial: boolean;
}

export function GettyImageCard({ title, embedUrl, artist, isEditorial }: GettyImageCardProps) {
  return (
    <div className="rounded-lg overflow-hidden border border-gray-200 shadow-sm">
      <div className="relative" style={{ aspectRatio: '16/9' }}>
        {embedUrl ? (
          <iframe
            src={embedUrl}
            title={title}
            width="100%"
            height="100%"
            style={{ border: 'none' }}
            allowFullScreen
            scrolling="no"
            referrerPolicy="no-referrer-when-downgrade"
          />
        ) : (
          <div className="w-full h-full bg-gray-100 flex items-center justify-center">
            <span className="text-gray-400 text-sm">No preview available</span>
          </div>
        )}
        <span
          className={`absolute top-2 right-2 text-xs px-2 py-0.5 rounded font-medium ${
            isEditorial
              ? 'bg-blue-100 text-blue-800'
              : 'bg-green-100 text-green-800'
          }`}
        >
          {isEditorial ? 'Editorial' : 'Creative'}
        </span>
      </div>
      <div className="p-3">
        <p className="text-sm font-medium line-clamp-2">{title}</p>
        {artist && (
          <p className="text-xs text-gray-500 mt-1">© {artist} / Getty Images</p>
        )}
      </div>
    </div>
  );
}
```

**Expected result:** The gallery displays Getty images as embedded iframes with proper attribution, editorial/creative badges, and titles — compliant with Getty's embed tier licensing requirements.

## Best practices

- Always display proper Getty Images attribution including photographer/artist name and the Getty Images logo or text credit — this is required by the embed tier license agreement
- Filter API results by embed_content_url availability before displaying them — not all Getty images are available for embedding, and showing broken iframes degrades user experience
- Cache Getty API token and search results aggressively — the access token is valid for 30 minutes and search results for popular queries rarely change within minutes, so caching prevents unnecessary API calls
- Be transparent with your users about editorial vs. creative licensing — editorial images cannot be used for commercial purposes (advertising, product promotion), while creative images can
- Implement rate limiting on your /api/getty/search route to prevent a single user from exhausting your Getty API quota — consider adding a per-IP or per-session rate limit
- Include a clear 'Powered by Getty Images' attribution on pages displaying Getty content — this is typically required by the embed API terms
- Use the fields parameter in every Getty API request to request only the data your UI needs — the full image metadata object is large, and requesting unnecessary fields wastes bandwidth

## Use cases

### Editorial Image Search for Content Teams

Build an internal image search tool where your editorial or marketing team can search Getty's library, preview images, and get embed codes or download URLs for approved images. The tool saves time compared to navigating Getty's website and can integrate directly with your CMS workflow.

Prompt example:

```
Create an image search page with a prominent search input and a masonry grid of results. Each image card shows a thumbnail, caption, collection type (Editorial/Creative), orientation badge, and a 'Copy Embed Code' button. Include filter options for orientation (horizontal/vertical), image type (photo/illustration), and editorial/creative. Fetch results from /api/getty/search.
```

### Embeddable Photo Gallery for Editorial Content

Create a photo gallery component for an editorial blog or news site that displays Getty-licensed images using their official embed codes. The gallery fetches images from a specific Getty collection or event via the API and renders them in a responsive grid with captions.

Prompt example:

```
Build a photo gallery section that displays images using Getty Images embed iframes. Show images in a 3-column responsive grid. Each image shows in a 16:9 iframe container with the caption below. Add a loading state while embed codes load. Accept an array of Getty embed codes as props.
```

### Stock Photo Licensing Workflow

Build a licensing request workflow where users search for images, select ones they want to license, and submit a licensing request that creates a saved collection in Getty for follow-up. Show pricing estimates based on image type and usage rights.

Prompt example:

```
Create a stock photo licensing tool with a search input and results grid. Add a 'Save to Collection' button on each image that adds it to a saved list panel on the right. The panel shows saved images with checkboxes and a 'Request Licensing' button that posts the selected image IDs to /api/getty/license-request. Show a confirmation message after submission.
```

## Troubleshooting

### Getty API returns 401 Unauthorized — 'InvalidApiKey' or 'InvalidAccessToken'

Cause: The API key or secret is incorrect, the access token has expired, or the API key doesn't have permission for the endpoint being called.

Solution: Verify both GETTY_API_KEY and GETTY_API_SECRET are correct in your Vercel environment variables. Check that the token caching logic is not serving an expired token — the token is valid for 1800 seconds but serverless functions can cache in memory across warm invocations. If using the in-memory cache pattern, verify the expiry check logic.

```
// Ensure token expiry check accounts for clock drift
if (cachedToken && Date.now() < cachedToken.expiresAt - 120000) { // 2-minute buffer
  return cachedToken.value;
}
```

### Getty embed iframes show a broken layout or don't render in the app

Cause: The iframe embed URL may be missing required parameters, the container has restrictive CSS overflow settings, or Content Security Policy headers block the Getty iframe source.

Solution: Check your Next.js Content-Security-Policy headers to ensure embed.gettyimages.com and related Getty domains are in the frame-src allowlist. Also verify the embed container has no overflow: hidden on the iframe itself (only on the wrapper div). Check that embedUrl from the API is not null or undefined — use a conditional render.

```
// next.config.ts — Allow Getty embed iframes
{
  key: 'Content-Security-Policy',
  value: "frame-src 'self' https://embed.gettyimages.com https://*.gettyimages.com"
}
```

### Search returns results but embed URLs are null or missing

Cause: Not all Getty images are available in the embed tier — rights-managed and some editorial images require a full commercial license and don't have public embed URLs.

Solution: Filter your search results to images that have a valid embed_content_url. Add an image_type filter for creative stock images, which have broader embed availability. For editorial content, only some images are available for embedding; others require commercial licensing.

```
// Filter out images without embed URLs
const images = data.images
  .filter((img: any) => img.embed_content_url)
  .map((img: any) => ({ /* ... */ }));
```

## Frequently asked questions

### Do I need to pay for Getty Images API access?

The Getty Images Embed API tier is free but requires approval at developers.gettyimages.com. It allows you to embed Getty images using their hosted iframes with watermarks. Downloading images for commercial use requires a commercial licensing agreement with Getty, which has separate pricing based on usage volume and image types.

### Can I display Getty images as plain img tags or download them with the free API?

No — the embed tier only allows display via Getty's official iframe embed codes, which include their watermark and copyright notice. Using direct image URLs to display images without the watermark, or downloading image files, requires a commercial API license. Using Getty images outside of their permitted embed method violates their terms and can result in copyright claims.

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

Editorial images document real events (news, sports, entertainment) and can only be used for editorial purposes — news articles, educational content, commentary. They cannot be used for advertising or commercial promotion. Creative images are studio shoots, conceptual photography, and illustrations cleared for commercial use — you can use them in ads, product promotions, and branded content with the appropriate license.

### How do I handle the Getty Images attribution requirement in my app?

Getty requires visible attribution on all embedded images. The iframe embed code automatically includes Getty's branding, but you should also display the photographer's name (from the artist field in the API response) and a 'Getty Images' text credit below each image. This is both a legal requirement and good practice for respecting photographers' rights.

### How many API calls can I make with the free Getty Images embed tier?

Getty's API documentation specifies rate limits in the developer portal, but they're not prominently published. In practice, the embed tier is designed for web app use and supports reasonable request volumes. Add caching to your Next.js API route (next: { revalidate: 300 }) to reduce redundant API calls, and contact Getty's developer support if you need higher rate limits for a high-traffic application.

---

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