<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[MergeGuard Engineering Notes]]></title><description><![CDATA[MergeGuard Engineering Notes]]></description><link>https://mergeguard-notes.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Sat, 07 Nov 2026 11:58:50 GMT</lastBuildDate><atom:link href="https://mergeguard-notes.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[What Your Shopify Customer Segment Query Misses When Shoppers Are Split]]></title><description><![CDATA[Try this on your repeat-customer segment without opening it: take a shopper who has ordered twice, once under each of two email addresses, and decide…]]></description><link>https://mergeguard-notes.hashnode.dev/what-your-shopify-customer-segment-query-misses-when-shoppers-are-split</link><guid isPermaLink="true">https://mergeguard-notes.hashnode.dev/what-your-shopify-customer-segment-query-misses-when-shoppers-are-split</guid><dc:creator><![CDATA[Jimit Patel]]></dc:creator><pubDate>Sun, 01 Nov 2026 16:26:21 GMT</pubDate><content:encoded><![CDATA[<p>Try this on your repeat-customer segment without opening it: take a shopper who has ordered twice, once under each of two email addresses, and decide whether they qualify.</p>
<p>On a segment that counts one record's orders, they fail. Each record shows a single order, so a real repeat buyer misses the list twice over, and nothing tells you.</p>
<p>Every automation that reacts to what a person bought depends on the same assumption: a person is one record. This article walks through five segments, shows how a split customer breaks each one, and ends with a one-hour test that gives you two numbers about your own data.</p>
<h2>Where the extra records come from</h2>
<p>Shopify's Help Center says a customer profile <a href="https://help.shopify.com/en/manual/customers/manage-customers">"is created in your Shopify admin when a customer interacts with your business"</a>, through a sign-up, an order or a dropped checkout. One profile holds one email.</p>
<p>So a person who orders once from a work address and again from a personal one shows up as two customers with an order apiece. Nothing is broken, because the store followed its rule.</p>
<p>Merchants describe this in public. For my <a href="https://doi.org/10.5281/zenodo.23705270">published study (DOI 10.5281/zenodo.23705270)</a>, language models coded a long Shopify Community thread requesting a merge feature. Switching addresses featured for 39 of the 97 authors who gave a cause, while phones in place of email and mistyped addresses featured for 19 each.</p>
<p>Keep the limits in mind: these are volunteers writing mostly between 2020 and 2022, so the figures say nothing about frequency. Shopify's own merge feature arrived later and changed part of the picture.</p>
<h2>What does a Shopify customer segment query count?</h2>
<p>A Shopify customer segment query counts customer records. Shopify's <a href="https://shopify.dev/docs/api/shopifyql/segment-query-language-reference">segment query reference</a> says the language "uses only the <code>WHERE</code> clause to filter customers by their attributes", such as <code>number_of_orders</code>, each customer's all-time orders. So a person with one order on each of two profiles fails <code>number_of_orders &gt;= 2</code> twice.</p>
<h2>Segment 1: "Repeat customers"</h2>
<p>A repeat-buyer segment can be as short as the query above. Do Shopify segments automatically update? Shopify's <a href="https://help.shopify.com/en/manual/customers/customer-segmentation">Help Center</a> says customers "are automatically added or removed" according to the criteria, so nothing flags the error for you.</p>
<p>Split records defeat this directly, as the query shows. Shoppers who changed address or paid at a till can vanish from the list that should hold them.</p>
<p>Illustration, with invented numbers: if 500 of your 4,000 profiles belong to people with a second profile, up to 250 repeat buyers could be missing from the segment. The real figure depends on your data. Count it before you trust any estimate, including this one.</p>
<h2>Segment 2: "First-purchase welcome flow"</h2>
<p>A welcome or thank-you series usually triggers on a first order. The trigger is "this record has placed one order".</p>
<p>A returning shopper who uses a different email places a first order on a new record. The flow treats them as new. They receive the introduction, the "how to use it" sequence and the first-order discount again. The brand looks as if it has forgotten them.</p>
<h2>Segment 3: "Review request after delivery"</h2>
<p>Review requests and post-purchase surveys fire per order. If one person has two records and two recent orders, two requests may go to two inboxes. If both addresses belong to the same mailbox owner, the person gets both.</p>
<p>Splitting also hides satisfaction. A reviewer who left feedback under one record can be asked again under the other.</p>
<h2>Segment 4: "Win-back after 90 days of silence"</h2>
<p>Win-back segments key on last order date. A person who bought last week under address B looks inactive on address A, whose last order was a year ago. A "we miss you" offer lands days after a purchase.</p>
<p>The study records this family of problem. Among 87 authors reporting an impact, 36 cited broken history or lost spend tracking, 32 cited service trouble, and 9 cited email or SMS trouble. A segment built on history inherits whichever history it can see.</p>
<h2>Segment 5: "VIP by lifetime spend"</h2>
<p>A spend threshold of, say, a set amount over the lifetime of the account assumes the whole spend sits on one record. Split spend means a top customer may sit below the line on both records. The VIP list is shorter than it should be, and the perks go to someone else.</p>
<p>Illustration, with invented numbers: a shopper who spent 300 on one profile and 250 on another has 550 in total, and a threshold of 500 misses them on both.</p>
<h2>A one-hour test</h2>
<p>Five segments, five ways to fail. Now find out which ones apply to you. You do not need new software. Use a spreadsheet export of your customers and one recent segment.</p>
<ol>
<li><strong>Pick the segment.</strong> Choose a repeat-buyer or win-back list.</li>
<li><strong>Make a phone column.</strong> Leave only numerals in it.</li>
<li><strong>Make a person-and-place column.</strong> Combine name, street and postcode in one lowercase string.</li>
<li><strong>Group by each key.</strong> Flag groups of two or more records.</li>
<li><strong>Check who is in the segment.</strong> For each group, see which records qualify and which do not.</li>
<li><strong>Count the misses.</strong> The records that qualify only when combined are your hidden members. The records that qualify on both are your double sends.</li>
</ol>
<p>The result is two numbers you can defend: how many people the segment misses, and how many it counts twice.</p>
<h2>Households are not duplicates</h2>
<p>Be careful with step 4, because an address match sweeps up partners and housemates. They are separate people with separate orders, even though 5 of the 97 authors counted such relatives as duplicates.</p>
<p>Blending two people changes more than history. <a href="https://help.shopify.com/en/manual/customers/manage-customers">Shopify's Help Center</a> says one subscribed profile leaves the merged result subscribed, and that a merge has no way back. Confirm the two profiles are one person first.</p>
<p>The clearest public case in the question log we keep is a <a href="https://community.shopify.com/t/how-can-i-combine-multiple-customer-accounts/116276">Shopify Community thread</a> where customers held accounts under different emails, and a reward tier at $5,000 of spend broke because it needed one purchase history. That is one merchant's report, and I can't tell you what changed for that store afterwards.</p>
<h2>What to fix first</h2>
<p>We made one related call in our own app: a group of profiles counts as one person on a list while the group is active, even when Shopify would refuse to merge it. That is why I rank merging as one step among several, and not as the first.</p>
<p>Order the work by what the fix costs and what it protects.</p>
<ol>
<li><strong>Entry points.</strong> Request an address at the counter and double-check typed emails on forms, which slows new splits.</li>
<li><strong>Strong matches.</strong> Merge once phone, name and address agree and you have confirmed one person.</li>
<li><strong>Judgment groups.</strong> Go through the remainder by hand, leaving households alone.</li>
<li><strong>Exclusions.</strong> Shopify refuses some merges, such as past subscription contracts, so keep the older copy out of sends.</li>
<li><strong>Re-test.</strong> Run the one-hour test again and compare.</li>
</ol>
<h2>The takeaway</h2>
<p>A segment is only as good as its record of a person. Before tuning copy or timing, check whether the segment counts the right people. A split customer fails quietly, and the one-hour test makes the failure visible.</p>
<p>Go back to the shopper with two orders and two emails. An hour from now, you can know how many of them your segment is missing.</p>
<hr />
<p>Jimit Patel is a co-founder of <a href="https://www.trymergeguard.com">MergeGuard for Shopify</a>, an app that finds and merges duplicate customer profiles. He published a coded study of how merchants describe duplicate profiles.</p>
]]></content:encoded></item><item><title><![CDATA[Shopify customer segments in API 2026-10: store the query as versioned data]]></title><description><![CDATA[If your app creates, reads or edits Shopify customer segments through the GraphQL Admin API, version 2026-10 has a change you need to read before you move…]]></description><link>https://mergeguard-notes.hashnode.dev/shopify-customer-segments-in-api-2026-10-store-the-query-as-versioned-data</link><guid isPermaLink="true">https://mergeguard-notes.hashnode.dev/shopify-customer-segments-in-api-2026-10-store-the-query-as-versioned-data</guid><category><![CDATA[shopify]]></category><category><![CDATA[GraphQL]]></category><dc:creator><![CDATA[Jimit Patel]]></dc:creator><pubDate>Sun, 01 Nov 2026 11:41:39 GMT</pubDate><content:encoded><![CDATA[<p>If your app creates, reads or edits Shopify customer segments through the GraphQL Admin API, version 2026-10 has a change you need to read before you move to it. I will separate what Shopify has published from what I could not find, because the second list decides how careful you need to be.</p>
<h3>What the 2026-10 release notes say</h3>
<p>The <a href="https://shopify.dev/changelog/release-notes/2026-10">2026-10 release notes</a>, under Customers in the GraphQL Admin API, list a breaking change: segment query language functions now use <code>MATCHES</code> and <code>NOT MATCHES</code> instead of <code>= true</code> and <code>= false</code>. Function parameters take their own operators. The named dates <code>12_months_ago</code>, <code>90_days_ago</code>, <code>30_days_ago</code> and <code>7_days_ago</code> are deprecated, and the notes point to date offsets such as <code>-12m</code>. The linked <a href="https://shopify.dev/changelog/posts/updated-function-syntax-on-the-segment-query-language">changelog post</a> is dated October 1, 2026, is flagged Breaking API Change and Action required, and says the new syntax starts in API version 2026-10.</p>
<p>The post gives these conversions:</p>
<table>
<thead>
<tr>
<th>Before</th>
<th>From 2026-10</th>
</tr>
</thead>
<tbody><tr>
<td><code>products_purchased(quantity: 5) = true</code></td>
<td><code>products_purchased MATCHES (quantity = 5)</code></td>
</tr>
<tr>
<td><code>shopify_email.opened() = true</code></td>
<td><code>shopify_email.opened MATCHES ()</code></td>
</tr>
<tr>
<td><code>12_months_ago</code></td>
<td><code>-12m</code></td>
</tr>
</tbody></table>
<p>Because parameters now carry operators, the post notes that comparisons such as <code>!=</code> and <code>&gt;</code> become possible where they were not before. The <a href="https://shopify.dev/docs/api/shopifyql/segment-query-language-reference">segment query language reference</a> says function names are followed by <code>MATCHES</code> or <code>NOT MATCHES</code>, and calls the previous syntax deprecated. It also lists a limit of 250 segments and a limit on clauses in a grouped clause.</p>
<h3>How do Shopify customer segments change in API 2026-10?</h3>
<p>In API version 2026-10, segment query functions are written with <code>MATCHES</code> or <code>NOT MATCHES</code> and per-parameter operators instead of <code>= true</code> or <code>= false</code>. Shopify's changelog flags this as a breaking change that needs action. The named dates such as <code>30_days_ago</code> are deprecated in favour of offsets like <code>-30d</code>.</p>
<h3>What the notes do not say</h3>
<p>I read the release notes, the changelog post, the reference page and the <a href="https://shopify.dev/docs/api/admin-graphql/latest/objects/Segment">Segment object page</a>. None of them says:</p>
<ol>
<li>What happens to a segment already saved in a store. The reference page does not address existing segments when the syntax changes.</li>
<li>Whether a query in the old form is rejected, accepted or rewritten when you send it on 2026-10. The post says the new syntax starts in 2026-10, which is all it says.</li>
<li>Anything about a version number for the query syntax itself. The Segment object has <code>name</code>, <code>query</code>, <code>id</code>, <code>creationDate</code> and <code>lastEditDate</code>, and its page does not mention syntax versions.</li>
</ol>
<p>Shopify's <a href="https://shopify.dev/docs/api/usage/versioning">versioning page</a> says each stable version is supported for a minimum of 12 months and that a stable version is guaranteed not to change for its supported lifetime. It does not state outright that breaking changes only arrive in new versions, although that is the reading it supports. That is the basis for the method below, and it is an inference, not a Shopify promise about segments.</p>
<h3>Treat the query as data with a version, not as a string in your code</h3>
<p>These are my recommendations. Shopify does not prescribe them.</p>
<ol>
<li><strong>Store the API version next to every query string you save.</strong> A segment query written for 2026-07 and one written for 2026-10 can look alike and mean different things to a parser.</li>
<li><strong>Generate queries from a structure, not by pasting strings.</strong> Keep a small internal form such as "function purchased, parameter quantity, operator equals, value 5" and render it for each API version you support. The three conversions in the table above become three lines in one renderer.</li>
<li><strong>Keep one renderer per supported version.</strong> Shopify supports each stable version for at least 12 months, so for a while you will serve stores through two versions at once.</li>
<li><strong>Test against a development store before you flip the version.</strong> Create the segment with the new syntax, read its members, and compare the count with the old one. A count that moves tells you the change was not only cosmetic. I have not run this against 2026-10, so treat the comparison as a test you design, not a result I can report.</li>
<li><strong>Replace named dates now.</strong> The deprecation notice is the one part of the change that does not wait for you to upgrade.</li>
<li><strong>Log the exact query string you sent and the version header you got back.</strong> The versioning page describes a fallback: if you target a version you cannot access, Shopify responds with the oldest accessible stable version, and the <code>X-Shopify-API-Version</code> header will differ from the one you asked for. A query rendered for the wrong version is the failure you are guarding against.</li>
</ol>
<h3>A segment is a list of profiles</h3>
<p>A segment is, in Shopify's words, <a href="https://shopify.dev/docs/api/admin-graphql/latest/objects/Segment">a group of customers that meet specific criteria</a>, and the Shopify Help Center says <a href="https://help.shopify.com/en/manual/customers/customer-segmentation">customers are added or removed automatically</a> as they meet the rules. That answers a common question about the Customers section of the Shopify admin: the membership of a segment moves on its own, so a count you read yesterday is not a count you can reuse.</p>
<p>Membership is also counted in customer profiles. Shopify says <a href="https://help.shopify.com/en/manual/customers/manage-customers">each profile can have only one email address</a>, so a shopper who uses two addresses can sit in a segment twice. In a <a href="https://doi.org/10.5281/zenodo.23705270">study I published</a>, the most common cause among 97 authors who described one was a second or changed email address, named by 39 of them. Language models did the coding, and the thread was self-selected and mostly from 2020 to 2022, so read that as a reason to check, not as a rate. For an integration the practical point is small: a segment count is a count of profiles, so report it as that.</p>
<h3>Checklist before you upgrade to 2026-10</h3>
<ul>
<li>Every saved query has a stored API version.</li>
<li>A renderer exists for the old and the new function syntax.</li>
<li>Named dates are replaced with offsets.</li>
<li>A development store has run the new syntax, and the member count was compared.</li>
<li>Logs show the version header returned for each segment request.</li>
<li>The report that shows segment size says "profiles".</li>
</ul>
<hr />
<p><em>Jimit Patel is a co-founder of MergeGuard for Shopify, an app that finds and merges duplicate customer profiles. He published a study of 417 Shopify Community posts on how duplicates arise, coded by language models. Site:</em> <a href="https://www.trymergeguard.com"><em>https://www.trymergeguard.com</em></a></p>
]]></content:encoded></item></channel></rss>