Provider comparison
@media-sdk/core ships two built-in MediaClient implementations: PexelsMediaClient and PixabayMediaClient. Both normalize responses into the same Photo, Video, and Pagination types so your application logic stays provider-neutral.
Quick summary
| Pexels | Pixabay | |
|---|---|---|
| Best for | Curated feeds, size filter, video orientation | Category/dimension filters, editor's choice |
| Auth | Authorization header | key= query parameter |
| Curated photos | ✅ | ❌ |
| Hotlinking rules | Standard API terms | Must serve API-returned URLs |
| Pagination URLs | nextPage / prevPage preserved | Page-number only |
Operation capability matrix
| Operation / filter | Pexels photos | Pexels videos | Pixabay photos | Pixabay videos |
|---|---|---|---|---|
searchPhotos / searchVideos | ✅ | ✅ | ✅ | ✅ |
getPhoto / getVideo | ✅ | ✅ | ✅ | ✅ |
curatedPhotos | ✅ | — | ❌ | — |
trackView / trackDownload | ✅ | ✅ | ✅ | ✅ |
orientation filter | ✅ | ✅ | ✅ | ❌ |
size filter | ✅ | ✅ | ❌ | ❌ |
color filter | ✅ | ❌ | ✅ | ❌ |
category filter | ❌ | ❌ | ✅ | ✅ |
minWidth / minHeight | ❌ | ❌ | ✅ | ✅ |
editorsChoice | ❌ | ❌ | ✅ | ✅ |
locale filter | ✅ | ✅ | ✅ | ❌ |
Use getCapabilities to read this matrix at runtime instead of hardcoding provider names.
For multi-provider setup (env vars, createMediaClient, runtime swap), see Provider configuration.
Authentication
import { ApiKeyProvider, PexelsMediaClient } from "@media-sdk/core";
const client = new PexelsMediaClient(
new ApiKeyProvider(process.env.PEXELS_API_KEY!),
);import { ApiKeyProvider, PixabayMediaClient } from "@media-sdk/core";
const client = new PixabayMediaClient(
new ApiKeyProvider(process.env.PIXABAY_API_KEY!),
);Both clients accept the same ApiKeyProvider type. Wire formatting is internal to each client.
Pagination differences
Both providers return the same normalized Pagination shape, but behavior diverges:
| Field | Pexels | Pixabay |
|---|---|---|
hasNext / hasPrevious | Derived from next_page / prev_page URLs | Computed from page * perPage < totalHits |
nextPage / prevPage | Populated with raw API URLs | Always undefined |
| Recommended navigation | page ± 1 (URLs optional) | page ± 1 only |
// Works for both providers — prefer page numbers
if (pagination.hasNext) {
await client.searchPhotos({
query,
page: pagination.page + 1,
perPage: pagination.perPage,
});
}When to pick each provider
Choose Pexels when you need:
- Curated photo feeds (
getCuratedPhotos) sizefilter on photos or videosorientationfilter on videoslocaleon video search
Choose Pixabay when you need:
category,minWidth,minHeight, oreditorsChoicefilters- A second catalog without maintaining separate integration code
- Photo search with dimension constraints
Use both when you want runtime provider switching. Instantiate clients directly — there is no ProviderFactory in v0.3.x:
import {
ApiKeyProvider,
PexelsMediaClient,
PixabayMediaClient,
type MediaClient,
} from "@media-sdk/core";
type ProviderName = "pexels" | "pixabay";
function createClient(
provider: ProviderName,
apiKey: string,
): MediaClient {
const auth = new ApiKeyProvider(apiKey);
switch (provider) {
case "pexels":
return new PexelsMediaClient(auth);
case "pixabay":
return new PixabayMediaClient(auth);
}
}Capability-driven UI (required pattern)
Gate features with capabilities, not provider identity strings.
Anti-pattern: provider-string branching
// ❌ Do not gate UI features on provider name
if (provider === "pexels") {
showCuratedTab();
}
if (selectedProvider === "pixabay") {
hideSizeFilter();
}Provider names may appear in a selector label or env-setup copy. They must not drive feature visibility.
Correct pattern: capabilities
import { getCapabilities, type MediaClient } from "@media-sdk/core";
function buildFilterUI(client: MediaClient) {
const caps = getCapabilities(client);
return {
showCurated: caps.operations.curatedPhotos,
showSizeFilter: caps.photoFilters.size,
showCategoryFilter: caps.photoFilters.category,
showOrientationFilter: caps.photoFilters.orientation,
};
}import { useMediaCapabilities } from "@media-sdk/react";
function SearchFilters() {
const caps = useMediaCapabilities();
return (
<>
{caps.operations.curatedPhotos && <CuratedTab />}
{caps.photoFilters.size && <SizeFilter />}
{caps.photoFilters.category && <CategoryFilter />}
{caps.photoFilters.orientation && <OrientationFilter />}
</>
);
}See Capabilities for the full MediaCapabilities type and React cross-link.
Error behavior
| Scenario | Error |
|---|---|
| Curated on Pixabay | UNSUPPORTED_CAPABILITY |
| Unsupported filter for provider | UNSUPPORTED_FILTER |
| Invalid filter enum value | INVALID_FILTER_VALUE |
Filters are never silently ignored. See Errors.
Related pages
- Provider configuration —
createMediaClient, env vars, runtime swap - PexelsMediaClient
- PixabayMediaClient
- MediaClient
- Filters