To integrate Replit with the Getty Images API, create a developer account at developers.gettyimages.com, obtain an API key and OAuth client credentials, store them in Replit Secrets (lock icon π), and use your Python or Node.js backend to search and download premium editorial and creative images. Deploy on Autoscale for on-demand image search workloads.
Why Connect Replit to the Getty Images API?
Getty Images is the standard for premium editorial photography, news images, sports photography, and archival content. The Getty Images API (v3) gives developers programmatic access to search hundreds of millions of images and videos, retrieve metadata, generate embed codes for editorial display, and download licensed creative assets. This is essential for media applications, news aggregators, content management platforms, and any product that requires professional-quality imagery with verified licensing.
The Getty Images API uses OAuth 2.0 with the client credentials flow for server-to-server authentication. Your Replit backend exchanges its API key and client secret for a bearer token, then includes that token in API request headers. Tokens expire after a period and must be refreshed, but the client credentials flow makes token management straightforward in a server-side application. Editorial images (news, sports, entertainment) can be displayed via embed URLs without a download license; creative images (commercial photography) require purchasing a license before download.
Replit's Secrets system (lock icon π in the sidebar) is the correct storage for your Getty API key and client secret. Both are sensitive credentials that grant access to your Getty developer account β exposing them could allow unauthorized image downloads billed to your account. Store them in Replit Secrets, access them via environment variables, and never include them in client-side code.
Integration method
You connect Replit to the Getty Images API by registering a developer application at developers.gettyimages.com, obtaining an API key and OAuth 2.0 client credentials, and storing them in Replit Secrets. Your server-side Python or Node.js code authenticates using the client credentials OAuth flow to obtain a bearer token, then searches and retrieves images using the Getty API. Image display in production requires a valid license β the API provides embed URLs for editorial use and downloadable assets for licensed creative content.
Prerequisites
- A Replit account with a Python or Node.js project created
- A Getty Images developer account at https://developers.gettyimages.com
- An approved Getty Images API application (approval may take 1-3 business days for new accounts)
- Understanding of OAuth 2.0 client credentials flow
- Familiarity with image licensing terms (editorial vs creative usage rights)
Step-by-step guide
Register a Getty Images Developer Application
Register a Getty Images Developer Application
Go to https://developers.gettyimages.com and sign in or create a Getty developer account. Navigate to 'My Applications' and click 'Create a new application'. Fill in your application name, description, and intended use case. Getty Images reviews new applications before granting API access β for approved Getty partners and enterprise customers, access is typically granted within 1-3 business days. Once your application is approved, you receive an API Key (client ID) and a Client Secret from the application settings page. The API key is used as a query parameter or header for read-only operations, while the client secret is used in the OAuth token exchange for operations that require a bearer token. Getty Images also offers an Embed API for editorial images that does not require a separate developer application β this is suitable for basic display use cases. The full REST API (v3) at https://api.gettyimages.com/v3 requires developer credentials and is needed for searches, metadata retrieval, and licensed downloads. For sandbox testing, Getty provides a sandbox environment at https://api.gettyimages.com/v3 with a set of test images accessible with sandbox credentials β check your developer dashboard for sandbox API key availability.
Pro tip: Getty Images API access requires application approval. Apply early and describe your use case clearly β news/editorial applications are typically approved faster than open-ended commercial use cases.
Expected result: You have a Getty Images API Key and Client Secret from your approved developer application.
Store Credentials in Replit Secrets
Store Credentials in Replit Secrets
Open your Replit project and click the lock icon π in the left sidebar to open the Secrets pane. Add two secrets: - Key: GETTY_API_KEY β Value: your Getty Images API key (client ID) - Key: GETTY_CLIENT_SECRET β Value: your Getty Images client secret Click 'Add Secret' after each entry. These values are AES-256 encrypted by Replit and injected as environment variables at runtime. Never include them in client-side JavaScript that runs in the browser β Getty API credentials must only be used server-side to prevent unauthorized access to your developer account. If you are building a multi-user application where different users have their own Getty accounts, you would store user-level tokens in your database (encrypted), not as static Replit Secrets. For server-to-server integrations using your own account, the two secrets above are sufficient.
Pro tip: Never use Getty Images API credentials in frontend JavaScript. All API calls must go through your Replit backend to keep the client secret protected and prevent unauthorized image downloads.
Expected result: GETTY_API_KEY and GETTY_CLIENT_SECRET appear in the Replit Secrets pane with values hidden.
Authenticate and Search Images in Python
Authenticate and Search Images in Python
The Getty Images API uses OAuth 2.0 client credentials flow for authentication. Your Python code exchanges the API key and client secret for a bearer token at the token endpoint, then includes the token in Authorization headers for subsequent API requests. The example below implements token management with a simple in-memory cache that refreshes the token when it expires, plus functions for searching images and fetching image details. The search API returns rich metadata including image IDs, titles, captions, keywords, image families (editorial or creative), and URIs for different display sizes. Important licensing note: editorial images can be displayed using embed codes without a download license. Creative images (marked image_family: creative) require purchasing a license before commercial use. Always check the image_family field in search results and display appropriate licensing prompts in your UI.
1import os2import time3import requests45API_KEY = os.environ["GETTY_API_KEY"]6CLIENT_SECRET = os.environ["GETTY_CLIENT_SECRET"]78BASE_URL = "https://api.gettyimages.com/v3"9TOKEN_URL = "https://authentication.gettyimages.com/oauth2/token"1011# Simple token cache12_token_cache = {"token": None, "expires_at": 0}131415def get_access_token() -> str:16 """Get a valid OAuth access token, refreshing if expired."""17 if _token_cache["token"] and time.time() < _token_cache["expires_at"] - 60:18 return _token_cache["token"]1920 resp = requests.post(TOKEN_URL, data={21 "grant_type": "client_credentials",22 "client_id": API_KEY,23 "client_secret": CLIENT_SECRET24 })25 resp.raise_for_status()26 data = resp.json()27 _token_cache["token"] = data["access_token"]28 _token_cache["expires_at"] = time.time() + data.get("expires_in", 1800)29 return _token_cache["token"]303132def get_headers() -> dict:33 return {34 "Authorization": f"Bearer {get_access_token()}",35 "Api-Key": API_KEY,36 "Accept": "application/json"37 }383940def search_images(query: str, image_type: str = "editorial",41 page: int = 1, page_size: int = 10) -> dict:42 """43 Search Getty Images.44 image_type: 'editorial' (news/sports) or 'creative' (commercial stock)45 """46 params = {47 "phrase": query,48 "image_type": image_type,49 "page": page,50 "page_size": page_size,51 "fields": "id,title,caption,date_created,image_family,display_sizes,artist"52 }53 resp = requests.get(f"{BASE_URL}/search/images", params=params, headers=get_headers())54 resp.raise_for_status()55 return resp.json()565758def get_image_details(image_id: str) -> dict:59 """Get detailed metadata for a single image."""60 params = {"fields": "id,title,caption,artist,date_created,image_family,display_sizes,embed"}61 resp = requests.get(f"{BASE_URL}/images/{image_id}", params=params, headers=get_headers())62 resp.raise_for_status()63 return resp.json()646566if __name__ == "__main__":67 results = search_images("technology innovation", image_type="editorial", page_size=5)68 print(f"Found {results.get('result_count', 0)} images")69 for img in results.get("images", []):70 family = img.get("image_family", "unknown")71 title = img.get("title", "")[:60]72 print(f"[{family}] {img['id']}: {title}")Pro tip: Cache the OAuth access token in memory and refresh it only when it is close to expiry. Getty tokens are valid for 30 minutes β making a new token request for every API call wastes quota and slows your app.
Expected result: Running the script prints a list of Getty Images search results with IDs, image families, and titles.
Build a Node.js Getty Images Server
Build a Node.js Getty Images Server
The Node.js implementation follows the same OAuth pattern. Install axios with 'npm install axios'. The server caches the bearer token in a module-level variable and refreshes it automatically before expiry. The Express server below provides search and detail endpoints with proper error handling for common Getty API responses: 401 (token expired), 403 (insufficient permissions for this image type), and 429 (rate limit exceeded). Getty Images rate limits vary by account tier β free developer accounts have lower limits than paid API access.
1const express = require('express');2const axios = require('axios');34const app = express();5app.use(express.json());67const API_KEY = process.env.GETTY_API_KEY;8const CLIENT_SECRET = process.env.GETTY_CLIENT_SECRET;9const BASE_URL = 'https://api.gettyimages.com/v3';10const TOKEN_URL = 'https://authentication.gettyimages.com/oauth2/token';1112let tokenCache = { token: null, expiresAt: 0 };1314async function getAccessToken() {15 if (tokenCache.token && Date.now() < tokenCache.expiresAt - 60000) {16 return tokenCache.token;17 }18 const params = new URLSearchParams({19 grant_type: 'client_credentials',20 client_id: API_KEY,21 client_secret: CLIENT_SECRET22 });23 const { data } = await axios.post(TOKEN_URL, params.toString(), {24 headers: { 'Content-Type': 'application/x-www-form-urlencoded' }25 });26 tokenCache.token = data.access_token;27 tokenCache.expiresAt = Date.now() + (data.expires_in || 1800) * 1000;28 return tokenCache.token;29}3031async function getHeaders() {32 const token = await getAccessToken();33 return {34 Authorization: `Bearer ${token}`,35 'Api-Key': API_KEY,36 Accept: 'application/json'37 };38}3940// Search images41app.get('/search', async (req, res) => {42 const { query, type = 'editorial', page = 1, page_size = 10 } = req.query;43 if (!query) return res.status(400).json({ error: 'query parameter required' });44 try {45 const headers = await getHeaders();46 const { data } = await axios.get(`${BASE_URL}/search/images`, {47 params: {48 phrase: query,49 image_type: type,50 page,51 page_size,52 fields: 'id,title,caption,date_created,image_family,display_sizes,artist'53 },54 headers55 });56 res.json({57 result_count: data.result_count,58 images: data.images.map(img => ({59 id: img.id,60 title: img.title,61 artist: img.artist,62 image_family: img.image_family,63 date_created: img.date_created,64 thumbnail: img.display_sizes?.find(s => s.name === 'thumb')?.uri65 }))66 });67 } catch (err) {68 const status = err.response?.status || 500;69 res.status(status).json({ error: err.response?.data || err.message });70 }71});7273// Get image details74app.get('/image/:id', async (req, res) => {75 try {76 const headers = await getHeaders();77 const { data } = await axios.get(`${BASE_URL}/images/${req.params.id}`, {78 params: { fields: 'id,title,caption,artist,date_created,image_family,display_sizes,embed' },79 headers80 });81 res.json(data);82 } catch (err) {83 const status = err.response?.status || 500;84 res.status(status).json({ error: err.response?.data || err.message });85 }86});8788app.listen(3000, '0.0.0.0', () => {89 console.log('Getty Images integration server running on port 3000');90});Pro tip: The display_sizes array in Getty responses includes URIs for different image sizes (thumb, small, medium, large). Always use the smallest size needed for your UI β large display sizes require higher licensing tiers.
Expected result: The Node.js server returns Getty Images search results with thumbnails and metadata from GET /search?query=technology.
Deploy and Handle Image Licensing
Deploy and Handle Image Licensing
Deploy your Replit app by clicking the Deploy button. For image search APIs that respond to user queries, Autoscale deployment is appropriate and cost-effective. After deploying, verify that your API key and client secret are accessible in the production environment by checking that the token exchange succeeds in deployment logs. For editorial images, you can display images using Getty's embed API without a download license. Use the 'embed' field returned in image details to get the embed HTML code. For creative images that require a download license, your application will need to implement Getty's licensing workflow, which involves an additional API call to initiate a download agreement. Always display proper Getty Images attribution in your UI. The API terms of service require attribution for displayed images. The metadata returned by the API includes the artist name and Getty Images source β display these prominently alongside any image. For production commercial use, ensure your usage falls within your Getty API agreement terms.
Pro tip: Editorial images (news, sports, entertainment) can be embedded for free using Getty's embed code. If you only need editorial images, you may be able to use the Getty Embed API without the full developer application.
Expected result: Your deployed Replit app returns Getty Images search results with proper metadata and your application handles token refresh automatically.
Common use cases
Editorial News Image Search
A Replit-backed content platform searches the Getty Images API for editorial news images related to current events, retrieves embed URLs and metadata (photographer, caption, date), and displays them in an article feed with proper attribution. Editorial embed URLs allow legal display without a separate download license.
Build a Flask API that accepts a news keyword, searches Getty Images for editorial images using that keyword, and returns the top 10 results with titles, captions, photographer names, and embed URLs for display in an article layout.
Copy this prompt to try it in Replit
Automated Blog Header Image Selector
A Replit service receives article topics from a CMS webhook, searches Getty Images for relevant creative images, returns a ranked list of options to an editor dashboard, and stores the selected image ID for licensing when the article is published. This streamlines the image selection step in the editorial workflow.
Create an Express server that accepts a blog post topic, searches Getty Images creative content for matching images, returns the top 5 results with thumbnail URLs and licensing prices, and stores the selected image ID for later download.
Copy this prompt to try it in Replit
Stock Image Licensing Pipeline
A Replit backend automates the image licensing workflow for a marketing team: it receives image IDs approved by designers, checks licensing availability and pricing via the Getty API, and initiates the download of licensed images to an S3 bucket for use in campaigns. Purchase authorization uses Getty's download API with pre-authorized agreements.
Write a Python script that takes a list of Getty image IDs, fetches their licensing details and download sizes, and downloads the highest-resolution version of each licensed image, saving them to local storage.
Copy this prompt to try it in Replit
Troubleshooting
401 Unauthorized on API requests despite correct credentials
Cause: The OAuth access token has expired (default lifetime is 1800 seconds / 30 minutes) and your code is not refreshing it automatically.
Solution: Implement a token cache that checks expiry before each request and re-runs the client credentials token exchange when the cached token is close to expiry. Always subtract 60 seconds from the expiry check to refresh slightly before the actual expiry.
1# Check before each request2if time.time() >= _token_cache['expires_at'] - 60:3 # Re-fetch token4 _token_cache['token'] = fetch_new_token()5 _token_cache['expires_at'] = time.time() + 1800403 Forbidden for certain image types or download requests
Cause: Your Getty developer account tier does not have permission to access certain image types (e.g., creative downloads) or your API agreement does not cover the requested operation.
Solution: Check your Getty developer account agreement in the developer portal. Free/sandbox API access is limited to specific image types and cannot download licensed content. Contact Getty Images to upgrade your API access tier if your use case requires it.
Empty search results for certain queries
Cause: The query may use exact phrase matching or the image_type filter may exclude relevant results. Some queries return no editorial results but many creative results, or vice versa.
Solution: Try searching without the image_type filter to see all results, then filter client-side. Also check the 'result_count' field β if it is zero, the query phrase has no matching images. Try broader search terms or check Getty's search suggestions.
1# Search both types and filter results2results = search_images(query, image_type='editorial')3if results['result_count'] == 0:4 results = search_images(query, image_type='creative')API application not approved or sandbox credentials not working
Cause: New Getty Images developer applications require manual approval. The sandbox environment uses different credentials than production.
Solution: Log into your Getty developer portal and check the application status. If pending, wait 1-3 business days. If using sandbox credentials, confirm you are using the correct sandbox API key from your developer dashboard β sandbox and production API keys are different.
Best practices
- Store GETTY_API_KEY and GETTY_CLIENT_SECRET in Replit Secrets β never use them in client-side JavaScript or expose them in API responses.
- Implement OAuth token caching with automatic refresh before token expiry to avoid 401 errors under load.
- Always check the image_family field (editorial vs creative) in search results and display appropriate licensing information to users.
- Use editorial embed codes for news and sports images that you want to display without a download license β the embed API is free for editorial use.
- Display mandatory Getty Images attribution (photographer name and 'Getty Images') alongside every displayed image as required by the API terms.
- Cache search results for popular queries to reduce API calls and stay within rate limits β Getty search results are stable enough for short-term caching.
- Request only the image size fields your application needs β avoid requesting all display sizes for every search result to reduce response payload size.
- Use Autoscale deployment for image search APIs since request volume is unpredictable and Autoscale scales down during idle periods to reduce costs.
Alternatives
Shutterstock offers volume pricing and a broader catalog of creative commercial photography, making it a better fit for high-volume stock image workflows compared to Getty's premium editorial focus.
Pixabay provides completely free images with no API credentials required for basic use, making it the right choice when budget is a constraint and premium editorial quality is not required.
Vimeo is the better choice when you need high-quality video content rather than still images, offering ad-free video hosting with a privacy-focused API.
Frequently asked questions
How do I store my Getty Images API credentials in Replit?
Click the lock icon π in the left sidebar to open the Secrets pane. Add GETTY_API_KEY with your API key and GETTY_CLIENT_SECRET with your client secret. Access them in Python with os.environ['GETTY_API_KEY'] and in Node.js with process.env.GETTY_API_KEY. Never use these credentials in frontend JavaScript.
Can I use Getty Images for free on Replit?
Getty Images has a free developer tier for sandbox testing with a limited set of test images. Production access to the full Getty library requires an approved API agreement, which may involve usage fees for image downloads. Editorial images can be embedded for free using Getty's Embed API, which does not require a full developer application.
What is the difference between editorial and creative Getty Images?
Editorial images cover news, sports, entertainment, and historical events β they can be displayed using Getty embed codes without a separate download license but cannot be used for commercial advertising. Creative images are commercial stock photography cleared for broad commercial use, requiring a paid download license. The image_family field in API responses tells you which type each image is.
How do I handle Getty Images OAuth token expiry in Replit?
Implement a token cache in your server code that stores the access token and its expiry time. Before each API request, check if the token expires within the next 60 seconds and refresh it if so using the client credentials OAuth flow. This prevents 401 errors under normal operation without requiring a token request for every API call.
Does Getty Images API require attribution in my app?
Yes. Getty Images API terms require you to display photographer attribution and 'Getty Images' as the source for any displayed images. The API returns artist name and source metadata with each image. Always display these credits prominently in your UI alongside the image.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation