- Published on
How to Build a Trade Platform on Shopify Grow (Without Shopify B2B)
- Authors

- Name
- Steve Kibuika
- @kefoika
This guide explains how to implement a trade program for interior designers, architects, and other trade professionals using Shopify Grow and theme-native Liquid — no Shopify Plus B2B required.
If you are a merchant or developer looking to launch a designer/trade portal on a standard Shopify plan, this is a proven pattern you can adapt to your store.
What this pattern builds (and what it does not)
What you get: A lightweight, tag-based trade program that lets qualified professionals apply, submit documents, and shop a curated catalog at trade pricing.
What you do not get: Shopify's native B2B platform (available on Shopify Plus), which includes company accounts, B2B catalogs, payment terms, and quantity rules per company.
This approach works on Shopify Grow because it uses features available on all plans:
| Layer | Mechanism |
|---|---|
| Application | Native {% form 'create_customer' %} with hidden customer tag + note fields |
| Document upload | Shopify Forms app on a follow-up page |
| Access control | Customer tag (trade) checked in Liquid |
| Catalog | Product tag (Trade) filters collection grids |
| Display pricing | snippets/price.liquid shows discounted price with strikethrough retail |
| Checkout pricing | Automatic discount + customer segment (configured in Admin) |
| Trade home | Gated page at /pages/trade with custom landing content |
Architecture overview
flowchart LR
prospect[Prospect] --> applyPage["/pages/trade-application"]
applyPage --> createCustomer["create_customer form"]
createCustomer --> pendingTag["Tag: trade-pending"]
createCustomer --> docsPage["/pages/submit-trade-documents"]
docsPage --> formsApp[Shopify Forms]
adminReview[Admin review] --> approvedTag["Tag: trade"]
approvedTag --> tradeHome["/pages/trade"]
tradeHome --> catalog["Collections filtered by Trade product tag"]
catalog --> displayPrice["price.liquid 15% display"]
displayPrice --> checkout["Automatic discount at checkout"]
End-to-end flow:
- Prospect visits
/pages/trade-applicationand submits the trade application form. - Shopify creates a customer account tagged
trade-pending(recommended) with business details stored in the customer note. - Customer is redirected to
/pages/submit-trade-documentsto upload resale certificates and other files via Shopify Forms. - Admin reviews the application and uploaded documents in Shopify Admin.
- Admin removes
trade-pending, addstrade, and optionally marks the customer as tax-exempt. - Approved trade customer logs in, accesses
/pages/trade, browses trade-eligible products, sees trade display pricing, and receives the automatic discount at checkout.
Prerequisites
Before implementing this pattern, ensure you have:
- Shopify Grow (or any plan with customer accounts)
- Customer accounts enabled (Settings → Customer accounts)
- Shopify Forms app installed (free) for document collection
- Online Store 2.0 theme with section support (this guide uses a Dawn-based theme)
- Theme edit access (code editor or GitHub integration)
- Products tagged with
Tradefor trade-eligible SKUs
Optional but recommended:
- Customer segments for automatic discounts (Customers → Segments)
- Automatic discounts that target the trade customer segment
Page and template setup
Create three pages in Shopify Admin and assign the correct theme templates.
| Page handle | URL | Template suffix | Theme file |
|---|---|---|---|
trade-application | /pages/trade-application | trade | templates/page.trade.json |
submit-trade-documents | /pages/submit-trade-documents | Forms template | templates/page.Forms - Submit Trade documents.json |
trade | /pages/trade | trade-landing | templates/page.trade-landing.json |
Admin steps
- Go to Online Store → Pages → Add page.
- Create each page with the handle above.
- In the page sidebar, under Theme template, select the matching suffix (
trade,trade-landing, or the Forms template). - For the application page, the active section is
trade-application-form(configured inpage.trade.json).
The application template disables the default page and contact form sections, leaving only the trade application form:
{
"sections": {
"main": { "type": "main-page", "disabled": true },
"form": { "type": "contact-form", "disabled": true },
"trade_application_form_jWXtze": {
"type": "trade-application-form",
"settings": {
"heading": "Join Today",
"subheading": "Trade Program",
"top_cta_text": "Apply for Trade Access",
"contact_heading": "Apply for Trade Access",
"description": "<p>Join now or email <strong>trade@yourstore.com</strong> for more information</p>",
"submit_button_text": "Apply"
}
}
},
"order": ["main", "form", "trade_application_form_jWXtze"]
}
Add a Trade link to your main navigation menu pointing to /pages/trade-application for prospects, or /pages/trade for logged-in trade customers.
Trade application form
The application form lives in sections/trade-application-form.liquid and uses Shopify's native customer registration form. No third-party app is required for signup.
Custom form vs Shopify Forms
For the application step, Shopify Forms alone would work fine. You can collect business details and documents in a single Forms submission without building a custom theme section. That is the faster path if you want to ship quickly.
This implementation uses a custom create_customer form instead because it matches the application experience to the rest of the storefront — typography, spacing, benefit cards, and section layout all follow the theme's design system. The tradeoff is more theme code to maintain (trade-application-form.liquid + section-trade-application.css), in exchange for a branded, on-site application flow that creates a real customer account in one step.
A practical split that works well:
| Step | Recommended tool | Why |
|---|---|---|
| Application + account creation | Custom create_customer form (or Shopify Forms if speed matters more than branding) | Custom form creates the customer record and applies tags; Forms is simpler but does not register accounts natively |
| Document upload | Shopify Forms | Native file uploads; no reliable file handling in create_customer |
If you are starting from scratch and brand polish is not a priority, use Shopify Forms for both steps and manually create customer accounts after review. If the application page is a key conversion surface, the custom form is worth the extra work.
Core form structure
{%- form 'create_customer',
id: 'TradeApplicationForm',
class: 'trade-app-form',
return_to: '/pages/submit-trade-documents'
-%}
{%- if form.posted_successfully? -%}
<div class="trade-app-success">
<h3>Application Submitted</h3>
<p>Your account has been created! We will review your trade details and contact you shortly.</p>
</div>
{%- elsif form.errors -%}
<div class="trade-app-errors">
{{ form.errors | default_errors }}
</div>
{%- endif -%}
{%- comment -%}
Recommended: use trade-pending at signup, not trade.
Admin adds trade after review.
{%- endcomment -%}
<input type="hidden" name="customer[tags]" value="trade-pending">
{%- comment -%} Standard account fields {%- endcomment -%}
<input type="text" name="customer[first_name]" required>
<input type="text" name="customer[last_name]" required>
<input type="email" name="customer[email]" required>
<input type="password" name="customer[password]" required>
{%- endform -%}
Storing business data in customer notes
Shopify's create_customer form does not support custom metafields directly. Instead, use customer[note][Key] fields. Shopify serializes these into the customer's Note field in Admin, where your team can review them during approval.
<fieldset class="trade-app-fieldset">
<legend class="trade-app-legend">Company Details</legend>
<input type="text" name="customer[note][Company]" required>
<input type="url" name="customer[note][Website]" placeholder="https://">
<select name="customer[note][Business Type]" required>
<option value="Interior Designer">Interior Designer</option>
<option value="Architect">Architect</option>
<option value="Retailer">Retailer</option>
<option value="Hospitality">Hospitality</option>
<option value="Builder/Developer">Builder/Developer</option>
<option value="Other">Other</option>
</select>
<input type="text" name="customer[note][City]" required>
<input type="text" name="customer[note][State/Province]">
</fieldset>
<fieldset class="trade-app-fieldset">
<legend class="trade-app-legend">Business Details</legend>
<select name="customer[note][Annual Volume]">
<option value="Under $10,000">Under $10,000</option>
<option value="$10,000 - $50,000">$10,000 - $50,000</option>
<option value="$50,000 - $100,000">$50,000 - $100,000</option>
<option value="Over $100,000">Over $100,000</option>
</select>
<input type="text" name="customer[note][Tax ID]">
<input type="text" name="customer[note][Professional Membership ID]" placeholder="ASID, AIA, IIDA, etc.">
</fieldset>
<fieldset class="trade-app-fieldset">
<legend class="trade-app-legend">Additional Information</legend>
<textarea name="customer[note][Business Description]"></textarea>
<input type="checkbox" name="customer[note][Confirmed Business Account]" required>
<label>I confirm that I am applying for a business account, not a personal consumer account.</label>
<input type="checkbox" name="customer[accepts_marketing]" checked>
</fieldset>
Section schema and benefits blocks
The form section includes configurable benefit cards via blocks, so merchants can edit copy in the theme editor without touching code:
{
"name": "Trade Application Form",
"blocks": [
{
"type": "benefit",
"name": "Benefit Card",
"settings": [
{ "type": "text", "id": "title", "label": "Heading" },
{ "type": "textarea", "id": "text", "label": "Description" }
]
}
]
}
Styles are scoped in assets/section-trade-application.css.
Post-submit redirect
The return_to: '/pages/submit-trade-documents' parameter sends the customer to the document upload page immediately after successful registration — before they can browse the trade catalog.
Document upload step
Native Shopify customer forms do not support file uploads reliably. Use the Shopify Forms app for document collection (resale certificates, business licenses, etc.).
The document page template embeds the Forms app block and a "Proceed to Trade" button:
{
"sections": {
"forms": {
"type": "apps",
"blocks": {
"trade_docs_form": {
"type": "shopify://apps/forms/blocks/inline/8744a304-fcb1-4347-b211-bb6b4759a76a",
"settings": {
"form_id": "828092"
}
}
}
},
"rich_text_M69p4b": {
"type": "rich-text",
"blocks": {
"button_tNnTKK": {
"type": "button",
"settings": {
"button_label": "Proceed to Trade",
"button_link": "shopify://pages/trade"
}
}
}
}
}
}
Admin steps for Shopify Forms
- Install the Shopify Forms app from the App Store.
- Create a form with fields for resale certificate upload, business license, and any other required documents.
- Copy the form ID from the Forms app and paste it into the theme template's
form_idsetting. - Assign the Forms template to your
/pages/submit-trade-documentspage.
Note: The "Proceed to Trade" button links to
/pages/trade, which is gated. Pending applicants will be redirected back to the application page until approved — see the next section.
Gating the trade landing page
The trade landing page (/pages/trade) is the authenticated home for approved trade customers. Access is controlled by a lightweight gate section in sections/trade-landing.liquid:
{% comment %} Only approved trade customers may view this page {% endcomment %}
{% if customer and customer.tags contains 'trade' or request.design_mode %}
{% else %}
<script>
window.location.href = '/pages/trade-application';
</script>
{% endif %}
customer.tags contains 'trade'— allows only approved trade customers.request.design_mode— allows theme editor preview without logging in.- Non-trade and
trade-pendingcustomers are redirected to the application page.
The gate section has no visible content of its own. The actual landing page content (hero cards, collection links, etc.) is configured in templates/page.trade-landing.json using standard theme sections like hero-brand-cards-flex and multicolumn.
{
"sections": {
"main": { "type": "trade-landing", "settings": {} },
"hero_brand_cards_flex_RUA3CF": { "type": "hero-brand-cards-flex", "blocks": { } }
},
"order": ["main", "hero_brand_cards_flex_RUA3CF"]
}
Trade customer UX touches
Once approved, trade customers get a differentiated experience across the storefront.
Reusable trade customer check
Use this pattern anywhere you need trade-specific logic:
{%- liquid
assign is_trade_customer = false
if customer and customer.tags contains 'trade'
assign is_trade_customer = true
endif
-%}
Tip: Standardize on lowercase
tradefor the approved tag. Avoid checking bothtradeandTrade— pick one casing and use it consistently across all files.
Header logo links to trade home
In sections/header.liquid, trade customers clicking the logo go to /pages/trade instead of the retail homepage:
{%- liquid
assign is_trade_customer = false
if customer.tags contains 'trade'
assign is_trade_customer = true
endif
assign trade_url = '/pages/trade'
-%}
<a href="{% if is_trade_customer %}{{ trade_url }}{% else %}{{ routes.root_url }}{% endif %}"
class="header__heading-link">
{%- comment -%} Logo markup {%- endcomment -%}
</a>
Trade header banner
sections/trade-header-banner.liquid shows a persistent banner for logged-in trade customers. Mount it in your header group (sections/header-group.json):
{%- if customer.tags contains 'trade' or request.design_mode -%}
<div class="trade-banner">
<p class="trade-banner__text">{{ section.settings.text }}</p>
</div>
{%- endif -%}
Default banner text: "Trade Account Active". Height and copy are editable in the theme editor.
Account page label
In sections/main-account.liquid, trade customers see a distinct account title and type:
<h1 class="customer__title">
{% if customer.tags contains 'trade' %}
Trade Account
{% else %}
{{ 'customer.account.title' | t }}
{% endif %}
</h1>
{%- if customer.tags contains 'trade' -%}
<p>Account Type: <strong>Trade Account</strong></p>
{%- endif -%}
Trade catalog filtering
Trade customers should only see products eligible for trade pricing. Filter the collection product grid by a product tag.
In sections/main-collection-product-grid.liquid:
{%- liquid
assign is_trade_customer = false
if customer and customer.tags contains 'trade'
assign is_trade_customer = true
endif
-%}
{%- for product in collection.products -%}
{%- assign show_product = true -%}
{%- if is_trade_customer -%}
{%- unless product.tags contains 'Trade' -%}
{%- assign show_product = false -%}
{%- endunless -%}
{%- endif -%}
{%- if show_product -%}
{% render 'card-product', card_product: product %}
{%- endif -%}
{%- endfor -%}
Admin workflow for products
- Tag every trade-eligible product with
Tradein Admin (Products → [product] → Tags). - Retail customers see the full catalog (no filter applied).
- Approved trade customers see only products tagged
Trade.
Known gap: Search results (
sections/main-search.liquid) are not filtered by trade status. Trade customers using search may see non-trade products. Consider adding the same filter to search results as a follow-up.
Display pricing in the theme
Trade display pricing is handled in snippets/price.liquid, which is shared by product cards, product pages, and cart-adjacent UI.
Liquid logic
{%- liquid
assign is_trade_customer = false
if customer and customer.tags contains 'trade'
assign is_trade_customer = true
endif
assign trade_discounted_percentage = 0.85
-%}
<div class="price__regular">
{%- if is_trade_customer -%}
<span class="price-item price-item--regular h2">
{{- product.selected_or_first_available_variant.price
| times: trade_discounted_percentage
| money -}}
</span>
{%- endif -%}
<span class="price-item price-item--regular h2{% if is_trade_customer %} retail-price{% endif %}">
{{- product.selected_or_first_available_variant.price | money -}}
</span>
</div>
For a 15% trade discount, trade_discounted_percentage = 0.85 (customer pays 85% of retail).
Strikethrough retail price styling
In assets/component-price.css:
.price-item.retail-price {
opacity: 0.5;
text-decoration: line-through;
margin-left: 0.5rem;
}
Trade customers see the discounted price prominently, with the original retail price struck through beside it.
Critical: Display pricing is not checkout pricing. Liquid price math runs at render time on the storefront only. It does not change what Shopify charges at checkout. You must configure a matching automatic discount in Admin (next section) so the cart and checkout reflect the same 15% reduction.
Checkout pricing on Grow (Admin setup)
This is the step most merchants miss. Without it, trade customers see discounted prices on product pages but pay full retail at checkout.
Step 1: Create a customer segment
- Go to Customers → Segments → Create segment.
- Name it Trade Customers.
- Add condition: Customer tags → contains → trade.
- Save.
Step 2: Create an automatic discount
- Go to Discounts → Create discount → Amount off products (or Percentage).
- Set method to Automatic.
- Set value to 15% (matching your theme's
trade_discounted_percentage). - Under Customer eligibility, select Specific customer segments → Trade Customers.
- Set Applies to → All products (or limit to collections if needed).
- Configure combination rules (whether trade discount stacks with other promotions).
- Save and activate.
Step 3: Verify at checkout
- Log in as an approved trade customer (
tradetag, notrade-pending). - Add a product to cart.
- Confirm the automatic discount appears in cart and checkout.
- Confirm the discounted total matches what
price.liquiddisplayed on the product page.
Step 4: Tax exemption
For qualified resale transactions, mark the customer as tax-exempt in Admin:
- Go to Customers → [customer] → Manage.
- Under Tax settings, check Tax exempt.
- Save.
This aligns with the "Tax-Exempt Purchasing" benefit shown on the application page. Only enable this after reviewing the customer's resale certificate uploaded via Shopify Forms.
Recommended pending → approved workflow
A common launch mistake is applying the trade tag immediately on signup — before admin review. That gives anyone who completes the form instant trade access.
Use a pending → approved tag workflow instead:
| Stage | Customer tag | Access |
|---|---|---|
| Just applied | trade-pending | Can log in; cannot access /pages/trade or see trade pricing |
| Approved | trade | Full trade access, pricing, and catalog |
| Rejected | (remove trade-pending) | Standard retail experience |
Implementation change (one line in the form)
In sections/trade-application-form.liquid, change the hidden tag field:
{%- comment -%} Before (instant access — not recommended) {%- endcomment -%}
<input type="hidden" name="customer[tags]" value="trade">
{%- comment -%} After (pending until admin approval — recommended) {%- endcomment -%}
<input type="hidden" name="customer[tags]" value="trade-pending">
Ensure all Liquid checks use only trade (not trade-pending) for pricing, catalog filtering, and page gating. The snippets in this guide already follow that pattern.
Admin approval process
- Customer submits application → tagged
trade-pending, business data in customer note. - Customer uploads documents on
/pages/submit-trade-documents. - Admin receives notification (via Shopify Forms submission email or manual check).
- Admin reviews customer note fields and uploaded documents.
- If approved:
- Remove tag
trade-pending - Add tag
trade - Enable tax-exempt if resale certificate is valid
- Send approval email to customer
- Remove tag
- If rejected:
- Remove tag
trade-pending - Send rejection email with reason
- Remove tag
Optional: Shopify Flow automation
On Shopify Grow, you can use Shopify Flow (if available on your plan) to:
- Send an internal email when a customer is tagged
trade-pending - Send an approval email when
tradetag is added - Create a draft order task for high-volume applicants
Files reference checklist
Use this checklist when implementing or auditing the trade platform in your theme.
Dedicated trade files
| File | Purpose |
|---|---|
sections/trade-application-form.liquid | Application UI + create_customer form |
sections/trade-landing.liquid | Access gate for /pages/trade |
sections/trade-header-banner.liquid | "Trade Account Active" header banner |
assets/section-trade-application.css | Application form styles |
templates/page.trade.json | Application page template |
templates/page.trade-landing.json | Trade home page template |
templates/page.Forms - Submit Trade documents.json | Document upload page template |
Modified shared files
| File | Change |
|---|---|
snippets/price.liquid | Trade display pricing (15% off with strikethrough retail) |
assets/component-price.css | .retail-price strikethrough styling |
sections/main-collection-product-grid.liquid | Filter products by Trade tag for trade customers |
sections/header.liquid | Logo links trade customers to /pages/trade |
sections/header-group.json | Mounts trade header banner in header group |
sections/main-account.liquid | "Trade Account" label on account page |
Limitations and when to upgrade
Be upfront with your team and trade customers about what this pattern does and does not provide.
What this pattern does well
- Works on Shopify Grow without Plus
- No monthly app fees for core functionality
- Full control over application UX and branding
- Simple admin workflow using native Shopify customer tools
- Flat trade discount applied consistently at display and checkout
What this pattern does not provide
- Company accounts with multiple buyers under one business
- Per-SKU trade pricing (different discount rates per product or brand)
- Payment terms (Net 30, Net 60, purchase orders)
- Quantity price breaks per company
- Draft order workflows built into the storefront
- Automatic approval based on document verification
- Search filtering for trade catalog (not implemented — see catalog section)
When to upgrade to Shopify Plus B2B
Consider Shopify Plus B2B if you need:
- Multiple users per trade account (buyer, approver, admin roles)
- Custom catalogs and price lists per company
- Net payment terms and invoicing
- High trade order volume requiring automated workflows
- Integration with ERP or procurement systems
For a curated showroom with a flat trade discount and manual approval, the tag-based Grow pattern is sufficient and significantly simpler to maintain.
Testing checklist
Run through this checklist before launching or after any trade-related theme changes.
Application flow
- Visit
/pages/trade-applicationas a logged-out user — form renders correctly - Submit application with valid data — customer created in Admin
- Customer tagged
trade-pending(nottrade) after signup - Business fields appear in customer note in Admin
- Redirect to
/pages/submit-trade-documentsafter successful signup - Shopify Forms renders and accepts file upload
- Form validation errors display correctly (duplicate email, weak password, etc.)
Access control
-
trade-pendingcustomer redirected from/pages/tradeto application page - Logged-out user redirected from
/pages/tradeto application page - Approved trade customer can access
/pages/tradewithout redirect - Theme editor preview works (
request.design_modebypasses gate)
Trade customer experience
- Trade header banner visible for approved trade customer
- Logo links to
/pages/tradefor trade customer,/for retail customer - Account page shows "Trade Account" title and account type
- Collection pages show only products tagged
Trade - Product pages show discounted price with strikethrough retail
- Retail customer sees full catalog with no trade pricing
Checkout
- Automatic 15% discount applied at cart for approved trade customer
- Discounted cart total matches theme display price
- Retail customer receives no automatic trade discount
- Tax-exempt customer not charged tax after Admin tax exemption enabled
Edge cases
- Search results behavior documented (trade filter not applied — known gap)
- Customer with both
trade-pendingandtradetags — verifytradetakes precedence - Sale/compare-at pricing displays correctly alongside trade discount
Summary
Building a trade platform on Shopify Grow is achievable without Shopify Plus B2B. The pattern is:
- Apply with a native
create_customerform → tagtrade-pending+ business data in customer note - Upload docs with Shopify Forms on a follow-up page
- Review manually in Admin → swap tag to
trade - Gate the trade home page with a Liquid tag check
- Filter the catalog with a product tag (
Trade) - Display trade pricing in
price.liquid - Discount at checkout with an automatic discount tied to a customer segment
The theme handles the experience. Admin handles the business rules. Together they give trade professionals a portal that feels purpose-built — without the complexity or cost of Shopify Plus B2B.
This guide reflects a production Shopify theme implementation. Adapt page handles, discount rates, and form fields to your store.