Skip to main content

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.

FeatureRegular SearchAI Search
MethodText/keyword matchingSemantic understanding
Query StyleExact termsNatural language
ResultsTitle/tag matchesConcept-based matches
Visual UnderstandingNoYes
Best ForKnown filenamesExploring, discovering

Prerequisites

  • Access Token: OAuth2 token with search permissions
  • Organization Slug: Your organization identifier
  • AI Search Access: Feature must be enabled for your organization

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:

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.

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"

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;
}


Next Steps