Summary
- No app needed: Request a quote button using Shopify’s basic contact form.
- Get emails: The customer's request goes straight to your inbox.
- Make the sale: Agree on a price and create a Draft Order yourself.
If you just sell one Shopify B2B product at a time, this solution is fine. But if you sell many request a quote products, negotiate prices, or want automatic orders, you need a dedicated quote app.
This guide explains the setup, the work it leaves to your team, and how to decide whether an app is worth using.
What does a no-app Shopify quote form actually do?
A basic quote form collects an inquiry. It can ask for the buyer’s contact details, product requirements, quantity, and delivery location. Shopify supports a native Liquid contact form with custom fields. Shopify contact form documentation
The example in this guide sends an email. It does not automatically calculate a price, reserve inventory, create a quote record, or create an order.
For example, a buyer might request 200 printed tote bags delivered to Manchester. Your team still needs to check the printing requirements, stock, delivery cost, and lead time before replying with an offer.
What is the best way to add a quote button without an app?
For a simple product inquiry, I recommend a button-style disclosure that opens a form on the same product page. It keeps the product context visible and avoids sending the customer to a separate general contact page.
This is an implementation recommendation, not a claim that every store will convert better with it. Test it with your own customers.
| Approach | Suitable use | Main limitation |
|---|---|---|
| Product button linking to a contact page | Fastest starting point | Product details must be entered or passed to the form |
| Expandable form on the product page | Simple product-specific inquiries | Quote processing remains manual |
| Custom modal form | Stores that need an overlay design | Requires focus management, keyboard support, and more testing |
| Custom quote backend | Unusual workflows with development resources | You own development, hosting, security, and maintenance |
A standalone theme section is a practical starting point. It avoids depending on the internal markup of the theme’s purchase form. Placing the button directly beside Add to Cart requires theme-specific integration.
How to add a Request a Quote form to a Shopify product page
1. Work in a duplicate theme
In the theme editor, open Products → Create template, name it quote, and base it on your default product template. Online Store 2.0 uses product.quote.json; Liquid markup belongs in a section, not in that JSON file. Vintage themes need a theme-specific Liquid template adaptation. Shopify product templates.
Create a duplicate of your theme before editing it. Use its preview to check the form before publishing.
The example below is designed for a Shopify Online Store 2.0 product template that supports adding sections. It is not a headless storefront implementation.
If only some products need quotes, use a separate product template for those products. A change to the default product template can affect every product assigned to it.
2. Create a quote section
In your theme’s code editor, create a file in the Sections directory named product-quote-form.liquid and paste the following code.
This example deliberately asks customers to type the required variant or specifications. It does not pretend to stay synchronized with every theme’s variant picker. Product title, product ID, and product URL are included automatically.
{% if product != blank %}
{% assign quote_id = 'ProductQuote-' | append: section.id %}
<section id="{{ quote_id }}-wrapper" class="product-quote">
{% form 'contact', id: quote_id %}
<details {% if form.posted_successfully? or form.errors %}open{% endif %}>
<summary>Request a quote</summary>
<div class="product-quote__fields">
{% if form.posted_successfully? %}
<p role="status">Thank you. Your request has been sent.</p>
{% else %}
{% if form.errors %}
<div role="alert">{{ form.errors | default_errors }}</div>
{% endif %}
<p>Request a quote for <strong>{{ product.title | escape }}</strong>.</p>
<p>Tell us what you need. We will reply by email.</p>
<input type="hidden" name="contact[Request type]" value="Product quote">
<input type="hidden" name="contact[Product]" value="{{ product.title | escape }}">
<input type="hidden" name="contact[Product ID]" value="{{ product.id }}">
<input type="hidden" name="contact[Product URL]" value="{{ canonical_url | escape }}">
<label for="{{ quote_id }}-name">Name *</label>
<input id="{{ quote_id }}-name" name="contact[name]" type="text"
autocomplete="name" required value="{{ form.name | escape }}">
<label for="{{ quote_id }}-email">Email *</label>
<input id="{{ quote_id }}-email" name="contact[email]" type="email"
autocomplete="email" required value="{{ form.email | escape }}">
<label for="{{ quote_id }}-company">Company</label>
<input id="{{ quote_id }}-company" name="contact[Company]" type="text"
autocomplete="organization">
<label for="{{ quote_id }}-quantity">Quantity requested *</label>
<input id="{{ quote_id }}-quantity" name="contact[Quantity]" type="number"
min="1" step="1" required>
<label for="{{ quote_id }}-specs">Variant or specifications *</label>
<input id="{{ quote_id }}-specs" name="contact[Specifications]" type="text"
placeholder="Size, color, material, or N/A" required>
<label for="{{ quote_id }}-destination">Delivery country and postal code</label>
<input id="{{ quote_id }}-destination" name="contact[Delivery destination]"
type="text">
<label for="{{ quote_id }}-message">Project details *</label>
<textarea id="{{ quote_id }}-message" name="contact[body]" rows="5"
placeholder="Customization, delivery date, or other requirements"
required>{{ form.body | escape }}</textarea>
<p>Submitting this form requests a quote. It does not place an order.</p>
{% if shop.privacy_policy.url != blank %}
<p><a href="{{ shop.privacy_policy.url }}">Read our privacy policy</a></p>
{% endif %}
<button type="submit">Send quote request</button>
{% endif %}
</div>
</details>
{% endform %}
</section>
<style>
#{{ quote_id }}-wrapper { max-width: 760px; margin: 28px auto; padding: 0 20px; }
#{{ quote_id }}-wrapper summary,
#{{ quote_id }}-wrapper button {
padding: 14px 20px; border: 1px solid #222; border-radius: 6px;
background: #222; color: #fff; cursor: pointer; font: inherit;
}
#{{ quote_id }}-wrapper summary { width: fit-content; }
#{{ quote_id }}-wrapper .product-quote__fields {
display: grid; gap: 12px; margin-top: 20px;
}
#{{ quote_id }}-wrapper input:not([type="hidden"]),
#{{ quote_id }}-wrapper textarea {
width: 100%; box-sizing: border-box; padding: 12px;
border: 1px solid #777; border-radius: 4px;
background: #fff; color: #222; font: inherit;
}
#{{ quote_id }}-wrapper :focus-visible { outline: 3px solid #2367d1; outline-offset: 3px; }
</style>
{% endif %}
{% schema %}
{
"name": "Product quote form",
"tag": "div",
"enabled_on": { "templates": ["product"] },
"settings": [],
"presets": [{ "name": "Product quote form" }]
}
{% endschema %}
The disclosure uses native HTML and needs no custom JavaScript. The trigger looks like a button, but its HTML element is a summary, which opens the form inside details.
The Liquid form tag and contact[...] field naming follow Shopify’s documented contact-form mechanism. This is an original implementation example; it has not been tested in your store. Shopify contact form documentation
3. Add the section to your product template
Open the duplicate theme’s visual editor, select the product template, and choose Add section. Select Product quote form and place it beneath the main product information section. Save and preview.
This creates the button and form on the product page. It does not require a separate quote page.
Optional: hide the price and purchase buttons
On the quote template, hide or remove the Price and Buy buttons blocks if your theme supports it. Keep them if buyers should choose between buying and requesting a bulk quote. Do not comment out price or cart code globally in a shared main-product.liquid file: that can affect other templates too. If you need code changes, scope them to template.suffix == 'quote' and adapt them to the theme.
After testing and publishing the theme, open each intended product in Shopify admin and select quote under Theme template. The assignment list uses templates from the published theme; preview the duplicate before this step.
For a button beside the price or purchase controls, have a developer adapt the code to your theme’s product blocks. Never nest this contact form inside an existing product purchase form: nested HTML forms are invalid and can submit the wrong data.
4. Check where requests are delivered
Shopify sends native contact-form submissions to the store’s sender email address, configured in Notifications settings. Shopify also documents that the contact-form email subject cannot be customized. A field named Request type adds information to the message; it does not change the subject. Shopify contact-page help
5. Test the complete customer journey
Before publishing, check the following:
- Submit a request and confirm that the email arrives with the correct product and customer details.
- Submit invalid or missing required information and inspect the errors.
- Check the confirmation after submission and any anti-spam challenge.
- Test mobile layout, keyboard navigation, and the open/close control.
- Confirm that Add to Cart and accelerated checkout still work if you keep them.
- Check products with multiple variants and your other storefront languages.
- Check which custom fields need to be entered again after an unsuccessful submission.
This starter preserves the standard name, email, and message values where Shopify supplies them. It does not implement persistent recovery of every custom field. The integer quantity input assumes products sold in whole units; adapt it for fractional quantities.
How do you turn the request into an order?
A workable manual process is:
- Review the email and confirm the requested variant, quantity, customization, and destination.
- Check availability and prepare pricing, shipping, and delivery expectations.
- Send your offer and agree on any changes by email.
- Create a Shopify draft order with the correct customer, items, and agreed pricing.
- Send its invoice with a checkout link.
- Check payment and fulfillment status in Shopify.
Shopify draft orders support manual sales and invoices with secure checkout links. A paid draft becomes a regular order. The contact form in this tutorial does not automatically perform those steps. Shopify draft orders and invoices
What are the problems with a no-app quote form?
1. Email becomes your quote management system
This implementation has no quote dashboard, owner assignment, request number, or status history. As requests grow, it becomes easier to miss a reply or lose track of the latest offer.
A shared inbox and a spreadsheet can help, but someone must maintain them.
2. Product and variant details can be incomplete
A buyer might type “large blue” without enough information to identify the correct SKU. This tutorial intentionally uses a free-text specification field, so your team must verify it.
A more advanced implementation can capture variant IDs from the active product selection. That requires integration with the theme’s variant behavior, including changes made after the page loads. Reading an initial Liquid value alone does not guarantee that it stays current.
3. There is no multi-product quote basket
A single-product inquiry is manageable. A buyer requesting 20 different products needs a better way to collect products, variants, and quantities into one request.
You can build that yourself, but it is substantially more work than adding a contact form.
4. Negotiation has no structured record
Email works for a small number of revisions. More complicated deals may need versioned offers, line-item adjustments, attachments, an expiry date, and an acceptance history.
The starter form does not provide these features. Sending another email does not automatically update a structured quote record.
5. Creating draft orders takes time
You must transfer the agreed details into Shopify. Re-entering quantities, addresses, and prices creates opportunities for mistakes.
An integration can reduce this work, but it still needs careful handling of taxes, shipping, currency, stock, and pricing changes.
6. Follow-ups depend on your process
The form does not remind a salesperson to reply or contact a buyer who has gone quiet. You need a separate routine, task system, or automation.
7. Hiding a button is not purchase protection
Adding this form leaves the existing purchase options in place. That is useful when shoppers should be able to buy retail quantities or request a bulk quote.
For quote-only products, removing the visible Buy buttons block is a separate customization. Do not assume that hiding Add to Cart or a price with CSS prevents purchases or keeps pricing private. Check quick-add cards, sticky purchase controls, cart routes, product data, structured data, and other sales channels. Enforcement needs a solution appropriate to the store’s actual architecture.
8. Maintenance remains your responsibility
A standalone section reduces some coupling to the theme, but redesigns and theme migrations still need testing. You also own accessibility, translations, field changes, and troubleshooting.
Updates do not always erase custom code. Shopify can carry compatible changes forward, but conflicting edits may need to be reapplied. Keep a backup and check the updated theme before publishing. Shopify theme updates.
The absence of an app subscription does not mean the setup has no operating cost.
9. Email and spam handling need attention
Shopify analyzes the contact message field for spam and can mark suspicious messages with a spam prefix. Review filtering so legitimate requests are not overlooked. Shopify contact-page help
Adding a file input alone is also not a complete attachment solution. This tutorial does not include file uploads, storage, or attachment handling.
10. Submitted details are untrusted input
Customers can edit hidden fields and bypass browser validation. Check product IDs, specifications, and quantities against your catalog before making an offer. If you later automate pricing or order creation, validate those values in a trusted backend. Never put Shopify Admin API credentials in theme JavaScript.
Why use a third-party Shopify quote app?
You do not need an app just to display a button. The reason to consider one is the workflow after the customer submits the request.
Depending on the app and plan, a quote tool may provide a quote basket, request dashboard, notifications, quote documents, negotiations, reminders, and draft-order integration. Verify the exact features before choosing one; these are evaluation criteria, not features guaranteed by every quote app.
| Requirement | This no-app form | What to verify in an app |
|---|---|---|
| Product-page request button | Included | Placement and theme compatibility |
| Product context | Title, ID, URL; typed specifications | Accurate variant and SKU capture |
| Multi-product request | Not included | Quote basket and quantity editing |
| Quote tracking | Manual inbox process | Statuses, owners, and history |
| Negotiation | Email replies | Revised offers and acceptance records |
| PDF quote | Create separately | Templates and document export |
| Follow-up reminders | Separate process | Timing and automation controls |
| Order creation | Manual draft order | Draft-order or checkout integration |
| Price visibility | Separate customization | Where prices remain accessible |
| Data ownership | Email records | Export options and uninstall behavior |
Apps have trade-offs too: recurring fees, dependency on the provider, theme conflicts, feature limits, and possible storefront performance impact. Test the actual app in your theme and run a complete quote-to-payment journey before relying on it.
A custom backend is another option if your workflow is unusual and you have the resources to maintain it. You are not limited to either an inbox or a public app.
When is the no-app method enough?
Use it when requests are occasional, buyers usually ask about one product, and your team can reliably handle pricing and follow-ups by email.
Consider an app when requests involve many products, several people handle sales, customers frequently negotiate, or manual order creation delays replies.
There is no universal number of requests that makes an app necessary. Measure the work. For example, 30 requests per month taking 12 minutes of administration each equals six hours of work. This is an illustration, not a Shopify benchmark. Compare your actual time and error rate against the app’s cost and capabilities.
Will a Request a Quote button affect SEO?
The presence of a quote button does not, by itself, determine whether a product page can rank. Keep useful product descriptions, specifications, images, and internal links accessible.
If you remove public pricing, review the product’s structured data and any shopping feeds. Do not put a fake zero price in markup to represent “contact us for a quote.” Product search features have specific data requirements, so changing the offer information can affect eligibility. Organic indexing and product rich-result eligibility are different questions. Google product structured-data requirements
Frequently asked questions
Can I add Request a Quote to Shopify without an app?
Can customers submit a quote request without leaving the product page?
Does a contact form create a Shopify draft order?
Can I keep Add to Cart and Request a Quote together?
Can the form automatically capture the selected variant?
Do I need Shopify Plus for this form?
Is an app always better than custom code?
Choose the setup that matches your sales process
Start with a product-page form if collecting an inquiry is all you need. Move to a dedicated quote workflow when tracking, negotiation, and order preparation become difficult to manage manually.
For a wider explanation of quote workflows, read our Shopify Request a Quote guide.
Need to manage more than the initial inquiry? Explore DQ: B2B Request a Quote (RFQ) and compare its current workflow with the manual setup above.
Sources and implementation notes
References checked on 10 September 2026. The Liquid example has not been installed or submitted on a live Shopify store.
