Guide · No-app quote form

Shopify Request a Quote Without an App: Setup and Limitations

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.

ApproachSuitable useMain limitation
Product button linking to a contact pageFastest starting pointProduct details must be entered or passed to the form
Expandable form on the product pageSimple product-specific inquiriesQuote processing remains manual
Custom modal formStores that need an overlay designRequires focus management, keyboard support, and more testing
Custom quote backendUnusual workflows with development resourcesYou 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:

  1. Review the email and confirm the requested variant, quantity, customization, and destination.
  2. Check availability and prepare pricing, shipping, and delivery expectations.
  3. Send your offer and agree on any changes by email.
  4. Create a Shopify draft order with the correct customer, items, and agreed pricing.
  5. Send its invoice with a checkout link.
  6. 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.

RequirementThis no-app formWhat to verify in an app
Product-page request buttonIncludedPlacement and theme compatibility
Product contextTitle, ID, URL; typed specificationsAccurate variant and SKU capture
Multi-product requestNot includedQuote basket and quantity editing
Quote trackingManual inbox processStatuses, owners, and history
NegotiationEmail repliesRevised offers and acceptance records
PDF quoteCreate separatelyTemplates and document export
Follow-up remindersSeparate processTiming and automation controls
Order creationManual draft orderDraft-order or checkout integration
Price visibilitySeparate customizationWhere prices remain accessible
Data ownershipEmail recordsExport 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?
Yes. You can add a native contact form to a product template using Liquid. The form emails the request, and your team handles the sales process afterward.
Can customers submit a quote request without leaving the product page?
They can fill in the form on the product page. The native submission can reload or redirect the page and may involve an anti-spam challenge. This tutorial does not promise an AJAX submission without navigation.
Does a contact form create a Shopify draft order?
The example here does not. Your team creates the draft order after reviewing the request and agreeing on the details.
Can I keep Add to Cart and Request a Quote together?
Yes. That can suit a store offering standard purchases alongside custom or bulk inquiries. Explain when customers should use each option.
Can the form automatically capture the selected variant?
Yes, with additional theme-specific integration. The starter code asks for specifications instead. Reliable automatic capture must follow variant changes made after page load.
Do I need Shopify Plus for this form?
This approach uses a theme contact form rather than a Plus-only B2B checkout feature. You need a store with an Online Store theme that supports the implementation.
Is an app always better than custom code?
No. A simple form can meet a simple need. An app becomes useful when its workflow features save enough time or prevent enough errors to justify the cost and dependency.

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.

Selling on quotes?

Not sure quoting
is worth an app?

Nafeeur Rahman
Nafeeur Rahman
Founder

I usually reply within a business day.