ScreenshotNeo

BlogHow-to

How to Generate Document Thumbnails in SharePoint Online

Use Microsoft Graph thumbnails for static images, preview for interactive files, and handle permissions, missing sets, sizing, and failures safely.

By the ScreenshotNeo team1 October 20267 min read

Short answer: For a static image, request Microsoft Graph’s DriveItem thumbnails collection and use the returned small, medium, or large URL (or a custom size). For an interactive document viewer, call the DriveItem preview action instead. A file can have no thumbnail, URLs can change, and preview URLs are temporary and caller-scoped.

This guide covers both paths for SharePoint Online, including permissions, runnable requests, sizing, listing optimizations, fallbacks, and failure handling.

1. Pick the output you actually need

Need Graph operation Result Constraint
Card or list image GET /drives/{drive-id}/items/{item-id}/thumbnails ThumbnailSet metadata and image URLs A DriveItem may have zero or more sets; sizes vary. Microsoft reference
Interactive viewer POST /drives/{driveId}/items/{itemId}/preview Temporary GET or POST embed URL Caller-scoped and short-lived. Preview reference
PDF for a supported source GET /drive/items/{item-id}/content?format=pdf Converted PDF bytes Only documented source extensions are supported; this is separate from thumbnail retrieval.

2. Get the IDs and permission

Resolve the SharePoint site and document library (drive), then identify the file’s DriveItem ID. Your access token must be allowed to read that item. Microsoft lists delegated work or school Files.Read as the least-privileged thumbnail and preview permission, and application access Files.Read.All. SharePoint Embedded uses additional container permissions.

  1. Acquire an OAuth 2.0 Microsoft Graph token for the identity that will make the request.
  2. Use the drive and item IDs in the examples below. A site route such as /sites/{site-id}/drive/items/{item-id}/thumbnails is equivalent when the file is in the site’s default drive.
  3. Send Authorization: Bearer TOKEN; never put the token in a browser URL or expose it to untrusted clients.

3. Retrieve a thumbnail

Raw HTTP

GET https://graph.microsoft.com/v1.0/drives/{drive-id}/items/{item-id}/thumbnails
Authorization: Bearer {access-token}

The response is a value array of ThumbnailSet objects. Each set may contain small, medium, and large image objects with dimensions and a URL. Select the largest available size that fits your layout. A content route is also documented:

GET https://graph.microsoft.com/v1.0/drives/{drive-id}/items/{item-id}/thumbnails/{thumb-id}/{size}/content
Authorization: Bearer {access-token}

That route redirects to the thumbnail URL. Treat the returned URL as data, not as a permanent identifier: it can change when the item changes and a new thumbnail is generated.

cURL

curl --fail --location \
  -H 'Authorization: Bearer ACCESS_TOKEN' \
  'https://graph.microsoft.com/v1.0/drives/DRIVE_ID/items/ITEM_ID/thumbnails'

Python

import requests

TOKEN = 'ACCESS_TOKEN'
url = 'https://graph.microsoft.com/v1.0/drives/DRIVE_ID/items/ITEM_ID/thumbnails'
r = requests.get(url, headers={'Authorization': f'Bearer {TOKEN}'}, timeout=30)
r.raise_for_status()
data = r.json()
sets = data.get('value', [])
if not sets:
    raise RuntimeError('This item has no thumbnail set')
thumb = sets[0].get('large') or sets[0].get('medium') or sets[0].get('small')
if not thumb or not thumb.get('url'):
    raise RuntimeError('No usable thumbnail size was returned')
image = requests.get(thumb['url'], timeout=30)
image.raise_for_status()
open('thumbnail.jpg', 'wb').write(image.content)

Node.js (18+)

const token = process.env.GRAPH_TOKEN;
const endpoint = 'https://graph.microsoft.com/v1.0/drives/DRIVE_ID/items/ITEM_ID/thumbnails';
const meta = await fetch(endpoint, { headers: { Authorization: `Bearer ${token}` } });
if (!meta.ok) throw new Error(`Graph ${meta.status}: ${await meta.text()}`);
const sets = (await meta.json()).value ?? [];
const thumb = sets[0]?.large ?? sets[0]?.medium ?? sets[0]?.small;
if (!thumb?.url) throw new Error('No thumbnail is available');
const image = await fetch(thumb.url);
if (!image.ok) throw new Error(`Thumbnail ${image.status}`);
const fs = await import('node:fs/promises');
await fs.writeFile('thumbnail.jpg', Buffer.from(await image.arrayBuffer()));

4. Request thumbnails efficiently in a file list

When rendering many rows, ask Graph to expand thumbnails with the DriveItem listing request instead of making one request per row:

GET https://graph.microsoft.com/v1.0/drives/{drive-id}/root/children?$expand=thumbnails
Authorization: Bearer {access-token}

Use the supported listing shape in the API reference; some nested $expand forms are not supported. Cache the selected URL for the lifetime of your page, and refresh metadata when an item changes. Do not assume every returned item has a thumbnail.

Custom dimensions

The API documents size names such as c300x400 (fit inside a 300-by-400 box while preserving aspect ratio) and c300x400_crop (fill and crop). The resulting image may not be exactly the requested pixel dimensions. Ask for the smallest size that meets your display density to reduce transfer time.

5. Embed an interactive preview

Use preview when users must page, zoom, or interact with the actual document. Send a JSON body; page and zoom are optional and apply only when the preview app supports them.

POST https://graph.microsoft.com/v1.0/drives/{drive-id}/items/{item-id}/preview
Authorization: Bearer {access-token}
Content-Type: application/json

{"page": 1, "zoom": 1.25}

The response can include getUrl, postUrl, and postParameters. If getUrl is present, load it in an iframe or new page. For a POST form, submit the returned parameters to postUrl. Which fields appear depends on embed support and the requested options.

Preview URLs are temporary and intended for the caller. A visitor using one acts with the calling identity’s permissions. Generate them with least-privileged read access, keep them server-side where possible, and never present one as a durable share link. Delegated personal Microsoft accounts are not supported for this preview action.

6. Convert a file to PDF when that is the real requirement

For a supported source extension, Graph can return converted PDF content:

GET https://graph.microsoft.com/v1.0/drives/{drive-id}/items/{item-id}/content?format=pdf
Authorization: Bearer {access-token}

Conversion support is limited to the extensions listed in Microsoft’s current content API documentation. A PDF conversion is a separate operation; ordinary supported thumbnails do not require converting the document first.

7. Edge cases, reliability, performance, and cost

  • No image: an item can have zero thumbnail sets. Show a file-type icon or an “open document” link as a deliberate fallback.
  • Unsupported format or tenant policy: preview and thumbnail capability varies by service, tenant, and client. Handle failure and keep the list usable.
  • Changed item: thumbnail URLs can be replaced. Re-read metadata after an item update rather than persisting the URL forever.
  • Authorization boundary: keep Graph calls on a server when the browser should not receive broad permissions. Re-check the end user’s access before embedding a caller-scoped preview.
  • Latency: expand thumbnails in listings, request an appropriate size, and cache metadata briefly. Use bounded timeouts and retry only transient 429/5xx responses with backoff.
  • Cost: Microsoft Graph usage, storage, and network charges depend on your Microsoft 365 and Azure agreements. The reviewed documentation does not define a per-thumbnail price, so measure your tenant’s limits and billing separately.

8. Troubleshooting

Symptom Likely cause Fix
401 Unauthorized Missing, expired, or malformed token. Acquire a fresh Graph token and send it as a Bearer header.
403 Forbidden Insufficient Graph or container permission, or the identity cannot read the item. Grant the least-privileged required permission, obtain consent, and verify the drive/item belongs to the intended tenant.
404 Not Found Wrong drive or item ID, or the item moved. Resolve the current DriveItem again and do not mix IDs from different drives.
200 with an empty value No thumbnail set was generated. Use the documented fallback icon/link; do not retry indefinitely.
Image URL later stops working The item changed and the service issued a new URL. Refresh thumbnail metadata when change tracking or a cache miss indicates an update.
Preview action fails Unsupported file type, tenant policy, or missing preview capability. Handle the failure gracefully and offer download/open-original behavior.
Iframe is blank Expired URL, blocked third-party context, or POST parameters not submitted. Request a fresh preview, use the returned GET or POST flow exactly, and test in the target browser.
429 Too Many Requests Graph throttling. Honor Retry-After, use exponential backoff, and batch/list with $expand=thumbnails.

9. Or skip the browser setup with ScreenshotNeo

If you need a rendered image of a SharePoint page or a public document URL and do not want to operate a browser, ScreenshotNeo provides a single screenshot API request. Its options include full-page capture, element selection, custom headers/cookies/user agent, waiting rules, blocking resource types, resizing, caching, signed links, async jobs, and bulk capture. It is separate from Microsoft Graph: it captures the URL you provide, while Graph returns service-generated DriveItem thumbnails and previews.

Before capture, ScreenshotNeo accepts cookie or consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be disabled. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers report the page verdict and billing result. It also has an MCP server with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients.

See the ScreenshotNeo API documentation for all options:

cURL

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://contoso.sharepoint.com/sites/team/Shared%20Documents/report.docx -o shot.webp

Python

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://contoso.sharepoint.com/sites/team/Shared%20Documents/report.docx"}, timeout=90)
open("shot.webp", "wb").write(r.content)

Node.js

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://contoso.sharepoint.com/sites/team/Shared%20Documents/report.docx' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

ScreenshotNeo has 1,000 shots per month free with no card; paid plans start at $5 for 3,000 shots, and every feature is on every plan. Create a free ScreenshotNeo account.

10. FAQ

Does every SharePoint file have a thumbnail?

No. A DriveItem can return zero thumbnail sets, so always provide a fallback.

Can I reuse a thumbnail URL forever?

No. URLs may change when the item changes; refresh metadata as needed.

Should I use thumbnails or preview?

Use thumbnails for compact cards and preview for an interactive viewer with paging or zoom.

Can I expose a preview URL publicly?

No. It is temporary and caller-scoped; anyone using it acts with the caller’s permissions.

Does Graph convert every document to PDF?

No. Conversion supports only the source extensions listed in Microsoft’s content API documentation.