Optimize OneNote Graph API performance for large notebooks, image handling, and batch operations.
Use when dealing with slow API responses, large notebooks, image uploads, or HTTP 507 errors.
Trigger with "onenote performance", "onenote slow", "onenote large notebook", "onenote image upload".
Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Um comando direto ignora o prompt de revisão. Verifique a origem antes de executá-lo.
Optimize OneNote Graph API performance for large notebooks, image handling, and batch operations.
Use when dealing with slow API responses, large notebooks, image uploads, or HTTP 507 errors.
Trigger with "onenote performance", "onenote slow", "onenote large notebook", "onenote image upload".
allowed-tools
Read, Write, Edit, Bash(npm:*), Bash(pip:*), Grep
version
1.6.0
license
MIT
author
Jeremy Longshore <jeremy@intentsolutions.io>
tags
["saas","onenote","microsoft"]
compatibility
Designed for Claude Code
OneNote — Performance Tuning & Optimization
Overview
OneNote performance degrades predictably at scale: notebooks with 100+ sections take 3-5 seconds per API call when using $expand, pages with embedded images over 4MB fail silently, and sections hitting the page limit return 507 Insufficient Storage. Image uploads are capped at 25MB per multipart part, and requesting full page content for hundreds of pages without $select can exhaust your rate budget in seconds.
This skill provides tested patterns for every performance bottleneck: selective $expand and $select for minimal payloads, image compression before upload, batch requests via $batch, pagination with $top to avoid loading thousands of pages, and caching strategies that invalidate on change detection.
Key pain points addressed:
Full $expand=sections($expand=pages) on large notebooks can take 10+ seconds and return multi-MB responses
Image uploads silently fail when a single multipart part exceeds 25MB — no error, just missing image
507 Insufficient Storage when a section hits its page limit (approximately 5,000 pages)
Page content retrieval (GET /pages/{id}/content) is 5-10x slower than metadata-only requests
Prerequisites
Azure app registration with delegated permissions: Notes.ReadWrite
App-only auth deprecated March 31, 2025 — use delegated auth only
Python: pip install msgraph-sdk azure-identity Pillow (Pillow for image compression)
Every Graph API call should specify $select to return only the fields you need. The default response includes navigation properties, OData metadata, and verbose timestamps that inflate payloads:
// BAD — returns ~2KB per page with all metadataconst pages = await client.api("/me/onenote/pages").get();
// GOOD — returns ~200 bytes per page with only needed fields
pages = client.()
.()
.();
notebooks = client.()
.()
.();
notebooks = client.()
.()
.();
const
await
api
"/me/onenote/pages"
select
"id,title,lastModifiedDateTime"
get
// For notebooks, avoid expanding everything
// BAD — can take 10+ seconds on large notebooks
const
await
api
"/me/onenote/notebooks"
expand
"sections($expand=pages)"
get
// GOOD — get structure first, then drill into sections on demand
const
await
api
"/me/onenote/notebooks"
select
"id,displayName,lastModifiedDateTime,sectionsUrl"
get
Payload size comparison for a notebook with 50 sections and 500 pages:
Query
Response Size
Response Time
Full $expand
~800KB
5-10s
$select on notebook only
~2KB
200ms
$select + $top(10) sections
~1KB
150ms
Step 2 — Paginate Large Sections
Sections can accumulate thousands of pages. Always use $top to limit initial loads:
asyncfunction* iteratePages(client: any, sectionId: string, pageSize: number = 50) {
leturl: string | null =
`/me/onenote/sections/${sectionId}/pages?$select=id,title,lastModifiedDateTime&$orderby=lastModifiedDateTime desc&$top=${pageSize}`;
while (url) {
const response = await client.api(url).get();
const pages = response.value ?? [];
for (const page of pages) {
yield page;
}
// Stop if we got fewer than requestedif (pages.length < pageSize) break;
url = response["@odata.nextLink"] ?? null;
}
}
// Usage — process pages lazilyforawait (const page ofiteratePages(client, sectionId)) {
console.log(`Processing: ${page.title}`);
if (shouldStop(page)) break; // Can bail early
}
Step 3 — Image Upload with Size Validation
OneNote accepts images via multipart form data. Each part is limited to 25MB. Images larger than 4MB in the rendered page can cause performance issues in the client. Always validate and compress before upload:
The $batch endpoint processes up to 20 operations per request. This is the single most effective optimization for bulk workloads — it reduces HTTP overhead and counts as one request against rate limits:
asyncfunctionbatchGetPageMetadata(client: any,
pageIds: string[]
): Promise<Map<string, any>> {
const results = newMap<string, any>();
constBATCH_SIZE = 20;
for (let i = 0; i < pageIds.length; i += BATCH_SIZE) {
const chunk = pageIds.slice(i, i + BATCH_SIZE);
const batchBody = {
requests: chunk.map((id, idx) => ({
id: String(idx),
method: "GET",
url: `/me/onenote/pages/${id}?$select=id,title,lastModifiedDateTime`,
})),
};
const response = await client.api("/$batch").post(batchBody);
for (const item of response.responses) {
if (item.status === 200) {
results.set(item.body.id, item.body);
} elseif (item.status === 404) {
// Page was deleted — skipconsole.warn(`Page ${chunk[parseInt(item.id)]} not found`);
}
}
}
return results;
}
// 200 pages = 10 HTTP requests instead of 200const metadata = awaitbatchGetPageMetadata(client, twoHundredPageIds);
Step 6 — HTTP 507 Detection and Mitigation
When a section reaches its page limit (approximately 5,000 pages), new page creation returns 507 Insufficient Storage: