AI-Powered Search
Discover assets using natural language and semantic understanding with Playbook's AI Search.
Overview
AI Search goes beyond keyword matching to understand the meaning and context of your queries. Instead of exact text matches, AI Search finds assets based on visual similarity, concept understanding, and semantic relevance.
AI Search vs. Regular Search
| Feature | Regular Search | AI Search |
|---|---|---|
| Method | Text/keyword matching | Semantic understanding |
| Query Style | Exact terms | Natural language |
| Results | Title/tag matches | Concept-based matches |
| Visual Understanding | No | Yes |
| Best For | Known filenames | Exploring, discovering |
Prerequisites
- Access Token: OAuth2 token with search permissions
- Organization Slug: Your organization identifier
- AI Search Access: Feature must be enabled for your organization
Basic AI Search
Simple Query
curl "https://api.playbook.com/v1/my-org/ai_search?access_token=TOKEN&query=sunset+beach+photos"
Response:
{
"data": [
{
"id": 301,
"token": "coastal-sunset",
"title": "Golden Hour Coast",
"media_type": "image/jpeg",
"display_url": "https://cdn.playbook.com/coastal-sunset.jpg"
},
{
"id": 302,
"token": "beach-evening",
"title": "Evening Beach Walk",
"media_type": "image/jpeg",
"display_url": "https://cdn.playbook.com/beach-evening.jpg"
}
],
"pagy": {
"after_cursor": "eyJpZCI6MzAyLCJzY29yZSI6MC44NX0="
}
}
Natural Language Queries
AI Search understands natural language - ask questions the way you'd ask a person:
# Find conceptually related assets
"images that would work well for a summer campaign"
# Describe what you're looking for
"product photos with white background and good lighting"
# Ask for specific moods or styles
"minimalist designs with lots of negative space"
# Find by use case
"images suitable for social media headers"
Advanced Queries
Combining Concepts
# Multiple concepts
curl "https://api.playbook.com/v1/my-org/ai_search?access_token=TOKEN&query=professional+headshot+bright+background+smiling"
Filtering AI Search Results
Combine AI search with traditional filters for precision:
curl "https://api.playbook.com/v1/my-org/ai_search?access_token=TOKEN&query=modern+workspace&filters[media_type]=image/jpeg&filters[boards][]=office-photos"
Available Filters:
{
"filters": {
"media_type": "image/jpeg",
"boards": ["board-token-1", "board-token-2"],
"title": "contains-this-text",
"tags": ["approved", "branding"],
"tags_op": "and"
}
}
Pagination
AI Search uses cursor-based pagination for optimal performance.
First Page
curl "https://api.playbook.com/v1/my-org/ai_search?access_token=TOKEN&query=product+photography"
Next Page
Use the after_cursor from the previous response:
curl "https://api.playbook.com/v1/my-org/ai_search?access_token=TOKEN&query=product+photography&after_cursor=eyJpZCI6MzAyLCJzY29yZSI6MC44NX0="
JavaScript Example
async function searchAllPages(query) {
const allResults = [];
let cursor = null;
while (true) {
const params = new URLSearchParams({
access_token: ACCESS_TOKEN,
query: query
});
if (cursor) {
params.append('after_cursor', cursor);
}
const response = await fetch(
`https://api.playbook.com/v1/my-org/ai_search?${params}`
);
const { data, pagy } = await response.json();
allResults.push(...data);
if (!pagy.after_cursor) break;
cursor = pagy.after_cursor;
}
return allResults;
}
Refinement with Parent Queries
Use parent queries to refine and narrow down search results:
Initial Search
curl "https://api.playbook.com/v1/my-org/ai_search?access_token=TOKEN&query=office+interior"
Save the search result token or ID as parent_id.
Refined Search
curl "https://api.playbook.com/v1/my-org/ai_search?access_token=TOKEN&query=modern+minimalist&parent_id=search-token-123"
This narrows down the "office interior" results to only modern minimalist styles.
Use Cases
1. Visual Discovery
Find assets based on visual characteristics:
# By color palette
"images with warm autumn colors"
# By composition
"photos with central subject and blurred background"
# By style
"illustrations with flat design aesthetic"
2. Conceptual Search
Search by abstract concepts:
"assets that convey trust and professionalism"
"images that feel energetic and dynamic"
"designs with a vintage feel"
3. Smart Asset Discovery
Help users find assets they didn't know how to describe:
// User interface example
async function smartAssetFinder(userDescription) {
const response = await fetch(
`https://api.playbook.com/v1/${ORG_SLUG}/ai_search`,
{
method: 'GET',
headers: {
'Authorization': `Bearer ${ACCESS_TOKEN}`
},
params: {
query: userDescription,
filters: {
media_type: 'image/*',
tags: ['approved']
}
}
}
);
return await response.json();
}
// Usage
const results = await smartAssetFinder(
"bright cheerful images for kids product page"
);
4. Content Recommendations
Build "similar assets" features:
async function findSimilarAssets(assetToken) {
// First, get the asset details
const asset = await fetch(
`https://api.playbook.com/v1/${ORG_SLUG}/assets/${assetToken}?access_token=${ACCESS_TOKEN}`
).then(r => r.json());
// Use AI search with asset characteristics
const query = `${asset.data.title} ${asset.data.tags.join(' ')}`;
const similar = await fetch(
`https://api.playbook.com/v1/${ORG_SLUG}/ai_search?access_token=${ACCESS_TOKEN}&query=${encodeURIComponent(query)}`
).then(r => r.json());
// Filter out the original asset
return similar.data.filter(a => a.token !== assetToken);
}
Best Practices
1. Query Construction
Good Queries:
✅ "professional product photos with white background"
✅ "landscape images with mountains and blue sky"
✅ "minimalist logo designs in monochrome"
Less Effective:
❌ "good images" (too vague)
❌ "IMG_1234.jpg" (use regular search for filenames)
❌ "red" (too generic, be more specific)
2. Combining Search Types
Use AI Search for discovery, then refine with regular search:
async function hybridSearch(concept, exactTags) {
// Start with AI search for concept
const aiResults = await fetch(
`https://api.playbook.com/v1/${ORG_SLUG}/ai_search?access_token=${ACCESS_TOKEN}&query=${concept}`
).then(r => r.json());
// Filter by exact tags
const filtered = aiResults.data.filter(asset =>
exactTags.every(tag => asset.tags.includes(tag))
);
return filtered;
}
// Usage
const results = await hybridSearch(
"corporate headshots with natural lighting",
["approved", "2024"]
);
3. Performance Optimization
Cache Common Searches:
const searchCache = new Map();
async function cachedAISearch(query, ttl = 3600000) {
const cacheKey = `ai_search:${query}`;
if (searchCache.has(cacheKey)) {
const cached = searchCache.get(cacheKey);
if (Date.now() - cached.timestamp < ttl) {
return cached.data;
}
}
const response = await fetch(
`https://api.playbook.com/v1/${ORG_SLUG}/ai_search?access_token=${ACCESS_TOKEN}&query=${encodeURIComponent(query)}`
);
const data = await response.json();
searchCache.set(cacheKey, {
data,
timestamp: Date.now()
});
return data;
}
4. User Experience Tips
Provide Search Suggestions:
const searchSuggestions = [
"Product photos with clean backgrounds",
"Team photos in office settings",
"Lifestyle images with natural lighting",
"Brand assets in primary colors"
];
function showSearchHints() {
return searchSuggestions.map(suggestion => ({
label: suggestion,
onClick: () => performAISearch(suggestion)
}));
}
Complete Implementation Example
Here's a full search interface implementation:
class PlaybookAISearch {
constructor(orgSlug, accessToken) {
this.orgSlug = orgSlug;
this.accessToken = accessToken;
this.baseUrl = 'https://api.playbook.com/v1';
}
async search(query, options = {}) {
const params = new URLSearchParams({
access_token: this.accessToken,
query: query
});
// Add filters if provided
if (options.filters) {
if (options.filters.media_type) {
params.append('filters[media_type]', options.filters.media_type);
}
if (options.filters.boards) {
options.filters.boards.forEach(board => {
params.append('filters[boards][]', board);
});
}
if (options.filters.tags) {
options.filters.tags.forEach(tag => {
params.append('filters[tags][]', tag);
});
}
}
// Add pagination cursor
if (options.after_cursor) {
params.append('after_cursor', options.after_cursor);
}
// Add parent query for refinement
if (options.parent_id) {
params.append('parent_id', options.parent_id);
}
const response = await fetch(
`${this.baseUrl}/${this.orgSlug}/ai_search?${params}`
);
if (!response.ok) {
throw new Error(`AI Search failed: ${response.statusText}`);
}
return await response.json();
}
async *searchStream(query, options = {}) {
let cursor = null;
while (true) {
const results = await this.search(query, {
...options,
after_cursor: cursor
});
yield results.data;
if (!results.pagy.after_cursor) break;
cursor = results.pagy.after_cursor;
}
}
async searchAll(query, options = {}) {
const allResults = [];
for await (const batch of this.searchStream(query, options)) {
allResults.push(...batch);
}
return allResults;
}
}
// Usage
const search = new PlaybookAISearch('my-org', 'your_token');
// Simple search
const results = await search.search("sunset beach photos");
// Filtered search
const filtered = await search.search("product photography", {
filters: {
media_type: "image/jpeg",
tags: ["approved", "2024"]
}
});
// Get all results across pages
const allResults = await search.searchAll("office interiors");
// Stream results for progressive loading
for await (const batch of search.searchStream("brand assets")) {
console.log(`Loaded ${batch.length} assets`);
displayAssets(batch);
}
Error Handling
Common Errors
401: Unauthenticated
{
"error": "Unauthenticated"
}
Solution: Check your access token is valid.
403: AI Search not available
{
"error": "AI Search is not available for your organization"
}
Solution: Contact support to enable AI Search for your plan.
400: Invalid query
{
"error": "Query parameter is required"
}
Solution: Ensure the query parameter is not empty.
Comparison: When to Use Each Search Type
Use Regular Search When:
- Searching for specific filenames
- Looking up assets by exact tags
- Filtering by board membership
- You know the exact terms used in titles
Use AI Search When:
- Exploring your asset library
- Searching by visual concepts
- Finding assets for specific use cases
- Looking for aesthetically similar assets
- Users describe what they want in natural language
Use Both Together:
async function comprehensiveSearch(query, tags) {
// Get AI search results
const aiResults = await aiSearch(query);
// Filter by exact tags
const filtered = aiResults.filter(asset =>
tags.every(tag => asset.tags.includes(tag))
);
return filtered;
}
Related API Endpoints
Next Steps
- Learn about Asset Management to organize search results
- Explore Custom Fields for additional filtering
- Read about Webhooks to automate workflows based on search results