Two-Tier B2B Pricing on Shopify Without Plus: The Customer-Segment Pattern
The B2B Pricing Problem on Regular Shopify
Shopify Plus has B2B Catalogs — a native price-list-per-customer system that handles wholesale pricing cleanly. If you are on Plus, use it. The rest of this article is irrelevant to you. For everyone else (most Shopify stores), you need a different pattern, because regular Shopify treats every product as having a single price visible to all customers.
The pattern that works on regular Shopify (Basic, Shopify, Advanced) is customer-segment-based pricing using metafields and tags. Every product carries a B2B price as a metafield. Customers who are approved for trade pricing get tagged with a specific tag (e.g., approved-contractor). The theme's price rendering logic checks the customer's tags and swaps in the B2B price if they qualify. From the customer's perspective, when they log in, prices change. That is the entire user-visible feature.
The Pricing Math
Before any code, you need to define your pricing math. The model we ship looks like this. Cost is the wholesale cost of the SKU. Retail price is cost × ~2.24 (a 56 percent margin). Contractor price is cost × ~2.16 (a 54 percent margin — about 3 percent below retail). Display compare-at price is the sale price ÷ 0.775, which makes everything appear ~22.5 percent off. The compare-at trick is a transparency play — every product anchors at a higher number, the customer sees they are saving money, and the math works out cleanly across the catalog.
Quantity breaks layer on top: -8 percent at 5 units, -15 percent at 25, -22 percent at 100. These are not customer-segment tied — anyone buying in volume gets them. The combination of customer segment (retail vs. contractor) and quantity breaks creates four pricing tiers: retail-small, retail-bulk, contractor-small, contractor-bulk. Define these explicitly. Document them. Make them deterministic from a single cost field via a Python script, so when costs change you regenerate the entire pricing CSV in one command.
Metafields and the Custom Price Snippet
Define a metafield namespace called pricing on the product object. Add fields: pricing.cost (decimal), pricing.b2b_price (decimal), pricing.qty_break_5, pricing.qty_break_25, pricing.qty_break_100. When you import products, populate these fields from your pricing CSV. The compare-at price uses Shopify's native compare_at_price field, set to retail price / 0.775.
In your theme, override snippets/price.liquid (or create a custom snippet your sections use). The logic: check if customer is logged in and has a trade tag. If yes, use product.metafields.pricing.b2b_price as the active price. Otherwise use product.price. Render the compare_at_price as a strikethrough. For quantity breaks, render a small price ladder underneath ("$X each at 5+, $Y each at 25+"). The whole thing is server-rendered Liquid, no JavaScript required for the pricing display.
Manual Contractor Approval Workflow
The reason customer tagging is the right gatekeeper: it is a human-in-the-loop approval. The contractor cannot self-grant trade pricing by clicking a checkbox at signup. They submit an application with their company name, business email, and (in our case) ESA licence number. The application goes to the admin's email. The admin verifies the licence number against the public ESA contractor directory. Then they tag the customer approved-contractor in the Shopify admin.
This sounds slow. It is slow. That is the feature. Trade pricing is genuinely lower than retail. If contractors could self-approve, every retail customer would claim trade pricing the moment they figured out the form. Manual approval is the friction that keeps the pricing tier meaningful. We have stores running this for years where the admin spends maybe ten minutes per week processing applications. The trust that approved contractors place in the brand is worth those ten minutes.
Public Pricing as a Competitive Moat
Most B2B-focused competitors in trade categories hide their pricing entirely. The customer has to apply, wait 24-72 hours, and only then sees what anything costs. This is supposed to feel exclusive. To the customer, it feels like a delay.
Public retail pricing wins the customer who has a bid due in four hours. Trade pricing for approved accounts protects the margin for committed contractors. This dual posture is structurally hard for competitors who built around private pricing — they would have to either drop their walled garden (and admit retail customers exist) or watch their addressable market migrate to stores that meet the customer where they are. The customer-segment pattern is what makes this dual posture feasible without splitting your store into two products.
What Breaks When You Are Not Careful
Three failure modes worth flagging. First, caching. If your storefront caches HTML aggressively, the cached page may include retail pricing for an authenticated contractor. Either disable HTML caching for authenticated users or render pricing client-side from a customer-aware fragment. We have seen this bug ship in production — contractors complain that they see retail pricing some of the time, depending on which CDN node they hit.
Second, the compare_at_price overriding sale state. If you set compare_at on every product, your CSS logic for "show strikethrough only when on sale" needs to gate explicitly on whether the price is actually below compare_at. We hit a real bug where every product showed a strikethrough with the same value as the active price, because the CSS was unconditional. Fixed at root cause by gating on a .price--on-sale class set only when active price is genuinely lower.
Third, quantity break display logic. Make sure your "X each at 5+" copy is generated from the actual metafield values, not hardcoded. When you regenerate the pricing CSV with new costs, the quantity break values change automatically. If your theme has hardcoded prices in the copy, every cost update silently lies to the customer.
Ready to put this into action?
We build the digital infrastructure that turns strategy into revenue. Let's talk about what DRTYLABS can do for your business.
Get in Touch