notion-search-retrieve
Search Notion workspaces and retrieve pages, databases, and block content using the Notion API. Use when querying databases with filters, searching across a workspace, paginating large result sets, or extracting page content. Trigger with phrases like "notion search", "query notion database", "notion retrieve page", "notion pagination", "notion filter", "notion blocks", "notion get content".
Best use case
notion-search-retrieve is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Search Notion workspaces and retrieve pages, databases, and block content using the Notion API. Use when querying databases with filters, searching across a workspace, paginating large result sets, or extracting page content. Trigger with phrases like "notion search", "query notion database", "notion retrieve page", "notion pagination", "notion filter", "notion blocks", "notion get content".
Teams using notion-search-retrieve should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/notion-search-retrieve/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How notion-search-retrieve Compares
| Feature / Agent | notion-search-retrieve | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Search Notion workspaces and retrieve pages, databases, and block content using the Notion API. Use when querying databases with filters, searching across a workspace, paginating large result sets, or extracting page content. Trigger with phrases like "notion search", "query notion database", "notion retrieve page", "notion pagination", "notion filter", "notion blocks", "notion get content".
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
Related Guides
ChatGPT vs Claude for Agent Skills
Compare ChatGPT and Claude for AI agent skills across coding, writing, research, and reusable workflow execution.
Best AI Skills for Claude
Explore the best AI skills for Claude and Claude Code across coding, research, workflow automation, documentation, and agent operations.
SKILL.md Source
# Notion Search & Data Retrieval
## Overview
Search across a Notion workspace, query databases with compound filters, retrieve individual pages, and extract nested block content. Covers the full read path: workspace-level search, database queries with filter/sort/pagination, page retrieval, and recursive block tree traversal.
## Prerequisites
- `@notionhq/client` installed (`npm install @notionhq/client`)
- Notion integration token with read access to target pages/databases
- Integration added to target pages via the Share menu in Notion
- Completed `notion-install-auth` setup
## Instructions
### Step 1: Search the Workspace
Call `notion.search()` to find pages and databases. The integration only sees content explicitly shared with it.
```typescript
import { Client } from '@notionhq/client';
const notion = new Client({ auth: process.env.NOTION_TOKEN });
// Search for pages matching a query
const searchResults = await notion.search({
query: 'meeting notes',
filter: {
property: 'object',
value: 'page', // 'page' or 'database'
},
sort: {
direction: 'descending',
timestamp: 'last_edited_time',
},
page_size: 20,
});
for (const result of searchResults.results) {
if (result.object === 'page' && 'properties' in result) {
const titleProp = Object.values(result.properties)
.find(p => p.type === 'title');
const title = titleProp?.type === 'title'
? titleProp.title.map(t => t.plain_text).join('')
: 'Untitled';
console.log(`${title} (${result.id})`);
}
}
```
An empty `query` string returns all shared content. Results are eventually consistent — newly shared pages may take a few seconds to appear in the index.
### Step 2: Query Databases with Filters
Call `notion.databases.query()` for structured queries. Filters support compound `and`/`or` logic. See [filter-operators.md](references/filter-operators.md) for every property type and operator.
```typescript
// Single filter
const activeItems = await notion.databases.query({
database_id: 'your-database-id',
filter: {
property: 'Status',
select: { equals: 'Active' },
},
sorts: [
{ property: 'Priority', direction: 'descending' },
],
page_size: 50,
});
// Compound filter with AND
const highPriorityActive = await notion.databases.query({
database_id: 'your-database-id',
filter: {
and: [
{ property: 'Status', select: { equals: 'Active' } },
{ property: 'Priority', number: { greater_than: 3 } },
],
},
});
```
### Step 3: Paginate, Retrieve Pages, and Extract Content
Notion uses cursor-based pagination. All list endpoints return `has_more` and `next_cursor`. Call `notion.pages.retrieve()` for a single page, then `notion.blocks.children.list()` to read its content recursively.
```typescript
import type {
PageObjectResponse,
BlockObjectResponse,
} from '@notionhq/client/build/src/api-endpoints';
// Paginate through all database results
async function queryAllPages(databaseId: string): Promise<PageObjectResponse[]> {
const pages: PageObjectResponse[] = [];
let cursor: string | undefined = undefined;
do {
const response = await notion.databases.query({
database_id: databaseId,
start_cursor: cursor,
page_size: 100,
});
for (const page of response.results) {
if ('properties' in page) {
pages.push(page as PageObjectResponse);
}
}
cursor = response.has_more ? response.next_cursor! : undefined;
} while (cursor);
return pages;
}
// Retrieve a single page and extract typed property values
async function getPage(pageId: string) {
const page = await notion.pages.retrieve({ page_id: pageId });
if (!('properties' in page)) throw new Error('Partial page object');
return page as PageObjectResponse;
}
function extractProperties(page: PageObjectResponse) {
const result: Record<string, any> = {};
for (const [name, prop] of Object.entries(page.properties)) {
switch (prop.type) {
case 'title':
result[name] = prop.title.map(t => t.plain_text).join(''); break;
case 'rich_text':
result[name] = prop.rich_text.map(t => t.plain_text).join(''); break;
case 'number': result[name] = prop.number; break;
case 'select': result[name] = prop.select?.name ?? null; break;
case 'multi_select':
result[name] = prop.multi_select.map(s => s.name); break;
case 'date':
result[name] = prop.date ? { start: prop.date.start, end: prop.date.end } : null; break;
case 'people':
result[name] = prop.people.map(p => ('name' in p ? p.name : p.id)); break;
case 'checkbox': result[name] = prop.checkbox; break;
case 'url': result[name] = prop.url; break;
case 'email': result[name] = prop.email; break;
case 'phone_number': result[name] = prop.phone_number; break;
case 'status': result[name] = prop.status?.name ?? null; break;
case 'relation': result[name] = prop.relation.map(r => r.id); break;
case 'formula': result[name] = prop.formula; break;
case 'rollup': result[name] = prop.rollup; break;
default: result[name] = `[${prop.type}]`;
}
}
return result;
}
// Recursively fetch all blocks (page content)
async function getPageContent(
blockId: string, depth = 0, maxDepth = 3
): Promise<BlockObjectResponse[]> {
const blocks: BlockObjectResponse[] = [];
let cursor: string | undefined = undefined;
do {
const response = await notion.blocks.children.list({
block_id: blockId,
start_cursor: cursor,
page_size: 100,
});
for (const block of response.results) {
if (!('type' in block)) continue;
const b = block as BlockObjectResponse;
blocks.push(b);
if (b.has_children && depth < maxDepth) {
blocks.push(...await getPageContent(b.id, depth + 1, maxDepth));
}
}
cursor = response.has_more ? response.next_cursor! : undefined;
} while (cursor);
return blocks;
}
function blockToText(block: BlockObjectResponse): string {
const content = (block as any)[block.type];
if (!content?.rich_text) return '';
return content.rich_text.map((t: any) => t.plain_text).join('');
}
```
## Output
- Workspace-wide search returning pages and databases sorted by recency
- Database queries with compound filters across all property types
- Full pagination collecting every matching result
- Typed property extraction for all 15 Notion property types
- Recursive block tree traversal yielding full page content
## Error Handling
| Issue | Cause | Solution |
|-------|-------|----------|
| Could not find database | Database not shared with integration | Open database in Notion, click Share, add the integration |
| Could not find page | Page not shared or deleted | Verify page is shared; check `archived` status |
| Empty search results | Integration not connected | Share parent page/database with integration; wait for indexing |
| validation_error on filter | Wrong operator for property type | Check [filter-operators.md](references/filter-operators.md) |
| HTTP 429 rate_limited | Too many requests | Back off using `Retry-After` header; use `page_size: 100` |
| Missing properties | Partial page object | Check `'properties' in page` before casting to `PageObjectResponse` |
| Incomplete page content | Not recursing child blocks | Check `has_children` and recurse; increase `maxDepth` |
## Examples
See [examples.md](references/examples.md) for complete patterns including database export, full-text page dump, and compound filter variations.
## Resources
- [Notion Search API](https://developers.notion.com/reference/post-search)
- [Query a Database](https://developers.notion.com/reference/post-database-query)
- [Retrieve a Page](https://developers.notion.com/reference/retrieve-a-page)
- [List Block Children](https://developers.notion.com/reference/get-block-children)
- [Filter Reference](https://developers.notion.com/reference/post-database-query-filter)
- [Property Values](https://developers.notion.com/reference/page-property-values)
- [@notionhq/client npm](https://www.npmjs.com/package/@notionhq/client)
## Next Steps
For creating and updating pages, see `notion-core-workflow-a`. For PII handling and GDPR compliance, see `notion-data-handling`. For real-time sync via webhooks, see `notion-webhooks-events`.Related Skills
creating-github-issues-from-web-research
Execute this skill enhances AI assistant's ability to conduct web research and translate findings into actionable github issues. it automates the process of extracting key information from web search results and formatting it into a well-structured issue, ready... Use when managing version control. Trigger with phrases like 'commit', 'branch', or 'git'.
search-to-slack
Takes web search results and formats them as polished Slack messages, digests, or thread summaries ready to post to channels. Use when the user wants to research a topic and share findings on Slack. Trigger with phrases like "research and post to Slack", "create a Slack digest", "summarize and share in #channel", or "format search results for Slack".
research-to-deploy
Researches infrastructure best practices and generates deployment-ready configurations, Terraform modules, Dockerfiles, and CI/CD pipelines. Use when the user needs to deploy services, set up infrastructure, or create cloud configurations based on current best practices. Trigger with phrases like "research and deploy", "set up Cloud Run", "create Terraform for", "deploy this to AWS", or "generate infrastructure configs".
notion-webhooks-events
Build change detection and event handling for Notion workspaces using polling, native webhooks, and third-party connectors. Use when implementing real-time sync, change feeds, incremental backup, or event-driven workflows with Notion data. Trigger with phrases like "notion webhook", "notion events", "notion change detection", "notion polling", "notion sync changes", "notion real-time", "notion watch for changes".
notion-upgrade-migration
Upgrade @notionhq/client SDK versions and migrate between Notion API versions. Use when updating SDK packages, handling breaking changes between API versions, adopting new SDK features like comments API or status properties, or migrating Python notion-client. Trigger with phrases like "upgrade notion SDK", "notion migration", "notion breaking changes", "update notionhq client", "notion API version upgrade", "notion deprecation".
notion-security-basics
Apply Notion API security best practices for integration tokens, OAuth2 flows, least-privilege capabilities, and page-level access control. Use when securing integration tokens, configuring OAuth2 for public integrations, rotating credentials, or auditing which pages an integration can access. Trigger with phrases like "notion security", "notion secrets", "secure notion", "notion API key security", "notion token rotation", "notion OAuth2", "notion permissions audit".
notion-sdk-patterns
Apply production-ready @notionhq/client SDK patterns for TypeScript and Python. Use when implementing Notion integrations, building database queries with filters and sorts, handling pagination, constructing rich text blocks, or establishing team coding standards for Notion API usage. Trigger with "notion SDK patterns", "notion best practices", "notion code patterns", "idiomatic notion", "notion typescript", "notion python SDK".
notion-reliability-patterns
Graceful degradation when Notion is down: offline cache, retry with exponential backoff, circuit breaker, health checks, and fallback content. Use when building fault-tolerant Notion integrations for production. Trigger with phrases like "notion reliability", "notion circuit breaker", "notion offline fallback", "notion health check", "notion graceful degradation".
notion-reference-architecture
Design and implement a production-ready Notion integration architecture with proper layering, caching, error handling, and testing strategies. Use when designing new Notion integrations, reviewing existing project structure, establishing architecture standards for Notion applications, or migrating from ad-hoc API calls to a layered architecture. Trigger: "notion architecture", "notion project structure", "notion reference architecture", "notion integration design", "notion layered architecture", "notion service pattern".
notion-rate-limits
Manage Notion API rate limits with exponential backoff, queue-based throttling, and batch optimization. Use when hitting 429 errors, implementing retry logic, or optimizing API request throughput for Notion integrations. Trigger with "notion rate limit", "notion 429", "notion retry", "notion backoff", "notion throttling", "notion too many requests", "notion queue".
notion-prod-checklist
Execute Notion API production deployment checklist and readiness verification. Use when deploying Notion integrations to production, preparing for launch, verifying go-live readiness, or auditing an existing Notion integration. Trigger: "notion production checklist", "deploy notion integration", "notion go-live", "notion launch readiness", "notion prod audit".
notion-policy-guardrails
Governance for Notion integrations: integration naming standards, page sharing policies, property naming conventions, database schema standards, and access audit scripts. Trigger with phrases like "notion governance", "notion policy", "notion naming convention", "notion access audit", "notion schema standard".