Skip to Content
ProvidersPixabay

Pixabay

Category: Stock Images
Integration type: Platform-level API key
External API: Pixabay API v2


Purpose

Pixabay provides free-to-use stock photos, illustrations, and vectors licensed under the Pixabay License (free for commercial use, no attribution required). It is used by the Blog Writer, Social Post Writer, and GBP Post Writer agents to find and attach relevant images to generated content.

Pixabay is the platform default image source — no tenant configuration required. All search costs are absorbed by the platform (free API for low-to-medium volume).

See also Unsplash for higher-quality photography when required.


Config Structure

Platform config (env vars)

PIXABAY_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # From pixabay.com/api/docs/ PIXABAY_API_BASE_URL=https://pixabay.com/api/

Integration Pattern

Tool layer (packages/tools/src/pixabay.ts)

import axios from 'axios'; class PixabayTool { constructor( private apiKey: string, private baseUrl: string = 'https://pixabay.com/api/', ) {} async searchImages(options: { query: string; imageType?: 'photo' | 'illustration' | 'vector'; // Default: 'photo' orientation?: 'horizontal' | 'vertical' | 'all'; // Default: 'horizontal' category?: string; // 'backgrounds' | 'fashion' | 'nature' | 'science' | 'technology' | etc. minWidth?: number; // Minimum image width in pixels minHeight?: number; safeSearch?: boolean; // Default: true order?: 'popular' | 'latest'; // Default: 'popular' page?: number; // Default: 1 perPage?: number; // 3–200, Default: 20 }): Promise<PixabaySearchResult> { const response = await axios.get(this.baseUrl, { params: { key: this.apiKey, q: options.query, image_type: options.imageType ?? 'photo', orientation: options.orientation ?? 'horizontal', category: options.category, min_width: options.minWidth, min_height: options.minHeight, safesearch: options.safeSearch !== false ? 'true' : 'false', order: options.order ?? 'popular', page: options.page ?? 1, per_page: options.perPage ?? 20, }, }); return { totalHits: response.data.totalHits, total: response.data.total, images: response.data.hits.map((hit: any) => ({ id: hit.id, pageUrl: hit.pageURL, type: hit.type, tags: hit.tags.split(', '), previewUrl: hit.previewURL, // 150px thumbnail webUrl: hit.webformatURL, // ~640px web-ready largeUrl: hit.largeImageURL, // ~1280px fullHdUrl: hit.fullHDURL, // Full HD (requires API key tier) width: hit.imageWidth, height: hit.imageHeight, likes: hit.likes, views: hit.views, downloads: hit.downloads, photographer: hit.user, photographerUrl: `https://pixabay.com/users/${hit.user}-${hit.user_id}/`, })), }; } async searchVideos(options: { query: string; videoType?: 'film' | 'animation' | 'all'; order?: 'popular' | 'latest'; page?: number; perPage?: number; }): Promise<PixabayVideoResult> { const response = await axios.get(`${this.baseUrl}videos/`, { params: { key: this.apiKey, q: options.query, video_type: options.videoType ?? 'all', order: options.order ?? 'popular', page: options.page ?? 1, per_page: options.perPage ?? 20, }, }); return { totalHits: response.data.totalHits, videos: response.data.hits.map((hit: any) => ({ id: hit.id, pageUrl: hit.pageURL, tags: hit.tags.split(', '), duration: hit.duration, videos: { tiny: hit.videos.tiny?.url, small: hit.videos.small?.url, medium: hit.videos.medium?.url, large: hit.videos.large?.url, }, photographer: hit.user, })), }; } async verify(): Promise<void> { const result = await this.searchImages({ query: 'test', perPage: 3 }); if (result.total === undefined) { throw new Error('Pixabay API verification failed'); } } }

Agent image selection

When the Blog Writer or Social Post Writer produces content, the agent’s tool integration can call pixabay_search to find relevant images:

// Tool registration in agent execution engine { name: 'pixabay_search', description: 'Search for free stock images relevant to the content being created', parameters: { query: { type: 'string' }, imageType: { type: 'string', enum: ['photo', 'illustration', 'vector'] }, orientation: { type: 'string', enum: ['horizontal', 'vertical'] }, }, }

The agent returns image IDs and URLs; the platform downloads the selected image to S3, then uses the S3 URL for WordPress/Instagram/etc. publishing.


Image Download and Storage

Images are not stored long-term — they are downloaded on use:

// Before publishing to WordPress/Instagram async function fetchAndStoreImage( pixabayImage: PixabayImage, tenantId: string, activityId: string, ): Promise<string> { const imageBuffer = await axios.get(pixabayImage.largeUrl, { responseType: 'arraybuffer' }); const s3Key = `media/${tenantId}/pixabay/${activityId}/${pixabayImage.id}.jpg`; const { url } = await s3.upload({ key: s3Key, body: Buffer.from(imageBuffer.data), contentType: 'image/jpeg', }); return url; }

Pixabay License

Images from Pixabay are licensed under the Pixabay License:

  • Free for commercial and non-commercial use
  • No attribution required (but encouraged)
  • Cannot sell the images as-is or redistribute on stock image platforms

The platform should not claim copyright over Pixabay images — attribution can optionally be added to blog posts as Photo by {photographer} via Pixabay.


Test Cases

Unit tests (packages/tools/src/pixabay.test.ts)

TestApproach
searchImages() builds correct paramsMock axios.get; assert key, q, image_type, safesearch
searchImages() defaults to safesearch: trueAssert safesearch === 'true' when option not set
searchImages() maps tags string to arrayMock tags: 'dog, outdoor, park'; assert ['dog', 'outdoor', 'park']
searchImages() exposes all image URL variantsAssert previewUrl, webUrl, largeUrl mapped
searchVideos() uses /videos/ endpointAssert URL contains /api/videos/
verify() throws when response malformedMock {}; assert throws
Throws on 429 (rate limit)Mock 429; assert propagated

© 2026 Leadmetrics — Internal use only