Type: Developer Guide / Fix · Stage: Optimize · Topic: Customer Segments / ShopifyQL / GraphQL Admin API
Quick answer
If a customer segment query that worked on an older Admin API version now fails, check its function syntax before changing the audience logic. In Shopify GraphQL Admin API 2026-10, segment functions use MATCHES or NOT MATCHES instead of the older = true or = false comparison. Function parameters now carry their own comparison operators.
For example, change shopify_email.opened() = true to shopify_email.opened MATCHES (). This is a segment query language change, not a blanket replacement for every Boolean comparison in GraphQL or ShopifyQL.
On this page
Why an API upgrade can break an otherwise valid audience
Customer segments are saved filters built from customer attributes and behaviors. A marketing app might create them, a data integration might synchronize them, and a merchant might use them to drive a campaign. Older integrations often store the query as a string and submit it again when creating or updating a segment.
Shopify announced the syntax change on October 1, 2026. The old form treated a function like a Boolean expression. The new form treats it as a matching predicate with explicit operators inside its parameters. A saved query string in application code, a job queue, or a configuration file can therefore become a migration problem even when the merchant has not changed the audience definition.
Do not confuse this with ordinary attribute comparisons. A filter such as email_subscription_status = 'SUBSCRIBED' remains an attribute comparison. The change concerns functions, such as purchase and email-engagement predicates.
Translate the predicate, not just the punctuation
| Older segment expression | 2026-10 expression |
|---|---|
shopify_email.opened() = true |
shopify_email.opened MATCHES () |
shopify_email.opened() = false |
shopify_email.opened NOT MATCHES () |
products_purchased(quantity: 5) = true |
products_purchased MATCHES (quantity = 5) |
products_purchased(quantity: 5) = false |
products_purchased NOT MATCHES (quantity = 5) |
The new syntax also permits comparisons that the old function parameter style could not express, such as products_purchased MATCHES (quantity > 5). Use that deliberately: greater than five is not the same audience as exactly five.
Shopify also deprecated the named relative dates 12_months_ago, 90_days_ago, 30_days_ago, and 7_days_ago. Prefer relative offsets such as -12m, -90d, -30d, and -7d where the filter accepts date offsets. Audit those separately from the function conversion.
Find and update stored segment definitions
- Inventory the query strings. Search your app for
segmentCreate,segmentUpdate,customerSegmentMembers, the function names, and the old date tokens. Include database-stored rules and scheduled jobs, not just source files. - Read existing segments before changing them. Query
segmentsfor the current IDs, names, and query strings. Keep an export so you can compare the audience before and after the migration. - Convert function clauses deliberately. Preserve the original match intent and parameter values. Do not run a global search-and-replace on every
= truein the codebase. - Test against the same API version the integration will deploy. A query accepted by an earlier version or in a different interface does not prove that a 2026-10 API mutation accepts it.
- Update the existing segment rather than creating a second segment with a near-identical name. Preserve its ID when the intent is to maintain the same audience.
Use the Admin API to inspect the saved definitions:
query AuditSegments {
segments(first: 50) {
nodes {
id
name
query
}
pageInfo { hasNextPage endCursor }
}
}
For a controlled update, use the existing segment ID and inspect userErrors:
mutation UpdateSegment($id: ID!, $query: String!) {
segmentUpdate(id: $id, query: $query) {
segment { id name query }
userErrors { field message }
}
}
Example variable values:
{
"id": "gid://shopify/Segment/123456789",
"query": "products_purchased MATCHES (quantity > 5)"
}
The ID is illustrative. Confirm the segment exists and that the filter is meaningful for that store before submitting a mutation.
Keep segment membership from drifting silently
A syntactically valid migration is only half the job. Compare member counts and a sample of known customers using customerSegmentMembers or the segment membership query. Watch for differences caused by changed comparison operators, date windows, or an accidentally inverted NOT MATCHES clause.
If the segment drives discounts, marketing, or account operations, record the expected behavior for a customer who should qualify and one who should not. Make the migration reversible at the application-configuration level by keeping the old string and the replacement together, but do not roll back to an API version merely to preserve obsolete syntax.
Common misunderstanding
“Every = true in ShopifyQL is now wrong.” No. The 2026-10 change is specifically about functions in the segment query language. “MATCHES means contains a string.” Not here; it is a predicate operator. “If the segment saves, the membership is identical.” Not necessarily. An accidental change from = 5 to > 5 can produce a valid but different audience.
How to test this
- Copy an existing function-based segment and record its query, member count, and representative customers.
- Run the old expression against Admin API 2026-10 in a development environment; capture the validation response rather than assuming failure mode.
- Submit the translated
MATCHESexpression through the API and confirm nouserErrors. - Re-read the saved
Segment.queryand compare it with the intended expression. - Check members who should match, should not match, and sit on the boundary of a quantity or date condition.
- Test a
NOT MATCHEScase, an exact quantity, and a relative date filter separately. - Run the scheduled integration twice and verify it updates the existing segment instead of creating duplicates.
Sources and further reading
Documentation checked October 24, 2026.

