Skip to content

search.search()

Performs comprehensive search across questions, answers, and articles with flexible options for query, pagination, and sorting.

async search(options: SearchOptions = {}): Promise<PaginatedSearchResults>
async query(query: string, options: Omit<SearchOptions, 'query'> = {}): Promise<PaginatedSearchResults>
async searchByRelevance(query: string, options: Omit<SearchOptions, 'query' | 'sort'> = {}): Promise<PaginatedSearchResults>
async searchByDate(query: string, options: Omit<SearchOptions, 'query' | 'sort'> = {}): Promise<PaginatedSearchResults>
async searchByActivity(query: string, options: Omit<SearchOptions, 'query' | 'sort'> = {}): Promise<PaginatedSearchResults>
async searchByVotes(query: string, options: Omit<SearchOptions, 'query' | 'sort'> = {}): Promise<PaginatedSearchResults>
ParameterTypeRequiredDescription
optionsSearchOptionsNoSearch configuration options
PropertyTypeRequiredDescription
querystringNoSearch query string
pagenumberNoPage number (defaults to 1)
pageSize15 | 30 | 50 | 100NoNumber of results per page (defaults to 15)
sortSearchSortParameterNoSort order: 'relevance', 'newest', 'active', or 'score'

Returns a Promise<PaginatedSearchResults> containing:

PropertyTypeDescription
totalCountnumberTotal number of results found
pageSizenumberNumber of results per page
pagenumberCurrent page number
totalPagesnumberTotal number of pages available
sortSearchSortParameterApplied sort order
itemsArray<QuestionSearchResultModel | AnswerSearchResultModel | ArticleSearchResultModel>Search results

Each result item contains a type field and type-specific properties:

PropertyTypeDescription
typestringAlways 'question'
questionIdnumberQuestion identifier
titlestringQuestion title
snippetstringContent preview
scorenumberQuestion score
answerCountnumberNumber of answers
hasAcceptedAnswerbooleanWhether question has accepted answer
viewCountnumberView count
tagsTagSummaryResponseModel[]Associated tags
ownerUserSummaryResponseModelQuestion author
creationDateDateCreation timestamp
webUrlstringDirect URL to question
PropertyTypeDescription
typestringAlways 'answer'
answerIdnumberAnswer identifier
parentQuestionIdnumberParent question ID
titlestringAnswer title (usually question title)
snippetstringAnswer content preview
scorenumberAnswer score
isAcceptedbooleanWhether answer is accepted
tagsTagSummaryResponseModel[]Question tags
ownerUserSummaryResponseModelAnswer author
creationDateDateCreation timestamp
webUrlstringDirect URL to answer
PropertyTypeDescription
typestringAlways 'article'
articleIdnumberArticle identifier
titlestringArticle title
snippetstringArticle content preview
scorenumberArticle score
viewCountnumberView count
articleTypeArticleTypeArticle category
readTimeInMinutesnumberEstimated reading time
tagsTagSummaryResponseModel[]Associated tags
ownerUserSummaryResponseModelArticle author
creationDateDateCreation timestamp
webUrlstringDirect URL to article
import { StackOverflowSDK } from '@stackoverflow/teams-sdk';
const sdk = new StackOverflowSDK({
accessToken: 'your-access-token',
baseUrl: 'https://[your-site].stackenterprise.co/api/v3'
});
// Simple search without query (returns recent content)
const allResults = await sdk.search.search();
console.log(`Found ${allResults.totalCount} total results`);
console.log(`Page ${allResults.page} of ${allResults.totalPages}`);
console.log(`Results per page: ${allResults.pageSize}`);
// Process mixed result types
allResults.items?.forEach(item => {
switch (item.type) {
case 'question':
console.log(`Q: ${item.title} (${item.answerCount} answers, score: ${item.score})`);
break;
case 'answer':
console.log(`A: ${item.title} (${item.isAccepted ? 'accepted' : 'not accepted'}, score: ${item.score})`);
break;
case 'article':
console.log(`Article: ${item.title} (${item.readTimeInMinutes} min read, score: ${item.score})`);
break;
}
});
// Using query() - requires query parameter
const queryResults = await sdk.search.query('typescript interfaces');
// Using sort-specific convenience methods
const relevantResults = await sdk.search.searchByRelevance('react hooks');
const newestResults = await sdk.search.searchByDate('docker deployment');
const activeResults = await sdk.search.searchByActivity('kubernetes monitoring');
const topResults = await sdk.search.searchByVotes('javascript async');
// All convenience methods accept the same options (except query/sort)
const recentWithOptions = await sdk.search.searchByDate('python pandas', {
pageSize: 50,
page: 2
});
console.log(`Found ${recentWithOptions.totalCount} results sorted by date`);
console.log(`Showing page ${recentWithOptions.page} with ${recentWithOptions.pageSize} results per page`);
async function searchWithOptions() {
const results = await sdk.search.search({
query: 'javascript async await',
page: 1,
pageSize: 30,
sort: 'relevance'
});
console.log(`Search: "${results.query}" - ${results.totalCount} results`);
console.log(`Sorted by: ${results.sort}`);
// Filter by result type
const questions = results.items?.filter(item => item.type === 'question') || [];
const answers = results.items?.filter(item => item.type === 'answer') || [];
const articles = results.items?.filter(item => item.type === 'article') || [];
console.log(`Found: ${questions.length} questions, ${answers.length} answers, ${articles.length} articles`);
// Show top questions
questions.slice(0, 5).forEach((q, index) => {
console.log(`${index + 1}. ${q.title}`);
console.log(` Score: ${q.score} | Answers: ${q.answerCount} | Views: ${q.viewCount}`);
console.log(` Tags: ${q.tags?.map(t => t.name).join(', ')}`);
console.log(` Snippet: ${q.snippet?.substring(0, 100)}...`);
console.log('');
});
return results;
}
const searchResults = await searchWithOptions();
async function analyzeSearchResults(query: string) {
const results = await sdk.search.search({
query,
pageSize: 100,
sort: 'relevance'
});
// Analyze result distribution
const analysis = {
query,
totalResults: results.totalCount || 0,
pagination: {
currentPage: results.page || 1,
totalPages: results.totalPages || 0,
pageSize: results.pageSize || 0
},
typeDistribution: {
questions: 0,
answers: 0,
articles: 0
},
scoreStats: {
highest: 0,
lowest: 0,
average: 0,
total: 0
},
engagement: {
totalViews: 0,
totalAnswers: 0,
acceptedAnswers: 0,
averageReadTime: 0
},
tags: new Map<string, number>(),
authors: new Map<string, number>()
};
// Process each result
results.items?.forEach(item => {
// Type distribution
if (item.type === 'question') {
analysis.typeDistribution.questions++;
analysis.engagement.totalViews += item.viewCount || 0;
analysis.engagement.totalAnswers += item.answerCount || 0;
if (item.hasAcceptedAnswer) {
analysis.engagement.acceptedAnswers++;
}
} else if (item.type === 'answer') {
analysis.typeDistribution.answers++;
if (item.isAccepted) {
analysis.engagement.acceptedAnswers++;
}
} else if (item.type === 'article') {
analysis.typeDistribution.articles++;
analysis.engagement.totalViews += item.viewCount || 0;
analysis.engagement.averageReadTime += item.readTimeInMinutes || 0;
}
// Score statistics
const score = item.score || 0;
analysis.scoreStats.total += score;
if (score > analysis.scoreStats.highest) analysis.scoreStats.highest = score;
if (score < analysis.scoreStats.lowest) analysis.scoreStats.lowest = score;
// Tag frequency
item.tags?.forEach(tag => {
const current = analysis.tags.get(tag.name) || 0;
analysis.tags.set(tag.name, current + 1);
});
// Author frequency
if (item.owner?.displayName) {
const current = analysis.authors.get(item.owner.displayName) || 0;
analysis.authors.set(item.owner.displayName, current + 1);
}
});
// Calculate averages
const itemCount = results.items?.length || 0;
if (itemCount > 0) {
analysis.scoreStats.average = analysis.scoreStats.total / itemCount;
if (analysis.typeDistribution.articles > 0) {
analysis.engagement.averageReadTime = analysis.engagement.averageReadTime / analysis.typeDistribution.articles;
}
}
// Generate report
console.log(`\n=== Search Analysis: "${query}" ===`);
console.log(`Total Results: ${analysis.totalResults} (showing ${itemCount} on page ${analysis.pagination.currentPage})`);
console.log('\nContent Distribution:');
console.log(`- Questions: ${analysis.typeDistribution.questions} (${((analysis.typeDistribution.questions / itemCount) * 100).toFixed(1)}%)`);
console.log(`- Answers: ${analysis.typeDistribution.answers} (${((analysis.typeDistribution.answers / itemCount) * 100).toFixed(1)}%)`);
console.log(`- Articles: ${analysis.typeDistribution.articles} (${((analysis.typeDistribution.articles / itemCount) * 100).toFixed(1)}%)`);
console.log('\nScore Statistics:');
console.log(`- Highest: ${analysis.scoreStats.highest}`);
console.log(`- Lowest: ${analysis.scoreStats.lowest}`);
console.log(`- Average: ${analysis.scoreStats.average.toFixed(2)}`);
console.log('\nEngagement Metrics:');
console.log(`- Total Views: ${analysis.engagement.totalViews.toLocaleString()}`);
console.log(`- Total Answers: ${analysis.engagement.totalAnswers}`);
console.log(`- Accepted Answers: ${analysis.engagement.acceptedAnswers}`);
if (analysis.engagement.averageReadTime > 0) {
console.log(`- Average Read Time: ${analysis.engagement.averageReadTime.toFixed(1)} minutes`);
}
// Top tags
const topTags = Array.from(analysis.tags.entries())
.sort(([,a], [,b]) => b - a)
.slice(0, 10);
if (topTags.length > 0) {
console.log('\nTop Tags:');
topTags.forEach(([tag, count]) => {
console.log(`- ${tag}: ${count} results`);
});
}
// Top authors
const topAuthors = Array.from(analysis.authors.entries())
.sort(([,a], [,b]) => b - a)
.slice(0, 5);
if (topAuthors.length > 0) {
console.log('\nTop Authors:');
topAuthors.forEach(([author, count]) => {
console.log(`- ${author}: ${count} results`);
});
}
return analysis;
}
const analysis = await analyzeSearchResults('react hooks useState');
async function searchAllPages(query: string, maxPages: number = 5) {
const allResults = [];
let currentPage = 1;
let hasMorePages = true;
console.log(`Starting comprehensive search for: "${query}"`);
while (hasMorePages && currentPage <= maxPages) {
try {
console.log(`Loading page ${currentPage}...`);
const pageResults = await sdk.search.search({
query,
page: currentPage,
pageSize: 50,
sort: 'relevance'
});
if (pageResults.items && pageResults.items.length > 0) {
allResults.push(...pageResults.items);
console.log(`Page ${currentPage}: Found ${pageResults.items.length} results`);
console.log(`Total so far: ${allResults.length} of ${pageResults.totalCount} results`);
// Check if there are more pages
hasMorePages = currentPage < (pageResults.totalPages || 0);
currentPage++;
// Add delay to avoid rate limiting
if (hasMorePages && currentPage <= maxPages) {
await new Promise(resolve => setTimeout(resolve, 1000));
}
} else {
hasMorePages = false;
}
} catch (error) {
console.error(`Failed to load page ${currentPage}:`, error.message);
hasMorePages = false;
}
}
console.log(`\nCompleted search: Collected ${allResults.length} total results across ${currentPage - 1} pages`);
return allResults;
}
const comprehensiveResults = await searchAllPages('typescript generics', 3);
// Process all collected results
const questionResults = comprehensiveResults.filter(item => item.type === 'question');
const highScoreResults = comprehensiveResults.filter(item => (item.score || 0) > 5);
console.log(`Found ${questionResults.length} questions with high scores: ${highScoreResults.length}`);
async function processSearchResults(query: string) {
const results = await sdk.search.search({
query,
pageSize: 50,
sort: 'relevance'
});
// Type-safe result processing
const processedResults = {
questions: [],
answers: [],
articles: [],
summary: {
totalFound: results.totalCount || 0,
processingDate: new Date().toISOString(),
query
}
};
results.items?.forEach(item => {
const baseInfo = {
id: null,
title: item.title || '',
snippet: item.snippet || '',
score: item.score || 0,
author: item.owner?.displayName || 'Unknown',
created: item.creationDate,
url: item.webUrl || '',
tags: item.tags?.map(t => t.name) || []
};
switch (item.type) {
case 'question':
processedResults.questions.push({
...baseInfo,
id: item.questionId,
answerCount: item.answerCount || 0,
viewCount: item.viewCount || 0,
hasAcceptedAnswer: item.hasAcceptedAnswer || false,
type: 'question'
});
break;
case 'answer':
processedResults.answers.push({
...baseInfo,
id: item.answerId,
parentQuestionId: item.parentQuestionId,
isAccepted: item.isAccepted || false,
type: 'answer'
});
break;
case 'article':
processedResults.articles.push({
...baseInfo,
id: item.articleId,
viewCount: item.viewCount || 0,
readTimeMinutes: item.readTimeInMinutes || 0,
articleType: item.articleType,
type: 'article'
});
break;
}
});
console.log(`Processed ${processedResults.questions.length} questions, ${processedResults.answers.length} answers, ${processedResults.articles.length} articles`);
// Sort each type by score
processedResults.questions.sort((a, b) => b.score - a.score);
processedResults.answers.sort((a, b) => b.score - a.score);
processedResults.articles.sort((a, b) => b.score - a.score);
return processedResults;
}
const processed = await processSearchResults('kubernetes monitoring');
// Use processed results
console.log('Top Questions:');
processed.questions.slice(0, 3).forEach(q => {
console.log(`- ${q.title} (Score: ${q.score}, ${q.answerCount} answers)`);
});
console.log('\nTop Articles:');
processed.articles.slice(0, 3).forEach(a => {
console.log(`- ${a.title} (${a.readTimeMinutes} min read, Score: ${a.score})`);
});
async function monitorSearchPerformance(query: string, iterations: number = 5) {
console.log(`Monitoring search performance for: "${query}" (${iterations} iterations)`);
const results = [];
for (let i = 1; i <= iterations; i++) {
const startTime = Date.now();
try {
const searchResults = await sdk.search.search({
query,
pageSize: 30,
sort: 'relevance'
});
const endTime = Date.now();
const duration = endTime - startTime;
const iterationResult = {
iteration: i,
duration,
totalResults: searchResults.totalCount || 0,
returnedResults: searchResults.items?.length || 0,
success: true,
timestamp: new Date().toISOString()
};
results.push(iterationResult);
console.log(`Iteration ${i}: ${duration}ms - ${iterationResult.returnedResults}/${iterationResult.totalResults} results`);
// Add delay between requests
if (i < iterations) {
await new Promise(resolve => setTimeout(resolve, 2000));
}
} catch (error) {
const endTime = Date.now();
const duration = endTime - startTime;
results.push({
iteration: i,
duration,
totalResults: 0,
returnedResults: 0,
success: false,
error: error.message,
timestamp: new Date().toISOString()
});
console.error(`Iteration ${i} failed after ${duration}ms:`, error.message);
}
}
// Calculate statistics
const successfulResults = results.filter(r => r.success);
const avgDuration = successfulResults.reduce((sum, r) => sum + r.duration, 0) / successfulResults.length;
const minDuration = Math.min(...successfulResults.map(r => r.duration));
const maxDuration = Math.max(...successfulResults.map(r => r.duration));
console.log(`\n=== Performance Summary ===`);
console.log(`Successful requests: ${successfulResults.length}/${iterations}`);
console.log(`Average response time: ${avgDuration.toFixed(2)}ms`);
console.log(`Fastest response: ${minDuration}ms`);
console.log(`Slowest response: ${maxDuration}ms`);
return {
query,
iterations,
results,
stats: {
successRate: (successfulResults.length / iterations) * 100,
avgDuration,
minDuration,
maxDuration
}
};
}
const performanceResults = await monitorSearchPerformance('api integration', 5);

This method can throw the following errors:

Error TypeStatus CodeDescription
AuthenticationError401Invalid or missing authentication token
TokenExpiredError401Authentication token has expired
ForbiddenError403Insufficient permissions for search operation
ValidationError400Invalid search parameters or query format
SDKErrorVariousOther API or network errors
import StackOverflowSDK, { ValidationError, ForbiddenError, AuthenticationError } from '@stackoverflow/teams-sdk';
const sdk = new StackOverflowSDK({
accessToken: 'your-access-token',
baseUrl: 'https://[your-site].stackenterprise.co/api/v3'
});
try {
const results = await sdk.search.search({
query: 'javascript promises',
pageSize: 50
});
console.log(`Search completed: ${results.totalCount} results found`);
} catch (error) {
if (error instanceof ValidationError) {
console.error('Invalid search parameters - check query format and options');
} else if (error instanceof ForbiddenError) {
console.error('Cannot perform search - insufficient permissions');
} else if (error instanceof AuthenticationError) {
console.error('Authentication required for search operation');
} else {
console.error('Search failed:', error.message);
}
}
async function safeSearch(query: string, maxRetries: number = 3): Promise<PaginatedSearchResults | null> {
let lastError;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
console.log(`Search attempt ${attempt}/${maxRetries} for: "${query}"`);
const results = await sdk.search.search({
query,
pageSize: 30,
sort: 'relevance'
});
console.log(`Search successful on attempt ${attempt}`);
return results;
} catch (error) {
lastError = error;
console.warn(`Attempt ${attempt} failed:`, error.message);
// Don't retry on certain error types
if (error instanceof ValidationError || error instanceof ForbiddenError) {
console.error('Non-retryable error encountered');
break;
}
// Wait before retry (exponential backoff)
if (attempt < maxRetries) {
const delay = Math.pow(2, attempt) * 1000;
console.log(`Waiting ${delay}ms before retry...`);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
console.error(`Search failed after ${maxRetries} attempts:`, lastError?.message);
return null;
}
const results = await safeSearch('docker containers', 3);
if (results) {
console.log(`Found ${results.totalCount} results`);
} else {
console.log('Search could not be completed');
}
  • Mixed Content Types: Search returns questions, answers, and articles in a single result set. Use the type field to differentiate.
  • Pagination: Results are paginated with comprehensive metadata. Use totalPages and current page to implement navigation.
  • Sorting Options: Four sort modes available - relevance (default), newest, active (most recent activity), and score (highest voted).
  • Query Flexibility: The query parameter is optional. Omitting it returns recent content across all types.
  • Performance: Search operations may take longer than single-item retrieval. Consider implementing caching for repeated queries.
  • Rate Limiting: Be mindful of API rate limits when performing multiple search operations or pagination loops.
  • Content Snippets: All result types include content previews in the snippet field for quick scanning.
  • Tag Inheritance: Answer results include tags from their parent questions for better searchability.