---
title: "Targeting rules"
description: "Control which products show the quote button and which buyers can submit, using product-side and customer-side rules evaluated in priority order."
url: "https://www.quotway.com/docs/targeting/targeting-rules"
type: "documentation"
category: "targeting"
updated: "2026-06-20"
locale: "en"
source: "QuotWay - B2B Quote & Negotiation App for Shopify"
---

# 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:

1. Sort rules by `priority` ascending.
2. Walk the list. The first rule whose conditions match the product + buyer wins.
3. 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](../troubleshooting/common-issues.md).

---

## 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: ALL` and 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](../approvals/approval-workflows.md) - what happens AFTER a quote gets submitted.
- [Partial acceptance and split conversion](../converting-to-orders/partial-acceptance-and-split-conversion.md) - how acceptance interacts with conversion.
