Targeting rules
Read time: 5 minutes. Who it's for: Merchants narrowing who sees the quote button and who can submit a quote.
QuotWay separates product-side targeting ("which products show the quote button?") from customer-side targeting ("which buyers can submit?"). Both run as a chain of rules - each rule either allows or denies; the first matching rule wins.
The two scopes
| Scope | Asks | Default if no rule |
|---|---|---|
| PRODUCTS | "Should the quote button show on this product?" | Deny - button hidden. |
| CUSTOMERS | "Should this buyer be allowed to submit?" | Deny - submission rejected. |
The default is "deny-all" on purpose. If you have no rules, no buyer sees the button. Onboarding creates a baseline ALL_PRODUCTS + ALL_CUSTOMERS rule for you so you start out with the button visible to everyone.
Rule types
Product-side
- ALL_PRODUCTS - every product shows the button.
- COLLECTION - show only on products in a specific collection.
- PRODUCT_TAG - show only on products with a specific tag (e.g.,
wholesale). Supports ANY (match any tag) or ALL (match all tags). - PRODUCT_TYPE - match by Shopify product type.
- VENDOR - match by Shopify product vendor.
Customer-side
- ALL_CUSTOMERS - every buyer can submit.
- CUSTOMER_TAG - match by Shopify customer tag (e.g.,
vip). ANY or ALL. - CUSTOMER_SEGMENT - match by Shopify customer segment. Membership is resolved server-side against Shopify, so a segment stays authoritative rather than trusting anything the storefront sends.
- B2B_COMPANY - on B2B-capable stores (Professional and above). Match by company GID.
- COMPANY_LOCATION - on B2B-capable stores (Professional and above). Match by company location.
- GUEST - explicitly allow guest (logged-out) buyers.
Rule order + priority
Each rule has a priority (lower = higher priority). When QuotWay evaluates whether to show the button:
- Sort rules by
priorityascending. - Walk the list. The first rule whose conditions match the product + buyer wins.
- If no rule matches → deny.
Rules can be enabled (active) or disabled (preserved for later but ignored). The Targeting editor at /app/quote-button/targeting has toggles for both states.
Editing rules
The dedicated editor at /app/quote-button/targeting shows all rules across both scopes. Each row has:
- Name + scope badge (PRODUCTS / CUSTOMERS).
- Rule type.
- Conditions (e.g.,
tags: ["wholesale"], operator: ANY). - Enabled toggle.
- Priority.
Click any rule to open the condition editor.
Worked example - Wholesale-tagged products, B2B-tagged customers
Say you sell to wholesalers via specially-tagged products + you have a wholesale-customer tag on your trusted buyer customer accounts. You want the quote button to appear ONLY when both match.
Rules:
| # | Scope | Type | Conditions | Priority | Enabled |
|---|---|---|---|---|---|
| 1 | PRODUCTS | PRODUCT_TAG | tags: ["wholesale"], operator: ANY |
100 | ✓ |
| 2 | CUSTOMERS | CUSTOMER_TAG | tags: ["wholesale-customer"], operator: ANY |
100 | ✓ |
That's it. Two rules. The button shows when the product has the wholesale tag AND the buyer has the wholesale-customer tag.
Worked example - Guest buyers + tagged products
If you want even logged-out buyers to be able to submit quotes (common for first-touch B2B inquiries):
| # | Scope | Type | Conditions | Priority | Enabled |
|---|---|---|---|---|---|
| 1 | PRODUCTS | PRODUCT_TAG | tags: ["wholesale"], operator: ANY |
100 | ✓ |
| 2 | CUSTOMERS | GUEST | (none) | 100 | ✓ |
| 3 | CUSTOMERS | ALL_CUSTOMERS | (none) | 200 | ✓ |
Rule 2 explicitly allows guests; rule 3 catches logged-in customers.
Enforcement is server-side, not display-only
Button visibility is the display layer. It is not what stops an ineligible product being quoted.
When a quote is submitted, QuotWay re-runs the same rule evaluation on the server against your stored rules, and rejects the submission if any line isn't eligible. Two details make that check trustworthy:
- Client-supplied product attributes are replaced, not trusted. The storefront request carries each line's product type, vendor, tags and collections - values a crafted request could fabricate. Before evaluating, the server discards them and substitutes the authoritative values fetched from your Admin API. The same applies to customer tags, which are re-fetched rather than taken from the request.
- Any failure defaults to deny. If a product can't be resolved - or the Admin fetch fails entirely - the line is treated as ineligible rather than waved through.
Cart submissions are filtered before the drawer even opens: only quote-eligible lines are carried into the quote, so ineligible items are dropped rather than quietly quoted.
Two things worth knowing about scope. Eligibility is evaluated when the buyer submits, so a product excluded later doesn't retroactively close quotes that already exist. And a quote you create in the admin isn't eligibility-checked - you're choosing the products explicitly, so the rules that gate your storefront don't gate you.
This matters if your exclusions exist for an operational reason - repairs or exchanges that follow a different workflow, say - because it means an excluded product can't reach you through the storefront, however the request was made.
Performance + caching
Targeting rules are read on every storefront page load. To keep latency low, QuotWay caches the rule list per shop for 5 minutes.
- When you create / update / delete a rule, the cache invalidates immediately on that shop.
- The cache is in-memory per Vercel function instance, so traffic scales linearly without per-shop database hits.
You should NOT see stale rules in normal use. If you do, the debugging procedure is at Troubleshooting common issues.
Common gotchas
- Button doesn't show even though my product has the tag. Tag matching is case-sensitive ("wholesale" ≠ "Wholesale"). The Shopify catalog sometimes inconsistent casing on legacy tags - pick one casing and stick with it.
- PRODUCT_TAG rule with
operator: ALLand 2 tags - works on some products but not others. Verify that each product actually has BOTH tags. The operator must be exact-match-all. - B2B company rule doesn't match. Use the company GID (
gid://shopify/Company/12345), not the company name. The editor's autocomplete prevents this, but if you paste a name from elsewhere, the rule silently fails to match. - Rules from a deleted plan tier still show. Disabling a rule preserves it. Use the Delete action to remove it.
Related articles
- Approval workflows - what happens AFTER a quote gets submitted.
- Partial acceptance and split conversion - how acceptance interacts with conversion.
Besoin d'un coup de main ? L'équipe est là pour vous aider.