This post covers a different problem than How to Update Term Store Values with REST API, MS Graph, JavaScript, and PnPjs — that post covers editing the terms themselves (renaming, restructuring the taxonomy). This one is about the far more common task: tagging a list item with an existing term through a Managed Metadata column, in PowerShell and JavaScript. The permission model is genuinely different between the two, covered below.
In this post: Adding a Managed Metadata column · Tagging items with PowerShell · Tagging items with JavaScript and REST · Multi-value columns need a different shape · The permission difference from editing terms · Looking up terms and sets directly · Related reading
Adding a Managed Metadata column
Before any of the code below works, the list needs an actual Managed Metadata column linked to a term set: List Settings > Create Column > type Managed Metadata, then point it at the term set in the Term Store. Everything past this point assumes that column already exists.
Tagging items with PowerShell
Connect-PnPOnline -Url "https://yourtenant.sharepoint.com/sites/YourSite" -Interactive
$term = Get-PnPTerm -TermSet "Locations" -TermStore "Managed Metadata Service" -Group "Department" |
Where-Object { $_.Name -eq "Canada" }
# Create a new item, tagged
Add-PnPListItem -List "Your List Name" -Values @{
Title = "New Item"
"ManagedMetadataColumnName" = $term.Id
}
# Or tag an existing item
Set-PnPListItem -List "Your List Name" -Identity 1 -Values @{
"ManagedMetadataColumnName" = $term.Id
}
`-Interactive` replaces `-UseWebLogin` above, which has been removed from `Connect-PnPOnline` entirely — a script still built around it fails to connect at all, not just with a deprecation warning.
Tagging items with JavaScript and REST
A Managed Metadata field needs a specific nested shape in the request body — `SP.Taxonomy.TaxonomyFieldValue`, with `Label`, `TermGuid`, and `WssId` (set to `-1` when assigning a term for the first time, since that value gets resolved server-side against the site’s hidden taxonomy list):
async function tagListItem(itemId, termLabel, termGuid) {
const listName = "YourListName";
const itemProperties = {
__metadata: { type: "SP.Data.YourListNameListItem" },
ManagedMetadataColumn: {
"__metadata": { type: "SP.Taxonomy.TaxonomyFieldValue" },
Label: termLabel,
TermGuid: termGuid,
WssId: -1
}
};
const response = await fetch(
`${_spPageContextInfo.webAbsoluteUrl}/_api/web/lists/getbytitle('${listName}')/items(${itemId})`,
{
method: "POST",
headers: {
"Accept": "application/json;odata=nometadata",
"Content-Type": "application/json;odata=verbose",
"X-RequestDigest": document.getElementById("__REQUESTDIGEST").value,
"X-HTTP-Method": "MERGE",
"If-Match": "*"
},
body: JSON.stringify(itemProperties)
}
);
if (!response.ok) {
throw new Error(`Tagging failed: ${response.status} ${response.statusText}`);
}
}
`X-HTTP-Method: MERGE` with `If-Match: *` is what makes this an update rather than a full item replace — dropping either header changes the semantics of the call, not just its verbosity.
Multi-value columns need a different shape
Worth knowing before assuming the single-term pattern above just accepts an array: a Managed Metadata column configured to allow multiple values needs a genuinely different request shape, not the same `TaxonomyFieldValue` object with more entries stuffed in. Getting this wrong is a common source of a request that succeeds but silently only saves one of the terms, or fails with an unhelpful error tied to the column’s internal hidden note field rather than the column itself. Given how easy this specific case is to get subtly wrong hand-building raw REST, it’s genuinely one of the better arguments for reaching for PnPjs’s taxonomy field helpers here instead of hand-rolling the multi-value request body — worth checking PnPjs’s current documentation for the exact method rather than trusting an old raw-REST multi-value snippet found elsewhere, since this corner of the API has more inconsistent guidance floating around than the single-value case above.
Tagging a list item with an existing term only needs ordinary Edit permission on the list — unlike editing the terms themselves, it doesn’t require Term Store Administrator rights at all.
The permission difference from editing terms
Worth knowing directly, since it’s a genuinely different requirement from managing the Term Store itself: applying an existing term to a list item only needs ordinary Edit permission on the list — the identity running the script doesn’t need to be a Term Store Administrator or a Group Manager on the relevant term group, the way writing to the term store’s own structure does. That permission requirement only kicks in when creating, renaming, or restructuring terms — covered in the related post linked below, not here. Conflating the two is a common source of confusion when troubleshooting a permission error: check whether the failing operation is tagging an item or editing a term before assuming which permission is actually missing.
Looking up terms and sets directly
Worth a direct correction: the Term Store REST endpoint lives under `_api/v2.1/termStore`, not `_api/v1/termstore` — there is no v1 termstore endpoint currently in service. For looking up a term’s GUID before tagging an item with it, rather than hardcoding one:
GET /_api/v2.1/termStore/groups/{groupId}/sets/{setId}/terms
Returns the terms in a set, including each one’s `id` (the GUID to use as `TermGuid` above) and its label — worth scripting this lookup once per term set rather than maintaining a hardcoded list of GUIDs that silently goes stale the next time someone edits the taxonomy. Caching that lookup for the duration of a batch tagging run is worth doing too, rather than re-querying the term set once per item — the term set’s contents don’t change mid-run, so there’s no reason to pay the extra round-trip repeatedly.
Related reading
- How to Update Term Store Values with REST API, MS Graph, JavaScript, and PnPjs — editing the terms themselves, including the real Term Store Administrator permission requirement that doesn’t apply to the tagging operations covered here.
- SharePoint Metadata: What You Need to Know — how metadata, content types, and the Term Store fit together at a higher level.
Tagging items and editing terms look related on the surface — both involve the Term Store — but they’re different operations with different permission requirements and different REST shapes. Worth keeping that distinction in mind when something that should be simple (assigning an existing term to an item) throws a permission error that actually points at the wrong problem, or when a single-value pattern gets reused unmodified for a multi-value column and silently doesn’t behave the way it looks like it should.
App Catalog Authentication Automation Backup Compliance Content Type CSS Flows Google Javascript Limitations List Metadata MFA Microsoft Node NodeJs O365 OneDrive Permissions PnP PnPJS Policy PowerApps Power Automate PowerAutomate PowerPlatform PowerShell React ReactJs Rest API Rest Endpoint Security Send an HTTP Request to SharePoint SharePoint SharePoint List SharePoint Modern SharePoint Online SPFX SPO Sync Tags Teams Termstore Versioning


