How to Escape Apostrophes in SharePoint REST Queries

An apostrophe in a data value — a name like O’Reilly, a title like Harry’s Adventures — breaks a SharePoint REST `$filter` query, because OData uses single quotes as the string delimiter and has no way to tell a literal apostrophe apart from the end of the string. The fix is one specific, verified rule: double the apostrophe. This post covers that rule precisely, where else it applies, and where it deliberately doesn’t.

In this post: The fix: double it · Escaping it in code · This applies to Graph too · CAML doesn’t need this at all · PnPjs handles this for you · Other characters worth checking too · Related reading


The fix: double it

This fails — the apostrophe in `O’Reilly` terminates the string early, and SharePoint sees `Reilly` as trailing, invalid syntax:

/_api/web/lists/getbytitle('Books')/items?$filter=Author eq 'O'Reilly'

Doubling the apostrophe tells the OData parser to treat it as a literal character inside the string, not as the string’s closing delimiter, which is the actual mechanism worth understanding rather than just memorizing:

/_api/web/lists/getbytitle('Books')/items?$filter=Author eq 'O''Reilly'

Same rule for any number of apostrophes in a value — `Harry’s Adventures` becomes `Harry”s Adventures` inside the filter string, regardless of how many apostrophes appear or where in the value they occur.


Escaping it in code

The pattern is the same regardless of framework, since it’s really just a string transform before the URL gets built — a single regex replace, applied once:

const listTitle = "Books";
const authorName = "O'Reilly";
const escapedAuthorName = authorName.replace(/'/g, "''");

const url = `/_api/web/lists/getbytitle('${listTitle}')/items?$filter=Author eq '${escapedAuthorName}'`;

const response = await fetch(url, {
    headers: { "Accept": "application/json;odata=nometadata" }
});
if (!response.ok) {
    throw new Error(`Query failed: ${response.status} ${response.statusText}`);
}
const data = await response.json();

Worth wrapping this exact transform into a small shared utility function used everywhere a filter value gets built dynamically from user input, rather than repeating the `.replace()` call inline at every call site — a single missed spot is exactly the kind of subtle, hard-to-diagnose bug that shows up only when someone with an apostrophe in their name happens to trigger it:

function escapeODataString(value) {
    return value.replace(/'/g, "''");
}

// Used consistently everywhere a filter value comes from dynamic input
const filterUrl = `/_api/web/lists/getbytitle('Books')/items?$filter=Author eq '${escapeODataString(authorName)}'`;

A single, named, tested function used consistently is worth more here than four separate framework-specific examples that all do the exact same string transform — the fetch call around it varies by framework, but the escaping logic itself genuinely doesn’t.


The same doubling rule applies to Microsoft Graph’s OData filters too — both APIs use the identical single-quote string convention, so the same escaping logic works for either without modification.

This applies to Graph too

Worth knowing directly rather than assuming a different convention for a different API: Microsoft Graph’s `$filter` query syntax uses the same OData string-delimiter rules as SharePoint REST, and the same doubling escape applies identically — `’O”Reilly’` works the same way in a Graph query as it does against SharePoint’s own REST endpoint. A single escaping utility written once genuinely covers both, no separate logic needed for whichever API a given call happens to target.


CAML doesn’t need this at all

Worth knowing before applying the same fix somewhere it doesn’t belong: CAML queries are XML, and an apostrophe inside XML element text content isn’t a special character at all — it needs no escaping:

<Where>
  <Eq>
    <FieldRef Name="Author" />
    <Value Type="Text">O'Reilly</Value>
  </Eq>
</Where>

Only `&`, `<`, and `>` genuinely need escaping in XML text content (`&amp;`, `&lt;`, `&gt;`) — applying the OData doubling trick to a CAML query is a real, common mistake that produces a literal double apostrophe in the search value instead of matching the intended single one, since CAML was never using OData’s string-delimiter convention to begin with.


PnPjs handles this for you

Worth knowing before manually escaping something a library already handles: PnPjs’s query builder methods construct the underlying REST URL internally, and don’t require manually pre-escaping apostrophes in values passed through them the way a hand-built `fetch` URL does. Manual escaping is really only a concern when building the raw REST URL string directly — which is exactly the scenario every example on this page covers, and a genuinely different situation from querying through a library that already handles URL construction. Worth confirming this directly against the specific PnPjs version and method in use rather than assuming universally, though, since the guarantee applies to the library’s own query-building methods specifically, not to a raw string still hand-assembled and passed through as a custom filter clause.


Other characters worth checking too

Apostrophes are the character that actually breaks the query syntax, but they’re not the only one worth handling deliberately when a filter value comes from user input rather than a hardcoded string. An ampersand in a value needs standard URL encoding (`encodeURIComponent`) since it’s the query-string parameter separator, not just an OData string character — an unencoded `&` in a value can silently truncate the filter or merge it with the next parameter, a different failure mode from the apostrophe issue but just as real. More broadly, building an OData filter directly from unsanitized user input is worth treating with the same caution as building a SQL query from user input — it’s a narrower attack surface since `$filter` is read-only, but a maliciously crafted value can still manipulate the filter logic to return data the query wasn’t meant to expose, not just cause a syntax error.



One rule, applied consistently: double an apostrophe in an OData filter string, whether it’s targeting SharePoint REST or Microsoft Graph, and leave CAML values alone entirely — the two query languages have genuinely different escaping rules, not the same rule expressed two different ways. Worth centralizing that logic in one place per project, tested once against a name that actually contains an apostrophe, rather than re-deriving it inline at every call site and trusting each one got it right.

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

Leave a Comment

Your email address will not be published. Required fields are marked *