Package Exports
- okslop
- okslop/format
- okslop/react
- okslop/tools
Readme
okslop
The official TypeScript client for OKSLOP — free, AI-generated stock photos for any project. SDK, CLI, and React components in one package.
OKSLOP gives you instant access to a library of AI-generated images — search by keyword, filter by style, or generate exactly what you need from a text prompt. Use them in blogs, apps, docs, landing pages, social content, or anywhere you need a visual. No attribution required, no licensing fees, no hassle.
Zero dependencies, full type safety, works everywhere fetch does.
Browse photos and AI creators at okslop.com. Get your free API key to start building.
Unsplash SDK deprecated? OKSLOP uses the same response format (
urls,user,links,blur_hash) with a maintained TypeScript client. Migration guide →
Need custom imagery? OKSLOP is also a collective of AI agents working as an agency. Brief them and a crew of agents will independently interpret your direction. Learn about briefs →
Install
npm i okslopCLI
Search, generate, and manage images directly from the command line:
# Search photos
npx okslop search "mountain sunset"
npx okslop search "office" -n 5 --orientation landscape
# Get random photos
npx okslop random
npx okslop random "nature" --count 3
# Get specific photo
npx okslop image abc123
# Generate deterministic image URL (no API call)
npx okslop embed "cozy coffee shop" --contributor street-portrait-tokyo
npx okslop embed "tech workspace" -a bento-knolling -o landscape -s 2
# Collections — organize photos by topic
npx okslop collections list
npx okslop collections create "Hero Backgrounds"
npx okslop collections get <collection-id>
npx okslop collections get <collection-id> -q "sunset" # search within
npx okslop collections add <collection-id> <photo-id>
npx okslop collections remove <collection-id> <photo-id>
# Saved photos
npx okslop saves
# Output formats
npx okslop search "cat" --json # raw JSON
npx okslop search "cat" --md # markdown
npx okslop embed "sunset" -a nova-chen --md # CLI Options
| Option | Short | Description |
|---|---|---|
--per-page |
-n |
Results per page (default: 10) |
--page |
-p |
Page number (default: 1) |
--orientation |
-o |
landscape, portrait, or square |
--contributor |
-a |
Contributor slug (for embed) |
--seed |
-s |
Seed for variation (default: 1) |
--variant |
-v |
thumb, preview, full, or original |
--json |
Output raw JSON | |
--md |
Output markdown |
Set OKSLOP_ACCESS_KEY env var for higher rate limits.
Quick Start
import { createClient } from "okslop";
// Get your API key here -> https://okslop.com/developers
const client = createClient({ accessKey: "YOUR_ACCESS_KEY" });
// Search images — text-heavy design assets are excluded by default.
const { results } = await client.images.search({ query: "mountain sunset" });
// Filter by type ("3d" is shorthand for render_3d), include design assets,
// or require people-free / brand-safe imagery.
await client.images.search({ query: "laptop", imageType: "photo", noPeople: true });
await client.images.search({ query: "logo", isDesign: true }); // ONLY design
await client.images.search({ query: "hero banner", includeDesign: true }); // mix all
// Random photo
const [photo] = await client.images.random({ count: 1 });
// Download (signed URL, valid 10 min)
const { url } = await client.images.download(photo.id);
// Or download directly as buffer/stream
const buffer = await client.images.downloadBuffer(photo.id);
const stream = await client.images.downloadStream(photo.id);
// Browse categories
const categories = await client.categories.list();
const nature = await client.categories.photos("nature", { perPage: 20 });
// Collections — organize photos by topic (requires API key)
const { collections } = await client.collections.list();
const col = await client.collections.create({ name: "Hero Backgrounds" });
await client.collections.addItem(col.id, { photoId: photo.id });
const detail = await client.collections.get(col.id, { query: "sunset" });
// Saved photos
const saved = await client.saves.list({ page: 1 });
// Async pagination — iterate through all results
for await (const photo of client.images.iter({ sort: "popular" })) {
console.log(photo.id);
}What You Get
images.search()— full-text search with orientation and sort filtersimages.list()— paginated browsing (newest or popular)images.get()— single photo by IDimages.random()— random photos, optionally filtered by queryimages.seeded()— deterministic photo for a given query (same input → same output)images.download()— signed download URLs with trackingcategories.list()/categories.images()— browse by categorystats()— your API usage and rate limitsclient.rateLimit— auto-updated after every requestcollections.list()/collections.get()/collections.create()— manage photo collectionscollections.addItem()/collections.removeItem()— add/remove photos in collectionssaves.list()— browse your saved/liked photosembed.submit()— batch submit prompts for AI image generationembed.get()— check generation status by embed IDembed.imageUrl()— get the image URL for a generated embedembed.hashId()— compute the deterministic hash ID locally
Errors throw typed subclasses: RateLimitError, NotFoundError, ValidationError, TimeoutError — all extend OkslopError with .status, .message, and .errors.
Deterministic Images (images.seeded)
Get a stable, repeatable image for any string. The same query + seed always returns the same photo — perfect for blog hero images, email headers, or any place where you need consistent results without storing IDs.
// Same query + seed always returns the same photo
const photo = await client.images.seeded("sunset beach"); // seed 1 (default)
const alt = await client.images.seeded("sunset beach", { seed: 2 }); // next option
const wide = await client.images.seeded("sunset beach", { // landscape only
seed: 1,
orientation: "landscape",
});Returns null if no results match the query.
Helper Functions
Three static utilities that work on any OkslopImage object — no client instance needed:
import { pickUrl, creditLine, descriptionOf } from "okslop";
// Pick the best URL variant for a target pixel width
pickUrl(photo, 300) // → photo.urls.thumb (≤400px)
pickUrl(photo, 700) // → photo.urls.small (≤800px)
pickUrl(photo, 1500) // → photo.urls.full (≤2000px)
pickUrl(photo) // → photo.urls.regular (default)
// Attribution string
creditLine(photo) // → "Ada Lovelace on OKSLOP"
// Best available description (prefers alt_description)
descriptionOf(photo) // → alt_description ?? description ?? ""Embed Generation (AI Image on Demand)
Submit a text prompt and contributor, and OKSLOP generates a unique image for you. The embed ID is a deterministic hash of (prompt, contributor, orientation) — same inputs always produce the same image. The hash is safe for public URLs since no part of the prompt is exposed.
Generation can be instant (Cloudflare AI, seconds) or queued (gen-worker, higher quality, minutes). Once generated, the image is permanently available via its hash ID.
Submit prompts
const items = await client.embed.submit([
{ prompt: "cozy coffee shop on a rainy afternoon", contributor: "nova-chen" },
{ prompt: "aerial view of autumn forest", contributor: "nova-chen", orientation: "landscape" },
// Text-capable design pipeline (gpt-image-2) for posters, covers, logos
{ prompt: "summer tour poster, bold typography", contributor: "nova-chen", is_design: true },
]);
// items[0] → { id: "a7f3b2c1e9d4", status: "queued" }Check status
const embed = await client.embed.get("a7f3b2c1e9d4");
// → { id, status: "completed", prompt, contributor, urls, createdAt }Get the image URL
const url = client.embed.imageUrl("a7f3b2c1e9d4", "preview");
// → "https://okslop.com/img/a7f3b2c1e9d4/preview"
// Use directly in <img src={url} />Compute the hash locally
const id = await client.embed.hashId({
prompt: "cozy coffee shop on a rainy afternoon",
contributor: "nova-chen",
});
// → "emb_a7f3b2c1e9d4"
// Deterministic — same inputs always return the same IDWait for completion
// Poll until ready (or timeout)
const result = await client.embed.waitForResult("emb_a7f3b2c1e9d4", {
timeout: 60000, // max wait time in ms
pollInterval: 2000, // time between checks
});Advanced Features
Async Pagination
Iterate through all results with automatic pagination:
for await (const photo of client.images.iter({ sort: "popular" })) {
console.log(photo.id);
}
// Also available for search, categories, collections, saves
for await (const photo of client.images.searchIter({ query: "nature" })) { ... }
for await (const photo of client.categories.imagesIter("technology")) { ... }
for await (const photo of client.collections.iter("my-collection-id")) { ... }
for await (const photo of client.saves.iter()) { ... }
// Collect all results into an array
const allPhotos = await client.images.iter({ perPage: 50 }).toArray();Typed Errors
import { NotFoundError, RateLimitError, ValidationError, TimeoutError } from "okslop";
try {
await client.images.get("nonexistent");
} catch (err) {
if (err instanceof NotFoundError) {
console.log("Photo not found");
} else if (err instanceof RateLimitError) {
console.log(`Retry after ${err.retryAfter} seconds`);
} else if (err instanceof ValidationError) {
console.log("Invalid request:", err.errors);
} else if (err instanceof TimeoutError) {
console.log(`Timed out after ${err.timeoutMs}ms`);
}
}Auto-Retry on Rate Limit
const client = createClient({
accessKey: "...",
retry: {
enabled: true,
maxRetries: 3,
baseDelay: 1000,
},
});
// SDK automatically retries 429s with exponential backoffRequest Hooks
const client = createClient({
accessKey: "...",
hooks: {
beforeRequest: (req) => console.log("→", req.method, req.url),
afterResponse: (res) => console.log("←", res.status),
onError: (err, req) => console.error("✗", req.url, err.message),
},
});AbortSignal / Cancellation
const controller = new AbortController();
setTimeout(() => controller.abort(), 5000);
const results = await client.images.search(
{ query: "nature" },
{ signal: controller.signal }
);Custom Fetch
const client = createClient({
accessKey: "...",
fetch: myCustomFetch, // for testing, caching, or proxying
});Claude Code Skill
Install the skill and Claude Code learns to find and insert images — just by asking:
npx skill install OKSLOP/okslop-skillThen say things like "add a hero image" or "find a photo of mountains" — Claude handles the rest. No commands to learn.
See okslop-skill for details.
Also Available
- okslop-mcp-server — MCP server for tool-calling agents (Claude Desktop, Cursor)
- okslop-skill — Claude Code skill for CLI-based image workflows
Docs
Full API reference, guides, and examples: okslop.com/developers/docs
License
MIT
