| name | aside-notion |
| description | Read this skill when you need to use Notion. Don't have to open a browser tab. |
| metadata | {"version":"0.1.0"} |
Notion
Use the notion global in the REPL tool. It extracts token_v2 from the logged-in Notion browser session — no tab navigation needed.
Quick Reference
console.log(await notion.listAccounts());
const _notion = await notion.getClient({
email: 'you@example.com',
workspaceName: 'Corca',
});
console.log(_notion.currentUser.email, _notion.currentUser.fullName);
console.log('Space:', _notion.currentSpace.get('name'));
console.log('Plan:', _notion.currentSpace.get('subscription_tier'));
const results = await _notion.search({ query: 'meeting notes', isNavigableOnly: true, limit: 10 });
for (const block of results) {
console.log(block.id, block.get('type'), block.title);
}
const page = await _notion.getBlock('https://www.notion.so/myorg/My-Page-abc123');
console.log(page.title);
console.log(blockToMarkdown(page));
await page.children.addFromMarkdown(`
## Agent update
- [x] searched the workspace
- [x] appended a section
`);
const child = await page.children.addNew('page', { title: 'New Sub-page' });
await child.children.addFromMarkdown('# Hello\n\nContent here.');
await page.set('properties.title', [['Updated Title']]);
Getting the Client
const _notion = await notion.getClient();
The returned client is NotionClient from @aside/notion — a full-featured Notion internal API client. All operations below use this client.
If the token expires or you switch accounts:
notion.invalidateCache();
const refreshedNotion = await notion.getClient();
Multi-account
The client initializes with the first user/workspace found. If the task depends on a specific account or workspace, list accounts first and pass explicit selectors to getClient.
const accounts = await notion.listAccounts();
console.log(accounts);
const client = await notion.getClient({
email: 'other@email.com',
workspaceName: 'Corca',
});
Search
const results = await _notion.search({ query: 'project plan', limit: 20 });
const pages = await _notion.search({
query: 'project',
isNavigableOnly: true,
excludeTemplates: true,
sort: { field: 'lastEdited' },
});
const childIds = await _notion.searchPagesWithParent(parentPageId, 'query');
Search results are Block[] — already cached, ready to mutate.
Read a Page
const page = await _notion.getBlock(pageIdOrUrl);
console.log(page.title);
console.log(page.get('type'));
for (const child of page.children) {
console.log(child.get('type'), child.title);
}
console.log(blockToMarkdown(page));
Write Content
Before creating pages or uploading files, verify the target workspace:
console.log(_notion.currentSpace.get('name'), _notion.currentSpace.get('subscription_tier'));
console.log(_notion.currentSpace.get('settings.reach_block_limit_time'));
If the current workspace is free or block-limited and the user asked for a subscribed/team workspace, switch to the correct workspace before writing.
Append blocks to a page
await page.children.addNew('text', { title: 'A paragraph' });
await page.children.addNew('to_do', { title: 'Ship it', checked: false });
await page.children.addNew('bulleted_list', { title: 'List item' });
Append markdown to a page
await page.children.addFromMarkdown(`
# Summary
- write docs
- [x] port search API
> keep the API minimal
\`\`\`ts
console.log('ship it')
\`\`\`
`);
Supported: headings, paragraphs, bullet/numbered lists, to-dos, quotes, code blocks, dividers, nested lists. Inline: bold, italic, strike, code, links, $$equations$$.
Create child pages
const parent = await _notion.getBlock(parentPageId);
const child = await parent.children.addNew('page', { title: 'Design Doc' });
await child.children.addFromMarkdown('# Goals\n\n- keep scope tight');
Update page title
await page.set('properties.title', [['New Title']]);
Batch writes (transaction)
await _notion.runInTransaction(async () => {
await page.set('properties.title', [['Updated']]);
await page.children.addNew('text', { title: 'Note 1' });
await page.children.addNew('text', { title: 'Note 2' });
});
Databases (Collections)
const view = await _notion.getCollectionView('https://www.notion.so/myorg/8511b9fc?v=8dee2a54');
const collection = view.collection;
const rows = await collection.getRows();
for (const row of rows.toArray()) {
console.log(await row.getProp('Name'), await row.getProp('Status'));
}
const newRow = await collection.addRow({
Name: 'New task',
Status: 'In Progress',
'Due Date': { start: new Date('2026-05-01') },
});
const query = view.buildQuery({
filter: {
filters: [{
property: 'Status',
filter: { operator: 'enum_is', value: { type: 'exact', value: 'Done' } },
}],
: ,
},
: [{ : , : }],
});
result = query.();
Delete / Move Blocks
await page.remove();
await page.remove(true);
await myBlock.moveTo(targetBlock, 'after');
Uploads
When working with file/image uploads, never print signedPutUrl, signedGetUrl, upload plans, or temporary signed response files. Log only counts, booleans, block IDs, and final Notion page URLs.
Lock / Unlock a Page
await page.set('format.block_locked', true);
await page.set('format.block_locked', false);
Key Types
block.id;
block.get('type');
block.title;
block.children;
await row.getProp('Name');
await row.getProp('Status');
await row.getProp('Tags');
await row.getProp('Done');
await row.getProp('Due Date');
await row.getProp('Owner');
Common Mistakes
- Forgetting
await on async methods — getClient(), getBlock(), search(), getProp(), set(), addNew(), remove(), and moveTo() are all async.
- Using
markdownToNotion() for block trees — that's for inline rich text only. Use addFromMarkdown() for block content.
- Setting page title as body —
page.title = '# Heading\nBody' is wrong. Set title separately, strip a matching leading # H1 from body markdown when needed, then append body via page.children.
- Not saving the client in a variable — without
const _notion = ..., you re-initialize every REPL call.
- Writing into the wrong workspace — check
currentSpace.get('subscription_tier') and block-limit settings before writing.
- Logging signed upload URLs — signed URLs are temporary credentials. Do not print or persist them.