Events
Events in @media-sdk/core represent user actions in your application — opening a preview, starting a download — not API traffic. Search and fetch methods do not emit events; you call trackView and trackDownload explicitly from your UI layer.
Installation
pnpm add @media-sdk/core@^0.3.0User-action model
| API method | Emits events? |
|---|---|
searchPhotos / searchVideos | No — fetch only |
getPhoto / getVideo | No — fetch only |
getCuratedPhotos | No — fetch only |
trackView | Yes — emits "media:view" |
trackDownload | Yes — emits "media:download" |
Wire analytics, logging, or provider attribution in event listeners — not inside search hooks.
Event types
type MediaType = "photo" | "video";
interface MediaViewEvent {
mediaId: number;
mediaType: MediaType;
}
interface MediaDownloadEvent {
mediaId: number;
mediaType: MediaType;
}
interface MediaEventMap {
"media:view": MediaViewEvent;
"media:download": MediaDownloadEvent;
}Subscribing with on()
on(eventName, listener) returns an unsubscribe function. Multiple listeners per event are supported:
import { ApiKeyProvider, PexelsMediaClient } from "@media-sdk/core";
const client = new PexelsMediaClient(
new ApiKeyProvider(process.env.PEXELS_API_KEY!),
);
const unsubscribeView = client.on("media:view", (event) => {
console.log("Viewed", event.mediaType, event.mediaId);
});
const unsubscribeDownload = client.on("media:download", (event) => {
console.log("Downloaded", event.mediaType, event.mediaId);
});
// Later — remove listeners
unsubscribeView();
unsubscribeDownload();trackView and trackDownload
Call these from UI handlers when the user performs the action:
import type { MediaClient } from "@media-sdk/core";
async function openPhotoPreview(
client: MediaClient,
photoId: number,
) {
const photo = await client.getPhoto(photoId);
client.trackView({
mediaId: photo.id,
mediaType: "photo",
});
return photo;
}import type { MediaClient } from "@media-sdk/core";
function handleDownload(
client: MediaClient,
videoId: number,
) {
client.trackDownload({
mediaId: videoId,
mediaType: "video",
});
// then trigger your download UI / link
}trackView and trackDownload are synchronous — they emit to local listeners only. They do not call provider analytics endpoints unless you add that in a listener.
Analytics example
Forward events to your analytics pipeline:
import type { MediaClient } from "@media-sdk/core";
function attachAnalytics(client: MediaClient) {
const offView = client.on("media:view", (event) => {
analytics.track("media_view", {
media_id: event.mediaId,
media_type: event.mediaType,
});
});
const offDownload = client.on("media:download", (event) => {
analytics.track("media_download", {
media_id: event.mediaId,
media_type: event.mediaType,
});
});
return () => {
offView();
offDownload();
};
}
const detach = attachAnalytics(client);
// detach() on cleanupPreview-open flow (end-to-end)
import {
ApiKeyProvider,
PexelsMediaClient,
type Photo,
} from "@media-sdk/core";
const client = new PexelsMediaClient(
new ApiKeyProvider(process.env.PEXELS_API_KEY!),
);
client.on("media:view", ({ mediaId, mediaType }) => {
console.log(`[analytics] ${mediaType} ${mediaId} opened`);
});
async function showPreview(photoId: number): Promise<Photo> {
const photo = await client.getPhoto(photoId);
client.trackView({
mediaId: photo.id,
mediaType: "photo",
});
return photo;
}
const preview = await showPreview(12345);
console.log(preview.src.medium);Capabilities
Both built-in providers support event tracking:
import { getCapabilities } from "@media-sdk/core";
const caps = getCapabilities(client);
// caps.operations.trackView === true
// caps.operations.trackDownload === trueFuture metadata (not shipped)
Event payloads today carry only mediaId and mediaType. A proposed v2 schema (provider, optional metadata bag) is documented in Analytics design — design only; no breaking changes in 0.3.x.
Related pages
- Analytics design — proposed v2 event fields (design only)
- MediaClient —
on,trackView,trackDownload - Capabilities —
trackView/trackDownloadflags - Errors — fetch errors vs event emission