Pagination
Search and curated methods return a PaginatedResponse<T> with normalized items and pagination fields. Both Pexels and Pixabay share the same pagination shape so your navigation logic stays provider-neutral.
Installation
pnpm add @media-sdk/core@^0.3.0PaginatedResponse
interface PaginatedResponse<T> {
items: T[];
pagination: Pagination;
}searchPhotos, searchVideos, and getCuratedPhotos all return this type.
Pagination shape
interface Pagination {
page: number;
perPage: number;
totalResults?: number;
hasNext: boolean;
hasPrevious: boolean;
nextPage?: string;
prevPage?: string;
}| Field | Type | Description |
|---|---|---|
page | number | Current page number |
perPage | number | Items per page |
totalResults | number? | Total matching results (when provider reports it) |
hasNext | boolean | Whether a next page exists |
hasPrevious | boolean | Whether a previous page exists |
nextPage | string? | Raw Pexels next-page URL (optional) |
prevPage | string? | Raw Pexels previous-page URL (optional) |
Use hasNext / hasPrevious for navigation logic. The URL fields are preserved for advanced use cases but are not required for page-based navigation.
Page-based navigation
This pattern works for both providers:
import { ApiKeyProvider, PexelsMediaClient } from "@media-sdk/core";
const client = new PexelsMediaClient(
new ApiKeyProvider(process.env.PEXELS_API_KEY!),
);
const query = "nature";
const perPage = 20;
let page = 1;
const first = await client.searchPhotos({ query, page, perPage });
console.log(first.items);
if (first.pagination.hasNext) {
const second = await client.searchPhotos({
query,
page: first.pagination.page + 1,
perPage: first.pagination.perPage,
});
console.log(second.items);
}
if (first.pagination.hasPrevious) {
// page 1 has no previous page — hasPrevious is false
}Stateful pagination helper
import type { MediaClient, Photo, PaginatedResponse } from "@media-sdk/core";
async function fetchPage(
client: MediaClient,
query: string,
page: number,
perPage = 20,
): Promise<PaginatedResponse<Photo>> {
return client.searchPhotos({ query, page, perPage });
}
async function fetchAllPages(
client: MediaClient,
query: string,
maxPages = 3,
): Promise<Photo[]> {
const photos: Photo[] = [];
let page = 1;
let hasNext = true;
while (hasNext && page <= maxPages) {
const result = await fetchPage(client, query, page);
photos.push(...result.items);
hasNext = result.pagination.hasNext;
page = result.pagination.page + 1;
}
return photos;
}Pexels vs Pixabay divergence
Both clients normalize to the same Pagination interface, but the providers compute fields differently:
| Behavior | Pexels | Pixabay |
|---|---|---|
hasNext | Boolean(next_page URL) | page * perPage < totalHits |
hasPrevious | Boolean(prev_page URL) | page > 1 |
nextPage / prevPage | Populated from API | Always undefined |
totalResults | From total_results | From totalHits |
| Recommended navigation | page ± 1 | page ± 1 |
const { pagination } = await pexels.searchPhotos({
query: "nature",
page: 1,
perPage: 20,
});
console.log(pagination.nextPage); // "https://api.pexels.com/v1/search?..."
console.log(pagination.hasNext); // trueconst { pagination } = await pixabay.searchPhotos({
query: "nature",
page: 1,
perPage: 20,
});
console.log(pagination.nextPage); // undefined
console.log(pagination.hasNext); // true when more results existPrefer incrementing page over following raw URLs — that keeps code portable across providers.
Curated pagination
getCuratedPhotos uses the same Pagination shape (Pexels only):
import { getCapabilities } from "@media-sdk/core";
if (getCapabilities(client).operations.curatedPhotos) {
const { items, pagination } = await client.getCuratedPhotos({
page: 2,
perPage: 15,
});
if (pagination.hasNext) {
await client.getCuratedPhotos({
page: pagination.page + 1,
perPage: pagination.perPage,
});
}
}React hooks
useMediaSearch and useMediaVideos from @media-sdk/react@^0.3.0 expose pagination from the latest response and re-fetch when page or perPage changes. See React hooks.
Related pages
- MediaClient —
SearchParams.page/perPage - Provider comparison — pagination behavioral differences
- Cancellation — abort when page changes mid-flight