Integrate Pixabay's free stock media API into your Bolt.new app with just an API key — no OAuth, no credit card, no licensing fees. Search over 4.5 million Creative Commons images, videos, and illustrations. A simple query parameter API that can be called from client-side code or an API route. Get your free key at pixabay.com/api/docs and start displaying images in under 10 minutes.
Add Free Stock Images and Videos to Your Bolt.new App with Pixabay
Pixabay is the simplest stock media API available for Bolt.new integrations. Every image and video in Pixabay's library is licensed under the Pixabay License, which allows free use for commercial and personal projects without attribution (though attribution is appreciated). The API requires just a single API key passed as a query parameter — no OAuth flow, no token exchange, no webhooks, no complex setup. It is genuinely a 10-minute integration.
The Pixabay API covers four media types: photos (realistic photography), illustrations (digital artwork), vectors (SVG-format graphics), and videos. Each type has its own search endpoint. Results include multiple image size variants (preview thumbnail, web-size, full-size), download URLs, contributor username, view and like counts, and color tags. The API returns up to 200 results per page with a maximum of 20 pages, enabling browsing of up to 4,000 results per query.
For most use cases, Pixabay's API can be called directly from client-side React code since Pixabay's servers include permissive CORS headers. However, proxying through a Next.js API route is the recommended practice: it keeps your API key out of the client bundle (preventing key theft and abuse), enables server-side caching to reduce API calls, and follows the same consistent pattern used for all other integrations in your app. The free tier allows 100 requests per minute, which is sufficient for most apps without caching.
Integration method
Pixabay's API uses simple URL query parameters with your API key — the simplest media API available. Technically, calls can be made from client-side code since Pixabay allows browser origins, but routing through a Next.js API route is recommended to keep the key server-side and add caching. No OAuth, no token exchange, no webhooks. The entire integration works in Bolt's WebContainer preview from the first request.
Prerequisites
- A free Pixabay API key (register at pixabay.com — instant approval, no credit card)
- A Bolt.new project (Vite or Next.js — both work with Pixabay's simple query API)
- No Supabase or external backend required for basic image search
Step-by-step guide
Get Your Pixabay API Key
Get Your Pixabay API Key
Go to pixabay.com and create a free account — registration takes under a minute and requires only an email address and username. After confirming your email, go to the API documentation at pixabay.com/api/docs/. Your API key is displayed on this page once you're logged in. Copy it. The free Pixabay API key allows 100 requests per minute and up to 2,500 images per request (with the `per_page` parameter maxed at 200). There are no daily or monthly limits on the free tier — the only constraint is the 100 requests per minute rate limit. The API key is a simple alphanumeric string passed as the `key` query parameter in every request. Test it immediately: open a new browser tab and go to `https://pixabay.com/api/?key=YOUR_KEY&q=sunset&image_type=photo` — you should see a JSON response with image data. Add the key to your .env.local file as `PIXABAY_API_KEY=your_key_here` (or `VITE_PIXABAY_API_KEY=your_key_here` if using Vite and calling client-side — though server-side is recommended).
Set up a Pixabay integration in my Next.js app. Add PIXABAY_API_KEY to .env.local. Create a lib/pixabay.ts utility that exports a searchImages(query, options) function and a searchVideos(query, options) function. Both should call the Pixabay API using the key from process.env.PIXABAY_API_KEY and return normalized results.
Paste this in Bolt.new chat
1// lib/pixabay.ts2const PIXABAY_BASE = 'https://pixabay.com/api';34export interface PixabayImage {5 id: number;6 pageURL: string;7 type: string;8 tags: string;9 previewURL: string;10 previewWidth: number;11 previewHeight: number;12 webformatURL: string;13 webformatWidth: number;14 webformatHeight: number;15 largeImageURL: string;16 imageWidth: number;17 imageHeight: number;18 downloads: number;19 likes: number;20 views: number;21 user: string;22 userImageURL: string;23}2425export interface PixabayVideo {26 id: number;27 pageURL: string;28 tags: string;29 duration: number;30 picture_id: string;31 user: string;32 userImageURL: string;33 views: number;34 downloads: number;35 likes: number;36 videos: {37 tiny: { url: string; width: number; height: number; size: number };38 small: { url: string; width: number; height: number; size: number };39 medium: { url: string; width: number; height: number; size: number };40 large: { url: string; width: number; height: number; size: number };41 };42}4344export interface PixabaySearchOptions {45 imageType?: 'all' | 'photo' | 'illustration' | 'vector';46 orientation?: 'all' | 'horizontal' | 'vertical';47 category?: string;48 colors?: string;49 order?: 'popular' | 'latest';50 page?: number;51 perPage?: number;52 safeSearch?: boolean;53}5455export async function searchImages(56 query: string,57 options: PixabaySearchOptions = {}58): Promise<{ hits: PixabayImage[]; total: number; totalHits: number }> {59 const params = new URLSearchParams({60 key: process.env.PIXABAY_API_KEY!,61 q: query,62 image_type: options.imageType ?? 'photo',63 orientation: options.orientation ?? 'all',64 order: options.order ?? 'popular',65 page: String(options.page ?? 1),66 per_page: String(Math.min(options.perPage ?? 20, 200)),67 safesearch: options.safeSearch !== false ? 'true' : 'false',68 });6970 if (options.category) params.set('category', options.category);71 if (options.colors) params.set('colors', options.colors);7273 const res = await fetch(`${PIXABAY_BASE}/?${params}`);74 if (!res.ok) throw new Error(`Pixabay API error: ${res.status}`);75 return res.json();76}7778export async function searchVideos(79 query: string,80 options: { order?: 'popular' | 'latest'; page?: number; perPage?: number } = {}81): Promise<{ hits: PixabayVideo[]; total: number; totalHits: number }> {82 const params = new URLSearchParams({83 key: process.env.PIXABAY_API_KEY!,84 q: query,85 order: options.order ?? 'popular',86 page: String(options.page ?? 1),87 per_page: String(Math.min(options.perPage ?? 20, 200)),88 });8990 const res = await fetch(`${PIXABAY_BASE}/videos/?${params}`);91 if (!res.ok) throw new Error(`Pixabay Videos API error: ${res.status}`);92 return res.json();93}Pro tip: Pixabay's safesearch parameter defaults to false in the API. Always set it to true in production apps unless your platform explicitly caters to adult content — safesearch=true ensures family-friendly results.
Expected result: The Pixabay utility is ready. Calling searchImages('sunset') from a server-side API route returns image data with preview and download URLs.
Create the Search API Route
Create the Search API Route
Even though Pixabay allows browser-side calls, create a Next.js API route to proxy requests. This keeps your API key out of the client bundle (where it could be extracted by anyone viewing page source), allows server-side caching to reduce API calls and stay within rate limits, and provides a consistent pattern with your other API integrations. The route accepts `q` (query), `type` (photo/illustration/vector/all), `orientation`, `page`, and `order` parameters. For image search, call `/api/pixabay/images`. For video search, call `/api/pixabay/videos`. In Bolt's WebContainer preview, this outbound HTTPS call to Pixabay's API works without any issues — it's a standard HTTP request, and Bolt's runtime handles outbound connections just fine. You can build and test the full image gallery in the preview before deploying.
Create Next.js API routes for Pixabay. app/api/pixabay/images/route.ts should accept query params q, type (photo/illustration/vector), orientation (horizontal/vertical), page (default 1), per_page (default 20), order (popular/latest). Call searchImages from lib/pixabay.ts and return the results. Also create app/api/pixabay/videos/route.ts for video search.
Paste this in Bolt.new chat
1// app/api/pixabay/images/route.ts2import { NextRequest, NextResponse } from 'next/server';3import { searchImages } from '@/lib/pixabay';45export async function GET(request: NextRequest) {6 const params = request.nextUrl.searchParams;7 const query = params.get('q') ?? '';89 if (!query.trim()) {10 return NextResponse.json({ hits: [], total: 0, totalHits: 0 });11 }1213 try {14 const results = await searchImages(query, {15 imageType: (params.get('type') as 'photo' | 'illustration' | 'vector') ?? 'photo',16 orientation: (params.get('orientation') as 'horizontal' | 'vertical' | 'all') ?? 'all',17 order: (params.get('order') as 'popular' | 'latest') ?? 'popular',18 page: parseInt(params.get('page') ?? '1', 10),19 perPage: parseInt(params.get('per_page') ?? '20', 10),20 safeSearch: true,21 });2223 // Cache for 5 minutes24 return NextResponse.json(results, {25 headers: { 'Cache-Control': 'public, s-maxage=300, stale-while-revalidate=60' },26 });27 } catch (error) {28 console.error('Pixabay search error:', error);29 return NextResponse.json({ error: 'Image search failed' }, { status: 500 });30 }31}Pro tip: Add Cache-Control headers to your API route responses. Pixabay results for popular queries like 'sunset' or 'flowers' don't change frequently — caching for 5 minutes significantly reduces API calls.
Expected result: GET /api/pixabay/images?q=mountain returns Pixabay image results including preview URLs, tags, and contributor names.
Build the Image Gallery Component
Build the Image Gallery Component
Create a responsive image gallery that searches Pixabay and displays results in a grid. The gallery needs a search input with debouncing (wait 400ms after the user stops typing before firing the API call), a loading skeleton while results fetch, a responsive CSS Grid layout that shows 2 columns on mobile and 4 columns on desktop, and lazy-loaded images using the `loading='lazy'` attribute for performance. Each image card should show the Pixabay `webformatURL` (medium-size image, suitable for gallery display), the contributor's username, view/like counts, and a download button. The `largeImageURL` is the full-size download version. Clicking an image should open a lightbox or modal with the larger version and metadata. Add a filter row above the grid: image type tabs (Photos / Illustrations / Vectors), orientation toggle (All / Horizontal / Vertical), and sort order (Popular / Latest). Pagination loads the next page of results when the user scrolls to the bottom or clicks 'Load More'.
Build a PixabayGallery component. Include: (1) a search input that queries /api/pixabay/images as the user types (400ms debounce); (2) filter tabs for type (Photos/Illustrations/Vectors) and orientation (All/Horizontal/Vertical); (3) a responsive 2-4 column CSS grid of image cards showing webformatURL, contributor, and likes; (4) a lightbox modal when clicking an image that shows largeImageURL, tags, and a Download button linking to largeImageURL; (5) a Load More button for pagination; (6) a 'Photo by {user} on Pixabay' attribution below each image.
Paste this in Bolt.new chat
Pro tip: Pixabay's webformatURL includes a resolution suffix (e.g., _640.jpg). You can get higher quality by replacing '_640' with '_1280' for the gallery display without fetching the full-size largeImageURL.
Expected result: A fully functional image gallery works in Bolt's WebContainer preview — search, filter, paginate, and view images in a lightbox, all with live Pixabay data.
Handle Downloads and Attribution
Handle Downloads and Attribution
Pixabay's license allows free commercial and personal use of all images without mandatory attribution. However, attribution is strongly encouraged as best practice and is appreciated by contributors. Add an attribution line below each image: 'Photo by {user} on Pixabay' with a link to the original image's `pageURL`. For downloads, Pixabay provides direct download URLs for different sizes. The `largeImageURL` is the full-resolution JPEG. Note that the `largeImageURL` and `imageURL` fields require an API call to a specific endpoint to get the actual full-resolution URL — the search results only include up to the large preview. To enable direct downloads, link the download button to the `webformatURL` (which is freely downloadable) or the `largeImageURL`. For video downloads, use the `videos.large.url` or `videos.medium.url` from the video search results. Implement the download as a fetch-then-blob approach to trigger the browser's download dialog, since direct link navigation may just open the image in a new tab instead of downloading.
Add download functionality to the Pixabay gallery. Create a downloadImage(url, filename) utility that fetches the image, converts to a blob, and triggers a browser download. Add a Download button to each image card and in the lightbox modal. Show the image resolution (width x height pixels) and file size in the modal. Add 'Photo by {user} on Pixabay' attribution under each image with a link to the original Pixabay page.
Paste this in Bolt.new chat
1// utils/download.ts2export async function downloadMedia(url: string, filename: string): Promise<void> {3 try {4 const response = await fetch(url);5 const blob = await response.blob();6 const objectUrl = URL.createObjectURL(blob);7 8 const link = document.createElement('a');9 link.href = objectUrl;10 link.download = filename;11 document.body.appendChild(link);12 link.click();13 document.body.removeChild(link);14 URL.revokeObjectURL(objectUrl);15 } catch (error) {16 console.error('Download failed:', error);17 // Fallback: open in new tab18 window.open(url, '_blank');19 }20}2122// Usage in component:23// downloadMedia(image.largeImageURL, `pixabay-${image.id}.jpg`);Pro tip: The Pixabay License requires that images are not redistributed as a standalone file or used to create competing stock photo sites. Standard use in apps, websites, and content is fully allowed without attribution — but adding attribution is good practice.
Expected result: Users can download images directly from the gallery. Clicking Download triggers a file download rather than opening the image in a new tab. Attribution shows below each image.
Common use cases
Image Picker for Content Creation Tools
Embed a Pixabay image search inside a blog editor, email builder, or social media post creator. Users can search for relevant free images and insert them directly into their content without leaving the app.
Add a Pixabay image picker to my content editor. Create a modal with a search input and a grid of Pixabay photo results. Users can type a search term, browse results, and click an image to insert its URL into the editor. Show image tags, contributor name, and dimensions on hover. Use the Pixabay API with my API key stored in environment variables.
Copy this prompt to try it in Bolt.new
Background Image Selector
Let users customize their profile, dashboard, or presentation background by choosing from Pixabay's curated image collection. Search by color, category, or keyword. Preview images before selecting.
Build a background image selector that searches Pixabay for high-resolution landscape and abstract images. Show a grid of large previews. When the user selects an image, set it as their profile background and save the Pixabay image URL to Supabase. Allow searching by keyword and filtering by orientation (horizontal/vertical) and color.
Copy this prompt to try it in Bolt.new
Stock Video Browser for Video Projects
A video search interface that lets users find free Pixabay videos by keyword and duration. Show video previews with play-on-hover and download links. Filter by resolution (HD, 4K) and duration.
Build a free stock video browser using the Pixabay Videos API. Search for videos by keyword, show results in a grid with animated preview on hover, display resolution badge (HD/4K) and duration. When a user clicks a video, show a modal with the full preview and download button links for SD, HD, and 4K versions. Use /api/pixabay/videos as the server-side proxy route.
Copy this prompt to try it in Bolt.new
Troubleshooting
Pixabay API returns 400 Bad Request for search queries
Cause: The API key is missing, malformed, or the query parameter has special characters that are not URL-encoded.
Solution: Verify PIXABAY_API_KEY is set in .env.local. Use encodeURIComponent(query) or URLSearchParams to properly encode the search query. Confirm the key is passed as the 'key' parameter (not 'api_key' or 'apiKey').
1const params = new URLSearchParams({2 key: process.env.PIXABAY_API_KEY!,3 q: query, // URLSearchParams auto-encodes4 per_page: '20',5});Images return 403 Forbidden when loading in the browser
Cause: The direct `largeImageURL` may have download restrictions. The `webformatURL` is intended for embedding; `largeImageURL` may require authentication for direct access.
Solution: Use `webformatURL` for gallery display and thumbnails — it is always accessible for embedding. For the download action, use the fetch-then-blob approach in utils/download.ts rather than direct image links. The `previewURL` (thumbnail) and `webformatURL` are always embeddable.
Rate limit errors (429 Too Many Requests) during development
Cause: The free Pixabay API tier allows 100 requests per minute. Fast typing in the search input without debouncing can exhaust the limit quickly.
Solution: Add a 400ms debounce to the search input. Add Cache-Control headers to your API route to cache responses. The cache means repeated searches for the same query don't consume additional API calls.
1// Add debounce to search input2const [debouncedQuery, setDebouncedQuery] = useState(query);3useEffect(() => {4 const timer = setTimeout(() => setDebouncedQuery(query), 400);5 return () => clearTimeout(timer);6}, [query]);Video previews don't play in the gallery
Cause: Pixabay video URLs use `.mp4` format but browser autoplay policies block unmuted videos from autoplaying.
Solution: Add muted and playsInline attributes to video elements for hover-preview. Only trigger play() on mouseenter events. For the full preview modal, allow user-initiated play with sound.
1<video2 src={video.videos.tiny.url}3 muted4 playsInline5 loop6 onMouseEnter={(e) => (e.target as HTMLVideoElement).play()}7 onMouseLeave={(e) => (e.target as HTMLVideoElement).pause()}8/>Best practices
- Store your Pixabay API key in environment variables and access it server-side — even though Pixabay allows client-side calls, keeping the key server-side prevents abuse and key theft
- Add debouncing (400ms) to search inputs to avoid exhausting the 100 requests per minute rate limit during fast typing
- Cache API route responses with Cache-Control headers — Pixabay's popular results change infrequently and caching significantly reduces API usage
- Always set safesearch=true in production unless your platform explicitly caters to adult content
- Include 'Photo by {user} on Pixabay' attribution in your UI as best practice — while not legally required, it supports the community of contributors
- Use webformatURL for gallery thumbnails and largeImageURL for full-size modal views — don't load large images in grid thumbnails
- For the download action, use fetch-then-blob to trigger the browser's download dialog rather than direct link navigation, which may open the image in a new tab
Alternatives
Shutterstock offers a larger premium library with commercial licensing for apps requiring professional photography not available in Pixabay's free collection.
Getty Images provides exclusive editorial and premium creative content for high-end publishing and media applications where image quality and exclusivity matter.
Canva's API provides a full design editor experience with its asset library, useful when users need to edit or customize images rather than just search and display them.
Frequently asked questions
Is Pixabay API free to use in commercial projects?
Yes. The Pixabay API is free to use and the images are licensed under the Pixabay License, which allows free commercial and non-commercial use without mandatory attribution. The API key is free with no monthly or per-request fees — only rate limits (100 requests/minute) apply.
Can I call the Pixabay API directly from client-side React in Bolt?
Technically yes — Pixabay's servers include CORS headers that allow browser-side calls. However, routing through a Next.js API route is strongly recommended to keep your API key out of the client bundle, enable server-side caching, and maintain consistent integration patterns. Your API key in client code can be extracted by anyone viewing page source.
Does the Pixabay API work in Bolt's WebContainer preview?
Yes, completely. Pixabay's API is HTTP-based with no native modules or TCP sockets required. Outbound HTTPS calls work in Bolt's WebContainer, so you can build and test the full image gallery in the preview before deploying. There are no webhook requirements for Pixabay.
How many images can I get per API request?
The Pixabay API returns up to 200 images per request (set per_page=200). Total search results are capped at the totalHits value returned in the response. You can paginate through results using the page parameter, giving access to up to 4,000 results per query (200 per page × 20 pages maximum).
How do I deploy a Bolt.new app with Pixabay to Netlify?
Connect Netlify in Bolt Settings → Applications and click Publish. Add PIXABAY_API_KEY to Netlify's environment variables in Site Configuration → Environment Variables. Redeploy to apply. No webhook registration or OAuth configuration is needed — Pixabay's simple API key setup requires only this one environment variable.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation