Create a SharePoint Connector
A SharePoint connector enables you to ingest data from your SharePoint instance (and OneDrive) into the Zeta Alpha platform. This guide shows you how to create and configure a SharePoint connector for your data ingestion workflows, including options that impact crawling performance.
The connector ingests document library files and OneNote notebooks (each notebook section becomes its own document) by default. When enabled, it also ingests SharePoint lists (each list item becomes its own document) and SharePoint site pages (each page becomes its own document).
Info: This guide presents an example configuration for a SharePoint connector. For a complete set of configuration options, see the SharePoint Connector Configuration Reference.
Prerequisites
Before you begin, ensure you have:
- Access to the Zeta Alpha Platform UI
- A tenant created
- An index created
- Microsoft App (SharePoint/OneDrive) credentials (refer to the tutorial Configure Microsoft App Access for detailed instructions)
- To render OneNote notebooks (
onenote.mode: visual), the delegatedNotes.Read.AllMicrosoft Graph permission on that same app with admin consent granted, and the username and password of an account that can open the notebooks, since the OneNote API accepts user-delegated tokens only (see Required permissions and authentication below and Optional: OneNote notebooks in the Microsoft app access tutorial) - To ingest SharePoint lists, the
Sites.FullControl.Allapplication permission on the Office 365 SharePoint Online API (not Microsoft Graph), and certificate or username/password credentials: reading item access rights goes through the SharePoint REST API, which rejects client-secret tokens (see Required permissions and credentials below and SharePoint API permissions in the Microsoft app access tutorial)
Step 1: Create the SharePoint Basic Configuration
To create a SharePoint connector, define a configuration file with the following basic fields:
is_document_owner: (boolean) Indicates whether this connector "owns" the crawled documents. When set totrue, other connectors cannot crawl the same documents.schedule: (string, optional) The schedule to crawl the SharePoint instance (cron format).content_source_name: (string) The name that identifies the content source in the index.certificate_credentials: (object, optional) The application credentials for certificate-based authentication. This is the recommended method — it supports all connector features including incremental permission sync, private keys never leave your infrastructure, and certificates can be rotated without updating Azure AD:client_id: The client ID of your SharePoint applicationtenant_id: The tenant ID of your SharePoint applicationcertificate_private_key: The PEM-encoded private key of the certificatecertificate_thumbprint: (optional) The SHA-1 thumbprint of the certificate. Not required whencertificate_public_keyis provided, since MSAL computes it automatically. Only needed if you omit the public certificate.certificate_public_key: (optional) The PEM-encoded public certificate. Not required whencertificate_thumbprintis provided. Required when using Subject Name/Issuer (SNI) authentication.
access_credentials: (object, optional) The application credentials using a client secret. Discouraged — client secret authentication does not support incremental permission detection, requiring a full access rights crawl instead which is slower and uses more API requests:client_id: The client ID of your SharePoint applicationclient_secret: The client secret of your SharePoint applicationtenant_id: The tenant ID of your SharePoint application
public_access_credentials: (object, optional) The user credentials for username/password authentication. Highly discouraged — requires storing user passwords and the account must not have MFA enabled:username: The username for SharePoint accesspassword: The password for SharePoint accessclient_secret: The client secret of your SharePoint applicationtenant_id: The tenant ID of your SharePoint application
certificate_credentials: (object, optional) The application credentials for certificate-based authentication. This is more secure than client secrets and recommended for production environments:client_id: The client ID of your SharePoint applicationtenant_id: The tenant ID of your SharePoint applicationcertificate_private_key: The PEM-encoded private key of the certificatecertificate_thumbprint: (optional) The SHA-1 thumbprint of the certificate. Not required whencertificate_public_keyis provided, since MSAL computes it automatically. Only needed if you omit the public certificate.certificate_public_key: (optional) The PEM-encoded public certificate. Not required whencertificate_thumbprintis provided. Required when using Subject Name/Issuer (SNI) authentication.
logo_url: (string, optional) The URL of a logo to display on document cards when no image is extracted from the pipeline.custom_metadata: (object, optional) Static key-value pairs added to every ingested document. See Content Source Custom Metadata.
Note: You must provide exactly one of certificate_credentials (certificate-based, recommended), access_credentials (client secret, discouraged), or public_access_credentials (username/password, highly discouraged).
Example Configuration
Here is an example of a basic SharePoint connector configuration with certificate-based authentication (recommended):
{
"name": "my_sharepoint_connector",
"description": "My SharePoint connector for product data",
"is_indexable": true,
"connector": "sharepoint",
"connector_configuration": {
"sharepoint": {
"is_document_owner": true,
"content_source_name": "SharePoint Files",
"certificate_credentials": {
"client_id": "my_client_id",
"tenant_id": "my_tenant_id",
"certificate_private_key": "-----BEGIN PRIVATE KEY-----\nMIIEv...\n-----END PRIVATE KEY-----",
"certificate_thumbprint": "AB12CD34EF56...",
"certificate_public_key": "-----BEGIN CERTIFICATE-----\nMIIC/j...\n-----END CERTIFICATE-----"
},
"logo_url": "https://mycompany.com/logo.png"
}
}
}
Alternatively, you can use client secret authentication with access_credentials, but this is discouraged because it does not support incremental permission detection. Permission updates require a full access rights crawl, which is slower and consumes more API requests:
{
"name": "my_sharepoint_connector",
"description": "My SharePoint connector for product data",
"is_indexable": true,
"connector": "sharepoint",
"connector_configuration": {
"sharepoint": {
"is_document_owner": true,
"content_source_name": "SharePoint Files",
"access_credentials": {
"client_id": "my_client_id",
"client_secret": "my_client_secret",
"tenant_id": "my_tenant_id"
},
"logo_url": "https://mycompany.com/logo.png"
}
}
}
You can also use username/password authentication with public_access_credentials, but this is highly discouraged:
{
"name": "my_sharepoint_connector",
"description": "My SharePoint connector for product data",
"is_indexable": true,
"connector": "sharepoint",
"connector_configuration": {
"sharepoint": {
"is_document_owner": true,
"content_source_name": "SharePoint Files",
"public_access_credentials": {
"username": "user@domain.com",
"password": "user_password",
"client_secret": "my_client_secret",
"tenant_id": "my_tenant_id"
},
"logo_url": "https://mycompany.com/logo.png"
}
}
}
Step 2: Add Field Mapping Configuration
When crawling SharePoint, the connector extracts document metadata and content as described in the SharePoint Connector Configuration Reference. You can map these SharePoint fields to your index fields using the field_mappings configuration.
Example Field Mappings
The following example shows field mappings for the default index fields:
{
...
"connector_configuration": {
"sharepoint": {
...
"field_mappings": [
{
"content_source_field_name": "name",
"index_field_name": "DCMI.title"
},
{
"content_source_field_name": "last_modified_date_time",
"index_field_name": "DCMI.modified"
},
{
"content_source_field_name": "created_date_time",
"index_field_name": "DCMI.created"
},
{
"content_source_field_name": "author",
"index_field_name": "DCMI.creator",
"inner_field_mappings": [
{
"content_source_field_name": "display_name",
"index_field_name": "full_name"
},
{
"content_source_field_name": "display_name",
"index_field_name": "Ontology_ID"
}
]
},
{
"content_source_field_name": "content_source_name",
"index_field_name": "DCMI.source"
}
],
...
}
...
}
}
Step 3: Specify What to Crawl
By default the connector crawls the files and OneNote notebooks of every site that its credentials can reach. Narrow the scope to the content you need: a smaller scope crawls faster and makes fewer API requests.
Available Configuration Options
The options have two layers:
- Scope options choose the sites. They apply to every content type.
- Content type options choose what is crawled from those sites. File options are flat fields directly on
sharepoint. OneNote, lists and pages each have a nested block undercontent_configuration, with its own filters. So the flatpath_inclusion_regex_patternsfilters files only,onenote.path_inclusion_regex_patternsfilters notebook sections, andpages.path_inclusion_regex_patternsfilters site pages.
The content_configuration blocks take effect only on a source that runs on scheduled_tasks (see Scheduling with Task Types). A source on the single schedule cron ignores all four blocks: it crawls files with the flat file options.
A PATCH that sends connector_configuration but leaves out the drives or onenote block keeps the stored block. If it leaves out the lists or pages block, that block resets to its default, which turns the content type off. To change a block, or to keep lists or pages on, send the block.
Scope: every content type
site_paths: (array of objects, optional) The sites to crawl. Without it, the connector crawls every site that the crawl identity can see. Each object contains:collection_hostname: The hostname of the SharePoint instance, such ascontoso.sharepoint.comsite_relative_path: The path of the site, such assites/research
include_sub_sites: (boolean, optional, defaultfalse) Withoutsite_paths, also crawl the sub-sites of each site.site_inclusion_regex_patterns: (array of strings, optional) Regular expressions matched against a site's name as Microsoft Graph returns it, often the site's title, such asResearch Team. A sub-site's name follows its parent's:Research Team/Lab. Only matching sites are crawled.site_exclusion_regex_patterns: (array of strings, optional) Regular expressions matched against a site's name, as for the inclusion patterns; matching sites are skipped. Exclusion takes precedence over inclusion.allow_access_rights: (array of objects, optional) Access rights added to every document of this source. Each object contains:name: The user's email, or the group's object idtype: The access-right type. Use a type that the connector records for files, so that the right matches the same users:sharepoint_userwith an email, ormsft_groupwith a Microsoft Entra group object id.
deny_access_rights: (array of objects, optional) Access rights denied on every document of this source. Structure is the same asallow_access_rights.
Files and notebooks can come from other places than the sites: one_drive_users and drive_ids replace the sites for files, and one_drive_users and onenote.drive_ids for notebooks. Lists and pages always come from the sites.
Files: flat fields on sharepoint
Document library files are crawled by default. Their options are flat fields directly on sharepoint. The only file option in content_configuration is the switch that turns files off.
content_configuration.drives.enabled: (boolean, optional, defaulttrue) Crawl document library files. Set tofalseto crawl only the other content types that the source enables; they are unaffected. Files already indexed are not deleted, see Turning document libraries off.one_drive_users: (array of strings, optional) Email addresses of users whose OneDrive files and notebooks are crawled, in place of the sites' files and notebooks.drive_idstakes precedence over it for files, andonenote.drive_idsfor notebooks. The drive patterns apply to these users' files.drive_ids: (array of strings, optional) Crawl the files of exactly these drives, in place ofone_drive_usersand the drives of the sites crawled. The site options, the drive patterns andinclude_one_drivesdo not apply to them; the path patterns do. Drive IDs can be obtained from the Microsoft Graph API.include_one_drives: (boolean, optional, defaultfalse) Also crawl the drives namedOneDrivein the sites crawled. Does not apply toone_drive_usersordrive_ids, which name their drives directly.drive_inclusion_regex_patterns: (array of strings, optional) Regular expressions matched against a drive's name, such asDocuments; only files in matching drives are crawled.drive_exclusion_regex_patterns: (array of strings, optional) Regular expressions matched against a drive's name; files in matching drives are skipped. Exclusion takes precedence over inclusion.path_inclusion_regex_patterns: (array of strings, optional) Regular expressions matched against a file's path in its drive; only matching files are crawled. Microsoft Graph returns the folder part percent-encoded and the file name as is, so the fileQ1 report.docxin the folderAnnual Reportshas the path/Annual%20Reports/Q1 report.docx.path_exclusion_regex_patterns: (array of strings, optional) Regular expressions matched against a file's path, as for the inclusion patterns; matching files are skipped. Exclusion takes precedence over inclusion.download_content_as_pdf: (boolean, optional) Convert Office documents to PDF before indexing them. Defaults to the connector deployment's own setting.extract_sensitivity_labels: (boolean, optional, defaultfalse) Read each file's Microsoft Purview sensitivity label intoconfidentiality_level.decrypt_protected_files: (boolean, optional, defaultfalse) Decrypt MIP-protected files so their content is indexed. Requires MIP decryption on the connector deployment.
OneNote: the content_configuration.onenote block
OneNote is crawled by default: each section's .one file is indexed as text. A configuration without the block gets one: enabled, text, with the flat file configurations include_one_drives, drive_ids and drive and path patterns copied in. After that, the block's own drive and path fields choose the notebooks, and the flat ones apply to files only. See OneNote notebooks.
enabled: (boolean, optional, defaulttrue) Crawl OneNote at all. Set tofalseto leave every.onefile out.mode: (string, optional, defaulttext)textindexes each section's.onefile.visualrenders each section of the notebooks in scope as one HTML document through the OneNote API instead; it requirespublic_access_credentialsas the source's only credentials and the delegatedNotes.Read.Allpermission, since the OneNote API rejects certificate and client-secret credentials.include_resourcesapplies tovisualonly.include_one_drives: (boolean, optional, defaultfalse) Also crawl the notebooks stored in drives namedOneDrivein the sites crawled. Does not apply toone_drive_usersoronenote.drive_ids.drive_ids: (array of strings, optional) Crawl exactly the notebooks stored in these drives, in place ofone_drive_usersand the notebooks of the sites crawled. Independent of the flatdrive_ids.drive_inclusion_regex_patterns: (array of strings, optional) Regular expressions matched against the name of the drive holding a notebook; only notebooks in matching drives are crawled.drive_exclusion_regex_patterns: (array of strings, optional) Regular expressions matched against the name of the drive holding a notebook; notebooks in matching drives are skipped. Exclusion takes precedence over inclusion.path_inclusion_regex_patterns: (array of strings, optional) Regular expressions matched against each section's.onepath in its drive, with no percent-encoding, such as/Notebooks/Team Notebook/General.one, in both modes. Only matching sections are crawled. A notebook's folder followed by/, such as^/Notebooks/Team Notebook/, matches every section in it.path_exclusion_regex_patterns: (array of strings, optional) Regular expressions matched against each section's.onepath, as for the inclusion patterns; matching sections are skipped. Exclusion takes precedence over inclusion.include_resources: (boolean, optional, defaultfalse) Inline the images and file attachments a section's pages embed into the section's own content. See Embedded images and attachments.
Lists: the content_configuration.lists block
Lists are off by default. They come from the sites in scope: one_drive_users, drive_ids and the flat file filters do not apply. See SharePoint lists.
enabled: (boolean, optional, defaultfalse) Ingest the SharePoint lists of the sites crawled, onetext/htmldocument per list item. Requires certificate or username/password credentials. Reading each list's permissions takes theSites.FullControl.AllSharePoint permission.include_hidden: (boolean, optional, defaultfalse) Also ingest lists hidden from the site contents page. This includes some lists SharePoint creates for itself, such asCSPViolationReportList, so pair it withname_inclusion_regex_patterns.name_inclusion_regex_patterns: (array of strings, optional) Regular expressions matched against list display names; only matching lists are ingested.name_exclusion_regex_patterns: (array of strings, optional) Regular expressions matched against list display names; matching lists are skipped. Exclusion takes precedence over inclusion.
Pages: the content_configuration.pages block
Site pages are off by default. They come from the sites in scope: one_drive_users, drive_ids and the flat file filters do not apply. See SharePoint Site Pages.
enabled: (boolean, optional, defaultfalse) Ingest the published site pages and news posts of the sites crawled, each page as its own HTML document.include_resources: (boolean, optional, defaultfalse) Inline the images and files uploaded into a site page into the page's own content. See Images and files on a page.path_inclusion_regex_patterns: (array of strings, optional) Regular expressions matched against a page's path/SitePages/{file name}; only matching pages are crawled. See Choosing which pages are crawled.path_exclusion_regex_patterns: (array of strings, optional) Regular expressions matched against a page's path/SitePages/{file name}; matching pages are skipped. Exclusion takes precedence over inclusion.
Example Configurations
Example 1: Crawl the files and notebooks of every site
{
"name": "my_sharepoint_connector",
"description": "My SharePoint connector for product data",
"is_indexable": true,
"connector": "sharepoint",
"connector_configuration": {
"sharepoint": {
"is_document_owner": true,
"content_source_name": "SharePoint Files",
"certificate_credentials": { "...": "..." },
"include_sub_sites": true,
"include_one_drives": true,
"field_mappings": [
...
]
}
}
}
Example 2: Crawl the OneDrive of specific users
{
"name": "my_sharepoint_connector",
"description": "My SharePoint connector for product data",
"is_indexable": true,
"connector": "sharepoint",
"connector_configuration": {
"sharepoint": {
"is_document_owner": true,
"content_source_name": "SharePoint Files",
"certificate_credentials": { "...": "..." },
"one_drive_users": [
"zeta@zeta-alpha.com",
"alpha@zeta-alpha.com"
],
"field_mappings": [
...
]
}
}
}
Example 3: Filter each content type
The scope and file filters are flat fields. The OneNote, lists and pages filters are in their blocks, which need scheduled_tasks:
{
"name": "my_sharepoint_connector",
"description": "My SharePoint connector for product data",
"is_indexable": true,
"connector": "sharepoint",
"scheduled_tasks": [
{ "task_type": "content_delta", "schedule": "*/15 * * * *" },
{ "task_type": "access_rights_delta", "schedule": "*/15 * * * *" },
{ "task_type": "content_full", "schedule": "0 4 * * 0" },
{ "task_type": "access_rights_full", "schedule": "0 5 * * 0" }
],
"connector_configuration": {
"sharepoint": {
"is_document_owner": true,
"content_source_name": "SharePoint",
"certificate_credentials": { "...": "..." },
"include_sub_sites": true,
"site_exclusion_regex_patterns": ["Zeta Private Team"],
"drive_inclusion_regex_patterns": ["^ZetaDrive$"],
"path_inclusion_regex_patterns": ["^/ZetaFiles/.*\\.docx$", "^/ZetaFiles/.*\\.xlsx$"],
"content_configuration": {
"onenote": { "path_exclusion_regex_patterns": ["/Personal Notebook/"] },
"lists": { "enabled": true, "name_exclusion_regex_patterns": ["^Scratch"] },
"pages": { "enabled": true, "path_exclusion_regex_patterns": ["^/SitePages/Archive-"] }
},
"field_mappings": [
...
]
}
}
}
Here files come only from ZetaDrive, but notebooks are not limited to it: the flat drive and path filters do not apply to OneNote.
Step 4: Create the SharePoint Connector
To create your SharePoint connector in the Zeta Alpha Platform UI:
- Navigate to your tenant and click View next to your target index
- Click View under Content Sources for the index
- Click Create Content Source
- Paste your JSON configuration
- Click Submit

Crawling Behavior
The first time the connector runs, it crawls all information specified in the connector configuration.
After the initial crawl, only new, deleted, and modified documents will be crawled for the specified sites, drives, and paths. This incremental approach avoids crawling unnecessary data and improves performance.
Turning document libraries off
Document library files are crawled by default. A source that should ingest only lists, or only OneNote, declines them:
{
"connector_configuration": {
"sharepoint": {
"...": "...",
"content_configuration": {
"drives": { "enabled": false },
"lists": { "enabled": true }
}
}
}
}
No file document or file permission is then emitted, .one section files aside. List and OneNote crawling are unaffected: in text mode the connector still lists the drives the onenote block selects for their .one section files, and in visual mode it follows the document libraries holding the rendered notebooks, since that is where their edits and permission changes surface.
Declining files stops crawling them; it does not remove the files already indexed. The next full crawl leaves every one of them unseen. If they are more than the delete fraction of the source's documents (0.2 unless max_delete_fraction_override is set), the platform's delete guard refuses the deletion, so they stay in the index with the permissions they last had. To remove them deliberately, raise max_delete_fraction_override on the content source, run one full crawl, then unset it.
Incremental Permission Sync
In addition to content changes, the connector also detects permission-only changes (e.g., when a user is granted or revoked access to a document without modifying the document itself). This uses the SharePoint REST getchanges API to track role assignment additions and removals.
Note: Incremental permission detection requires delegated authentication (certificate or ROPC credentials). Client secret authentication (app-only tokens) does not support the SharePoint
getchangesAPI and will skip incremental permission updates. Use the full access rights crawl as a workaround (see below).
Full Access Rights Crawl
You can configure the connector to perform a full access rights refresh without re-downloading content. This iterates all documents and emits updated permissions, then advances the access rights change token while leaving content tokens untouched.
This is useful for:
- Bulk-refreshing permissions at any point in time
- Working around the client secret limitation for incremental permission detection
- Recovering from a missed permission change window
To enable, set full_access_rights_crawl to true in the connector configuration:
{
"name": "my_sharepoint_connector",
"connector": "sharepoint",
"connector_configuration": {
"sharepoint": {
...
"full_access_rights_crawl": true
}
}
}
Since-Date Crawl
You can reseed delta crawling from a specific date by setting since_crawl_date (in YYYY-MM-DD format). When set, the connector ignores the stored delta tokens for that run and re-detects content and access-right changes modified on or after that date, then refreshes the tokens so subsequent runs resume incrementally.
This is useful for:
- Recovering from a missed change window
- Backfilling changes after expanding the crawl scope (e.g., adding new
site_pathsordrive_ids) - Catching up changes without paying for a full re-crawl
since_crawl_date is ignored when full_crawl is true.
{
"name": "my_sharepoint_connector",
"connector": "sharepoint",
"connector_configuration": {
"sharepoint": {
...
"since_crawl_date": "2024-01-15"
}
}
}
Crawl Mode Priority
When the connector runs, it selects the crawl mode in the following order:
- Full crawl — if
full_crawlis set totrue - Since-date crawl — if
since_crawl_dateis set - Full crawl — if this is the first run (no delta tokens stored)
- Full access rights crawl — if
full_access_rights_crawlis set totrue - Update crawl — incremental mode (default)
Authentication and Feature Compatibility
| Feature | Certificate | ROPC | Client Secret |
|---|---|---|---|
| Full crawl | ✅ | ✅ | ✅ |
| Incremental content changes | ✅ | ✅ | ✅ |
| Incremental permission changes | ✅ | ✅ | ❌ |
| Full access rights crawl | ✅ | ✅ | ✅ |
| OneNote rendering | ❌ | ✅ | ❌ |
| SharePoint lists | ✅ | ✅ | ❌ |
OneNote rendering (onenote.mode: visual) is the one feature that inverts the recommendation: its Graph API takes user-delegated tokens only, so it needs ROPC (public_access_credentials) and rejects both application credential types. The default text mode runs on any credentials. See Required permissions and authentication.
Lists rule out the client secret for a different reason: item access rights are read over the SharePoint REST API, which accepts app-only tokens only when they are proven with a certificate. A client-secret source gets 401 Unsupported app only token on every list item, whatever permissions are consented. See Required permissions and credentials.
Scheduling with Task Types
A SharePoint source syncs along two dimensions — document content and access rights — and each runs as either a full pass or a delta pass. These map to four task types you can schedule independently:
content_full— crawl the configured scope in full: ingest new and changed documents, refresh metadata, and remove documents the source no longer has.content_delta— ingest only the documents that changed since the last content run (incremental crawl).access_rights_full— re-apply permissions to every document in scope, without re-downloading content (the Full Access Rights Crawl above).access_rights_delta— apply only the permission changes since the last access-rights run (the Incremental Permission Sync above).
See Task types for the authoritative definitions. SharePoint does not accept the enhancement_* task types — those belong to enhancement connectors.
Schedule each task on its own cadence. Set scheduled_tasks, a top-level list on the content source (alongside name and connector, not inside connector_configuration), with one { "task_type": ..., "schedule": "<cron>" } entry per task type:
{
"name": "my_sharepoint_connector",
"connector": "sharepoint",
"scheduled_tasks": [
{ "task_type": "content_delta", "schedule": "*/15 * * * *" },
{ "task_type": "access_rights_delta", "schedule": "*/15 * * * *" },
{ "task_type": "content_full", "schedule": "0 4 * * 0" }
],
"connector_configuration": {
"sharepoint": {
"...": "..."
}
}
}
Each task_type may appear at most once. Editing the list reconciles the schedules; an empty list clears them. A source runs on either the single schedule cron or scheduled_tasks — use scheduled_tasks (and leave schedule unset) when you want independent per-task cadences and full-crawl reconciliation. Per-task scheduling is configured through the content-source API or the platform-admin content-source editor (create / edit). See How a content source runs for the general scheduling model.
Delta runs capture only forward changes. Unlike the single-schedule crawl, which performs a full crawl on its first run (see Crawl Mode Priority), an explicitly scheduled content_delta does not backfill: its first run on a source with no prior delta state records the current position and ingests nothing, and from then on it ingests only what changed since the previous content run. content_full is the authoritative pass — it re-crawls the scope, refreshes metadata, and removes documents the source has dropped. If the connector's delta state expires on the SharePoint side, the next delta run re-anchors to the current position and the following content_full reconciles any skipped window. A periodic content_full is therefore what guarantees the index converges on the source.
Recommended lifecycle.
- Seed the delta first. Run
content_deltaonce before the initial full crawl. It is cheap — it only records the starting position — and arming the delta cursor first means edits made during the initial full crawl (which can take hours on a large source) are still picked up by the next delta run, closing the change-gap. - Run
content_fullonce to load and reconcile the full corpus. - Steady state. Schedule
content_deltaandaccess_rights_deltafrequently (for example every 15 minutes) for freshness, andcontent_fullon a slower cadence (for example weekly, off-peak) to reconcile — refreshing stale metadata and removing documents the source no longer has.
On a source that renders OneNote, the content_full cadence decides how soon a new notebook is rendered when it sits in a document library the source does not read yet: a delta run finds new notebooks only in the libraries it already reads. See Change detection and deletions for what that means in practice, and Running OneNote as its own sync job for giving OneNote its own schedule.
On a source that renders OneNote, schedule access_rights_full as well, and size its cadence to the revocation latency you can accept. access_rights_delta applies a permission change made on a section itself, but a change on a notebook or a section group, which its sections inherit, reaches them with the next access_rights_full, or when a section is next edited.
On a source with lists enabled, schedule access_rights_full as well, and size its cadence to the revocation latency you can accept: a site-level permission change and a change to a list's Item-level Permissions setting are applied only by the full. See List item access rights.
Fetch tuning (advanced). SharePoint downloads document bodies in parallel batches. Two optional base connector-configuration fields tune this: fetch_batch_size (documents per fetch, which is also the ingestion batch size) and fetch_concurrency (how many batches download at once). Leave them unset to use platform defaults; lower fetch_concurrency when the source shares a Microsoft Graph rate-limit budget with other connectors, or raise it to speed up large crawls.
OneNote Notebooks
The connector ingests OneNote notebooks stored in SharePoint sites and in OneDrive. By default (content_configuration.onenote.mode: text) a notebook's section files are indexed as text, like document library files, whether or not the source crawls those. With mode: visual, each notebook section is ingested as its own document instead: its pages rendered by Microsoft to HTML and joined in OneNote's order. onenote.enabled: false leaves OneNote out altogether.
Rendering takes two things beyond the connector configuration below: username/password credentials with the delegated Notes.Read.All Graph permission (Required permissions and authentication), and, if sections should have an in-app preview or be visually processed, the html → pdf rule in the source's ingestion workflow (PDF rendering, previews and visual processing).
What is ingested, and what is not
A notebook exists twice in Microsoft 365:
- In the document library, a notebook is a folder holding a
.onetoc2table of contents and one.onefile per section, with a subfolder per section group. The library shows the notebook as a single item. - In the OneNote service, the same notebook is a notebook, section and page tree, and each page can be rendered to HTML.
| File in the document library | text (default) | visual | enabled: false |
|---|---|---|---|
A section's .one file | indexed as text | replaced by the rendered section, under the same document id | not ingested |
A .one file outside any notebook | indexed as text | not ingested | not ingested |
The .onetoc2 table of contents | never ingested | never ingested | never ingested |
Anything in the notebook's recycle bin (OneNote_RecycleBin) | never ingested | never ingested | never ingested |
Because a rendered section keeps the document id of its .one file, switching between text and visual replaces each section's document at the next crawl, a content_delta included, rather than adding a second copy.
Note that a OneNote page means a page inside a notebook section. SharePoint site pages (.aspx) are a separate content type, crawled with the pages block. See SharePoint Site Pages.
Required permissions and authentication
OneNote is a separate Microsoft 365 service with its own Graph permission, and rendering it (onenote.mode: visual) is the one part of the connector that cannot run on application-level credentials. The default text mode indexes each section's .one file through the drive API and needs no OneNote permission. As Microsoft states in the OneNote API reference, "the Microsoft Graph OneNote API doesn't support app-only authentication." Only user-delegated tokens are accepted; the OneNote service rejects the tokens issued for certificate and client-secret credentials, whatever permissions they carry, with:
40001 The request does not contain a valid authentication token
Azure AD still lists Notes.Read.All under Application permissions, still lets an administrator consent to it, and still issues tokens carrying it. The rejection happens at the OneNote service rather than at sign-in, so nothing in the Azure portal flags the combination as invalid. There is no app-only alternative for OneNote.
A visual OneNote source therefore needs both of the following:
- The delegated
Notes.Read.Allpermission on the Azure AD application from Configure Microsoft App Access, added under Microsoft Graph → Delegated permissions and admin-consented, since the username/password flow cannot prompt a user for consent. The tutorial's Optional: OneNote notebooks section walks through it; the permission is only read access to OneNote content. public_access_credentialson the content source: the username and password of an account that can open the notebooks. This is the only credential type the connector uses to obtain a delegated token, so a source configured withcertificate_credentialsoraccess_credentialscannot render OneNote. As with any username/password source, the account must not have MFA enabled.
Because files are best crawled with certificate credentials while visual OneNote requires username/password, run the two as two content sources over the same sites: the file source on certificate_credentials with onenote.enabled: false, and a second source on public_access_credentials that declines files and sets onenote.mode: visual. See Running OneNote as its own sync job: a split OneNote source is worth having regardless, for its own schedule and fetch concurrency.
Important: a source that sets
onenote.mode: visualwhile it authenticates with a certificate or a client secret is rejected when it is saved. So is one that setspublic_access_credentialsnext to either of them, because those take precedence and would crawl with an app-only token. The fix is the credentials, not another permission grant.
Further points to be aware of when planning the grant:
- Reach follows the crawl account. Delegated
Notes.Read.Allreads the notebooks that the account can access, so the OneNote crawl is bounded by that account's own SharePoint access; there is no tenant-wide grant to narrow. Give the account access to the sites whose notebooks should be indexed, then restrict the crawl further in the connector configuration withsite_paths,site_inclusion_regex_patternsand the path patterns described below. As with every other setting, Zeta Alpha only reads what the connector configuration allows. - OneDrive notebooks belonging to other users are reachable only when shared with the crawl account: a delegated token carries no rights over another user's OneNote. Site notebooks are unaffected: they follow the account's site access.
- Section permissions come from the document library. OneNote exposes no permission API, so each section takes the permissions of its
.onefile, exactly as that file has them as a document. This reuses theFiles.Read.All/Sites.Read.Allaccess the connector already needs for files, with no additional permission. Access is never widened to the site's permissions: a site member who cannot open the notebook does not gain access to its sections through search.
Enabling OneNote alongside files
A single source can render notebooks and crawl files together, provided it authenticates with public_access_credentials: one source carries one credential set, and visual OneNote needs the delegated one. Set the onenote block's mode on it:
{
"name": "my_sharepoint_connector",
"connector": "sharepoint",
"connector_configuration": {
"sharepoint": {
"...": "...",
"content_configuration": {
"onenote": { "mode": "visual", "include_resources": true }
}
}
}
}
Choosing which notebooks are crawled
Both modes take their notebooks from one selector, the most specific the source sets, as files do:
onenote.drive_idstakes exactly the notebooks stored in those drives.- Otherwise,
one_drive_userstakes the notebooks in those users' OneDrive: reachable only where those users have shared them with the crawl account, or where the crawl account is the user. - Otherwise,
site_paths,site_inclusion_regex_patterns,site_exclusion_regex_patternsandinclude_sub_sitesselect the sites whose notebooks are read. A source that sets nosite_pathsreads every site.
The onenote block then filters by what the document library shows: the drive_* patterns against the name of the drive holding the notebook, and the path_* patterns against each section's .one path in that drive. A path pattern matches the path as Microsoft Graph lists it, with no percent-encoding, such as /Notebooks/Team Notebook/General.one, in both modes. A text-mode content_delta matches the same path, since its change rows carry the folder path. A folder followed by /, such as ^/Notebooks/Team Notebook/, selects every section of a notebook or section group. A notebook found in a site's drive named OneDrive is crawled only with onenote.include_one_drives. No file setting applies to a notebook, so a file crawl pinned to the top-level drive_ids or narrowed by the top-level path patterns leaves the notebooks as they are. A source configured before the onenote block existed starts with a copy of those file settings in its block, so its .one files stay where they were. A copied path pattern that matches a folder only in its decoded form, such as one with a literal space, never matched that folder for files, and now applies to that folder's .one files: an inclusion pattern selects them, and an exclusion pattern drops them. Pages cannot be filtered: a section is the smallest unit.
"content_configuration": {
"onenote": {
"mode": "visual",
"path_exclusion_regex_patterns": ["^/Archive/", "/Personal Notebook/"]
}
}
In visual mode no .one file is indexed as text, so a section the filters exclude is not indexed at all, and neither is a .one file outside any notebook. A notebook whose document library folder the connector cannot reach from its OneNote link is skipped with a warning in the run's logs. Once the connector can reach it, the next content_full renders it.
Embedded images and attachments
A rendered section references its images and attachments as OneNote URLs that only the crawling application can open, so they are unusable to anyone reading the document later. With onenote.include_resources enabled, each of those resources is downloaded and embedded directly in the section's content, so the section carries its own media. Images are taken at full resolution when Microsoft provides one.
Resources are fetched individually and never break a section: one that fails to download, or that would push the section over the index's maximum file size, is left as its original link and the section is still ingested. Embedded video is an external link with no file behind it and is left untouched. Enabling this option increases the crawl's download volume and the stored size of each section. Changing it re-renders every section at the next crawl, a content_delta included.
PDF rendering, previews and visual processing
A rendered section is ingested as HTML, and its text is extracted from that HTML: searching, retrieval and citation work with no extra configuration. Two things need a PDF rendering of the section, which an HTML document only gets if the ingestion workflow is configured to produce one:
- The in-app page preview and thumbnail, both rendered from the PDF.
- Visual processing. The Visual Processor agent takes a document's
pdfrepresentation as its input, so on a section without one it has nothing to look at: the section's diagrams, screenshots and layout are not described, and only its text reaches the index. Text alone already carries what Microsoft's own image OCR returns, since a page'salttext is folded into the extracted text; visual processing is what adds a reading of the section as it looks.
This is opt-in per content source. To enable both for a OneNote source, add the html → pdf rule to the pdftotext task of the workflow assigned to it:
{
"name": "pdftotext",
"local_settings": {
"fields_conversion_map": {
"pdf": [
{ "input_type": "representations", "input_field": "content", "output_type": "pdf" },
{ "input_type": "representations", "input_field": "html", "output_type": "pdf" }
],
"text": [
{ "input_type": "representations", "input_field": "pdf", "output_type": "text" },
{ "input_type": "representations", "input_field": "markdown", "output_type": "text" },
{ "input_type": "representations", "input_field": "text", "output_type": "text" },
{ "input_type": "representations", "input_field": "html", "output_type": "text" },
{ "input_type": "representations", "input_field": "content", "output_type": "text" }
],
"nested_text": [{ "input_type": "representations", "input_field": "nested_content", "output_type": "text" }]
}
}
}
Give the whole map, not just the pdf entry: a fields_conversion_map in a task replaces the deployment's default map rather than merging with it, so any output field you leave out stops being produced for that workflow.
Both pdf rules are listed because one workflow serves documents of different types: the content rule renders Office files and images, the html rule renders HTML documents such as OneNote sections. Keep pdf declared before text, and keep every processor that consumes the PDF (image_extractor, thumbnail_maker and agent_processor) after pdftotext in the workflow's steps, so the rendered PDF exists by the time they run. For visual processing, pdf must also appear in the agent_processor task's agent_input_representations.
Text extraction is unaffected by the rule: an HTML document's text always comes from its HTML, never from the rendered PDF, so enabling this cannot change what is already searchable. Rendering each section does add work to ingestion, and visual processing adds an agent call per section on top, so enable it on the sources whose sections users read in the app or whose visual content matters, rather than on every workflow. Without the rule, a section is still fully searchable and its document link opens the section in OneNote.
Change detection and deletions
OneNote provides no change feed, at any level, and its timestamps cannot be trusted: an open Microsoft Graph regression reports a page's lastModifiedDateTime unchanged after edits. The connector watches the SharePoint document library instead. Every page edit rewrites its section's .one file, and the library's change feed reports that rewrite, so a delta run re-renders the section with all its pages. Deleting a section moves its .one file into the notebook's recycle bin, which the library's change feed reports as well, so a delta run removes the section. Sections inside a section group behave the same.
| Event in OneNote | Applied by content_delta | Applied by content_full |
|---|---|---|
| Page created, edited or deleted | ✅ | ✅ |
| Section created, renamed or deleted | ✅ | ✅ |
Changes to whole notebooks:
- A new notebook is rendered by the next
content_deltawhen its document library already holds a notebook the source keeps. In any other library, one the source crawls for files included, it waits for the nextcontent_full. - A deleted notebook is removed from the index by the next
content_deltain visual mode. In text mode its.onedocuments leave at the nextcontent_full. - Renaming a notebook or a section group rewrites no section file, so section titles keep the old name until the section is next edited.
The same holds for the source's scope: after changing which sites, users or notebooks the source covers, run content_full. Until it runs, only the sections edited since are picked up, and a notebook the new settings exclude stays in the index. Switching between text and visual, or toggling include_resources, needs no full crawl: the next content_delta relists every section in scope and replaces its document. On a visual source that delta renders every section, so it takes as long as a full crawl of the notebooks.
Running OneNote as its own sync job
Credentials pull OneNote onto its own content source: rendering needs username/password credentials while files are best crawled with a certificate (Required permissions and authentication), and a source carries exactly one credential set. A separate source also gets its own schedule and its own fetch concurrency, which OneNote needs: it serves at most five concurrent requests per user, while the platform runs ten fetches at once by default. Give a second content source onenote.mode: visual, decline its files, and set fetch_concurrency to 4:
{
"name": "my_sharepoint_onenote",
"description": "OneNote notebooks",
"is_indexable": true,
"connector": "sharepoint",
"scheduled_tasks": [
{ "task_type": "content_delta", "schedule": "*/15 * * * *" },
{ "task_type": "access_rights_delta", "schedule": "*/15 * * * *" },
{ "task_type": "content_full", "schedule": "0 3 * * *" },
{ "task_type": "access_rights_full", "schedule": "0 5 * * *" }
],
"connector_configuration": {
"sharepoint": {
"is_document_owner": true,
"content_source_name": "SharePoint OneNote",
"fetch_concurrency": 4,
"content_configuration": {
"drives": { "enabled": false },
"onenote": { "mode": "visual", "include_resources": true }
},
"public_access_credentials": {
"client_id": "my_client_id",
"tenant_id": "my_tenant_id",
"username": "onenote-crawler@contoso.com",
"password": "my_password"
},
"site_paths": [
{ "collection_hostname": "contoso.sharepoint.com", "site_relative_path": "sites/research" }
]
}
}
}
Here new notebooks are rendered nightly and the sections' access rights are refreshed nightly, while the file source can keep its weekly full crawl. The task types and the scheduled_tasks mechanics are the same as for files: see Scheduling with Task Types, including the recommendation to seed content_delta once before the first full crawl.
Points to keep in mind when splitting the source in two:
- Turn OneNote off on the files source, with
content_configuration.onenote.enabled: false, and run it onscheduled_tasks, where the block applies. A rendered section has the same document id as its.onefile, so a files source still indexing.onetext would write the same documents: only the first source to write a document owns it, and the other source's jobs endincomplete, orfailedwhen every document they write collides. With OneNote off there, sections and files are distinct documents and both sources can be document owners. Give the OneNote source its owncontent_source_name. .onefiles outside any notebook are indexed by neither source: visual mode renders notebook sections only, and the files source crawls no OneNote.- Keep both sources on the same crawl scope settings you intend to cover; the OneNote source discovers notebooks through its own
site_paths/ site patterns. The two sources cover the same sites only if the OneNote source's crawl account can open them: its reach is the account's access, not the application's. - Keep the files source on
certificate_credentials. Only the OneNote source needs username/password credentials, so splitting confines the ROPC account to the notebooks. - A OneNote-only source keeps full access rights on its sections, from the same place a combined source takes them: each section's
.onefile (see Required permissions and authentication). A section takes them when it is fetched, andaccess_rights_fullreads each.onefile's permissions again.access_rights_deltafollows the document library's permission change log and re-reads a section whose own permissions changed. A change made on a notebook or a section group reaches its sections only withaccess_rights_full, so schedule both. What such a source never emits is access rights for library files, since it ingests none.
Other OneNote behaviour worth knowing
- Section size. OneNote does not report a section's size in advance, so the index's maximum file size is applied while its pages download and again after rendering. An oversized section is handled like an oversized file. When resource embedding is on, the limit also applies to the section's combined size: a section that would exceed it keeps its original resource links instead.
- Metadata. A section's document title is its logical path,
{site name or OneDrive user}/{notebook}/{section}(with the section group segments inserted when the section is in one), the same convention as a file, whose title is its site, drive and path. The document link opens the section in OneNote on the web. Created and modified timestamps and the author come from the section. - Password-protected and empty sections are ingested with their title only: Microsoft lists a password-protected section but returns its pages as empty, with no error, so the connector cannot tell it apart from an empty section. Protecting or emptying a section that was already ingested removes its earlier content at the next crawl.
- Throttling. The OneNote service allows 120 requests per minute and 400 per hour per application and user, and, unlike the rest of Graph, its rate-limit responses carry no
Retry-Afterhint. The connector backs off and retries on its own; a sustained throttle slows a crawl but does not drop sections. Running OneNote as its own source keeps that budget separate from the file crawl.
SharePoint Lists
With content_configuration.lists.enabled, the connector ingests the SharePoint lists of the sites crawled: task trackers, issue logs, contact lists, custom lists. Each list item becomes its own document, so a row is searchable, retrievable and citable on its own.
Enable it on an existing source, or on a dedicated one:
{
"name": "my_sharepoint_connector",
"connector": "sharepoint",
"connector_configuration": {
"sharepoint": {
"...": "...",
"content_configuration": {
"lists": { "enabled": true, "name_exclusion_regex_patterns": ["^Scratch"] }
}
}
}
}
Unlike OneNote, lists need no credential split: certificate credentials cover files and lists in one source. List ingestion is also independent of the OneNote flags, so a source can combine any of the content types its credentials allow.
What becomes a document
- Every item of every in-scope list is rendered as a self-contained
text/htmldocument: a heading with the list and item title, then one line per column with the column's label and value. - Visible columns are rendered; hidden columns and column types with no text form (image thumbnails, geolocation) are omitted. Person, lookup, managed-metadata and hyperlink columns render as their display text. At most 12 lookup and person columns per list are expanded, a Microsoft Graph limit; further ones are omitted.
- The columns SharePoint maintains itself (Created, Modified, Author, Editor, Content Type and Attachments) are left out of the text. The first three are already document fields (created date, last updated date, authors), so a line for them repeats a value the document already carries. Columns that compute their value from a formula are content, not bookkeeping, and do render.
- The item's title is its Title column, or the first non-empty text column, or the item's numeric id. The document's path is
{site}/Lists/{list}/{title}, and its link opens the item in SharePoint. - Column values are also carried in the
column_valuesfield, keyed by internal column name, sofield_mappingscan promote them to index fields. Every column is there, including the ones kept out of the text:column_values.Editormaps like any other. See the configuration reference. - Attachments ride inside the item's document as downloadable links: file names are searchable text (also carried in
attachment_names, promoted to an index field the same way ascolumn_values), while the file contents are embedded for download but not indexed. An attachment that would exceed the index's maximum file size is listed by name only. A failed attachment download fails the whole item, so it is retried on the next run. Attachments are listed with their size and version at enumeration, so an attachment replaced in place is re-indexed on the next full content pass even though the item itself did not change.
Document libraries are not lists to this connector; files are always crawled through the file settings. Lists that SharePoint marks as system (galleries, the user information list, workflow history) and the Web Template Extensions, Access Requests and item-reference lists are never ingested. Hidden lists are ingested only with include_hidden.
Required permissions and credentials
Enumerating lists and reading item content use the Microsoft Graph permissions the connector already has. List access rights are the extra requirement: they are read from the SharePoint REST role-assignment endpoint, whose authorization comes from the Office 365 SharePoint Online API permissions of the app registration, not the Graph ones. Two things must hold:
- A Full Control grant. Enumerating role assignments requires SharePoint's Enumerate Permissions right, which only Full Control includes. Add the Office 365 SharePoint Online →
Sites.FullControl.Allapplication permission and grant admin consent; the Microsoft app access tutorial walks through it. The SharePointSites.Read.Allpermission that suffices for incremental permission sync is not enough here: with a lower grant the read of a list's permissions returns403 System.UnauthorizedAccessException, and every item of the list carries only the source'sallow_access_rights(see below). - Certificate or username/password credentials. SharePoint REST rejects app-only tokens that were not proven with a certificate, before any authorization check, so no permission grant changes it. A source on
access_credentials(client secret) gets401 Unsupported app only tokenon every list item; the fix is the credential type, not another permission.
For a username/password source the Full Control requirement translates to two grants, both mandatory: the delegated Office 365 SharePoint Online → AllSites.FullControl permission, admin-consented, and Full Control for the crawl account itself on every site in scope (site Owners group or site collection administrator). Effective rights are the intersection of the two, so a Members or Visitors account still gets the 403. Sites the account cannot open are skipped, as everywhere with delegated credentials.
With Sites.Selected instead of tenant-wide permissions, the per-site grant must carry the fullcontrol role for list permissions to be read; with read, list items carry only the source's allow_access_rights. See step 19 of the tutorial.
If Full Control cannot be granted at all, only the permission read is affected: a list's role assignments resolve empty and each item carries the source's allow_access_rights, skipped when that leaves none. The connector still reads each list's settings and its attachments over SharePoint REST, so it needs a read-level Office 365 SharePoint Online grant (Sites.Read.All app-only, AllSites.Read delegated). With no grant on that API the settings read returns 401/403, every item fails to fetch and the list crawl produces no documents. See List item access rights below.
Choosing which lists are crawled
site_paths,site_inclusion_regex_patterns,site_exclusion_regex_patternsandinclude_sub_sitesselect the sites whose lists are read. Neitherone_drive_usersnordrive_idsnarrows them.name_inclusion_regex_patternsandname_exclusion_regex_patternsthen filter on the list's display name. Exclusion takes precedence, and a non-empty inclusion set gates lists exactly as path patterns gate files: a list matching no inclusion pattern is skipped.include_hiddenadds every list hidden from the site contents page that Microsoft Graph does not mark as system. Some of those are SharePoint's own, such asCSPViolationReportListandSharePointHomeCacheList, so setname_inclusion_regex_patternsto the hidden lists you want alongside it. System lists and the Web Template Extensions, Access Requests and item-reference lists stay excluded regardless.drive_idsdoes not constrain lists; it targets the file crawl only.path_inclusion_regex_patternsandpath_exclusion_regex_patternsapply to files only, not to list items.
Lists follow the site scope and nothing else, so a source that pins its file crawl with drive_ids or one_drive_users but sets no site_paths and no site patterns enumerates the lists of every site the crawl identity can see, which on a tenant-wide grant is the whole tenant. Set site_paths or the site regex patterns whenever list crawling is on.
List item access rights
Every item carries its list's permissions: the list's role assignments are read once per list and apply to all of its items, with no per-item read. An item with unique permissions (broken inheritance) is covered by its list's permissions too, which may be broader or narrower than its own.
A refused (401/403) read of a list's permissions is the expected state of a deployment without Full Control, so it degrades: the list's permissions resolve empty and each item carries the source's allow_access_rights, and is skipped entirely when that leaves no access rights, so an item is never ingested with open access. A transient failure of the read fails the item, so it is retried rather than ingested against an empty list ACL.
Each user or group that a role assignment grants read is recorded with the same access right it has on files: a Microsoft Entra or Microsoft 365 group as msft_group with its object id, a user as sharepoint_user with their email, and a SharePoint group as sharepoint_site_group with its group id. List items therefore match the same user and group mappings as files. A principal with no such access right, such as Everyone, Everyone except external users or a user without an email, is recorded under its SharePoint login name with the type sharepoint_principal and is not matched to platform users, so an item granted only to it is found through the source's allow_access_rights.
Lists whose Item-level Permissions restrict reads to "items that were created by the user" are honoured: an item carries only the users and groups whose permission level includes Override List Behaviors (Design and Full Control, so a site's Owners but not its Members, who hold Edit). The item's creator is not added, so on such a list other users find none of the items they created. Changing this setting alters no role assignment, so SharePoint's change log does not report it and it reaches the items on the next access_rights_full.
Both access-rights task types cover list items. access_rights_full re-resolves every in-scope item's rights without re-downloading content. access_rights_delta follows each list's SharePoint change log and re-reads a list whose own permissions changed.
SharePoint records a role assignment against the object it was made on, and an item that inherits holds none of its own, so changing a list's, a library's or a site's permissions names no items in the change log. Removing a permission from the parent is not recorded against items with unique permissions either, so a container-level change reaches no item by name in either direction. Applying one means re-reading everything under it:
- For a list,
access_rights_deltare-reads the list itself and re-emits every item. Every item's rights are the list's, read once per run, so the pass costs the item listing rather than a call per item. - For document library files, re-reading costs one permissions call per item. The delta logs that it saw the change, naming the drive, and
access_rights_fullis what applies it.
A permission change at the site level is always applied by access_rights_full, because SharePoint's list change log does not report it at all.
Change detection for lists
Lists have a real change feed, so freshness works like files, not like OneNote:
| Event in the list | Applied incrementally | Applied by a full pass |
|---|---|---|
| Item created or edited | content_delta | content_full |
| Item deleted | content_delta | content_full |
| Attachment added or removed | content_delta | content_full |
| Attachment file replaced in place | not detected | content_full |
| Permission change on a single item | no effect: items carry their list's permissions | no effect |
| Permission change on the whole list | access_rights_delta | access_rights_full |
| Item-level Permissions setting changed | not detected | access_rights_full |
A list that is new to the connector (created, newly in scope, or list crawling just enabled) is listed in full on the next content_delta, and a list whose change feed has expired on the SharePoint side is listed in full again on the run that notices. Such a listing adds and updates items only: an item deleted while the feed was expired is removed by the next content_full. The access-rights change log works the same way: a list whose token has aged past SharePoint's retention has its items' permissions re-read and its token reset on that run.
An item's identity is stable within its list: edits update the same document. An item moved to another list, or a list deleted and recreated by a migration, changes identity; the affected items are re-ingested as new documents and the old ones are removed by the next content_full.
SharePoint Site Pages
The connector can ingest the modern site pages of the sites it crawls: articles, home pages and news posts. Each page becomes its own HTML document.
Enable it with the pages block of content_configuration on the content source:
{
"connector_configuration": {
"sharepoint": {
"...": "...",
"content_configuration": {
"pages": { "enabled": true }
}
}
}
}
Which pages are ingested
The connector reads each page from the Microsoft Graph pages API and composes its HTML from the page's web parts. It does not ingest the page's .aspx file in the Site Pages library.
Only published pages are ingested, at the version the page's readers see; a draft never reaches the index. A page that was never published is not crawled. On a source with username/password credentials, a page with a saved draft is fetched again only after it is published, and a page first found with a saved draft is ingested at that point.
News posts are ingested with ordinary pages. The crawled record's promotion_kind is newsPost for a news post and page for an ordinary page. Map it with field mappings to use it as a search facet.
Classic pages, such as wiki pages and the pages of classic publishing sites, are not ingested, because the Microsoft Graph pages API serves modern pages only. Page templates are not ingested either. A page whose web parts hold no readable content is skipped.
What a page's document contains
The document follows the page's layout: the banner, then each section in order, with its column widths and background emphasis. It contains:
- The text, links and images that SharePoint extracted from each web part, third-party web parts included.
- One block per repeated element, such as a hero tile or a quick link, so that a tile's image, heading, text and link stay together.
- The shape of the web parts you write content into: image, image gallery, hero, editorial card, quick links, people, markdown, code snippet, embed, YouTube, button, call to action and link. An image keeps its caption and alternative text. Quick links keep their lines or cards. An editorial card keeps its kicker and description. A markdown or code snippet web part contributes its body. If one of these web parts has an unexpected shape, the connector treats it as any other web part.
- The file's name beside each link to a file on the site's SharePoint host, except in live-query web parts.
- For a live-query web part (news, highlighted content, events, site activity), the snapshot of results that SharePoint saved with the page. The connector does not run the query again, so the snapshot can be out of date. Results that are files or pages are indexed as their own documents when the source crawls them.
- The heading of a web part, when the page shows one, such as the title of a news, list or quick links web part.
It leaves out:
- The rows of a list view. SharePoint stores only the list and the view that the web part shows, so the document holds the list's name as a link to the list.
- The name and description of each web part type, such as "Hero" or "Show an image on your page".
- Links with no readable label, so that no raw URL appears in the text.
Page metadata follows the file convention: the document title is {site name}/SitePages/{page title}, the link is the page URL, the timestamps are the page's own, and the author is the page's creator.
As with OneNote, page previews and visual processing need the html → pdf rule in the source's ingestion workflow. See PDF rendering, previews and visual processing.
Choosing which pages are crawled
Pages belong to a site, so the site settings (site_paths, site_inclusion_regex_patterns, site_exclusion_regex_patterns) decide which pages are in scope. In each site, the pages block's own path_inclusion_regex_patterns and path_exclusion_regex_patterns filter pages by the path /SitePages/{file name}. The top-level path patterns filter files, not site pages, so the two filters can differ:
"content_configuration": {
"pages": { "enabled": true, "path_exclusion_regex_patterns": ["/SitePages/Archive-"] }
}
drive_ids and one_drive_users scope the file crawl only. A source that sets either still takes its pages from the site settings. With no site settings, that is every site the crawl identity can see.
Images and files on a page
With include_resources on, the connector inlines the page's assets: the pictures and files that an author adds to the page as a copy. SharePoint keeps them in an assets folder for that page alone, with the page's permissions. They are never indexed as documents of their own.
The connector does not read an asset's own permissions. If someone narrows them later, anyone who can read the page can still see the asset in the indexed page.
- If site owners narrow the permissions of page assets, keep
include_resourcesoff. - If an asset was narrowed after it was inlined, remove it from the page or turn
include_resourcesoff, then publish the page again. The connector fetches a page again only when the page changes, so a full crawl does not remove the inlined copy.
A picture that is not inlined appears as a link with its alternative text. These are not inlined:
- Every picture, with
include_resourcesoff. - Pictures that an author added by sharing the original instead of a copy, because they keep their own permissions.
- Assets of a page renamed after its assets folder was created, because SharePoint keeps the folder's original name.
- Template artwork, such as the hero tiles of a communication site's default home page.
- Pictures on other hosts, such as Microsoft's public content CDN.
Files that a page links to are never inlined. The file crawl indexes them under their own access rights.
The index's maximum file size applies to each resource and to the whole page. A page over the limit is ingested with links in place of its inlined resources, and skipped if it is still over.
Access rights
A page carries the permissions of its .aspx item in the Site Pages library, recorded as for a file, and needs no permission or credential beyond the file crawl's. If they cannot be read, the run reports a fetch failure for the page; they are never widened to the site's.
access_rights_delta reads the Site Pages library's change log, which needs certificate or username/password credentials (see Incremental Permission Sync). access_rights_full reads every page again. A permission change on the Site Pages library itself makes the delta re-read every page of the site.
Change detection for pages
content_delta reads the change feed of each site's Site Pages library. It fetches pages edited, renamed, moved or restored, and removes pages deleted, unpublished or moved out of the path patterns. If the feed position has expired, the next content_delta lists the site's pages again, and the next content_full removes pages deleted in the gap.
Running pages as their own sync job
To give pages their own schedule (see Scheduling with Task Types), turn the other content types off on a separate source:
"content_configuration": {
"drives": { "enabled": false },
"onenote": { "enabled": false },
"pages": { "enabled": true }
}
Such a source does not index the files its pages link to, so run a files source over the same sites next to it.