How to Add a Gift Message Field to Shopify Product Pages

2026-10-21 · upselling

Gift messages are one of the cheapest ways to raise average order value on Shopify — a buyer adding "Happy birthday, Sam" to a $40 order is a buyer who doesn't need to visit a card shop. You don't need a paid app to collect that message. Shopify's line item properties feature lets you add a text field to any product form, store the message against the specific line item, and surface it in the cart, checkout, order admin, and notification emails. This guide walks through the exact Liquid edits, the CSS to make the field look native, and the checks most merchants skip.

Why Use Line Item Properties Instead of a Gift App

Line item properties are custom fields attached to a single variant in the cart. They travel with the product through checkout, appear on the order, and show up in the packing slip and confirmation email. For a gift message, that's exactly the right data model.

A gift app makes sense when you need gift wrapping SKUs with their own inventory, tiered pricing, or a dedicated gift-building flow. If all you need is a short note, an app adds a monthly fee (check current pricing for any app you're considering), a script tag on every page, and a dependency you'll have to migrate away from later.

Things line item properties do well:

The one limitation worth knowing up front: line item properties are text, not logic. You can't validate length or block emoji without custom JavaScript, and you can't conditionally hide the field based on a "this is a gift" checkbox without a small amount of JS. For most stores, a plain text area is enough.

Before You Start: Theme Access and a Backup

You need edit access to your theme's code. In Shopify admin, go to Online Store → Themes, click the three-dot menu on your live theme, and choose Edit code. If you're on a Shopify plan that supports it, use Duplicate first to create a backup copy — it takes ten seconds and saves an hour if something breaks.

Find the product form. In most themes (Dawn, Refresh, Sense, Craft, and the rest of Shopify's free OS 2.0 themes), the form lives in one of these:

Search the file for <form with action="/cart/add" or for the {% form 'product' %} tag. That's where the input goes. If your theme uses a JSON product template with a separate product-form.js, the markup is still in Liquid — the JS just handles variant changes.

Step 1: Add the Gift Message Input to Your Product Form

Inside the product form, after the variant selector and before the add-to-cart button, add this block:

{% if product.available %}
  <div class="gift-message-field">
    <label for="gift-message-{{ product.id }}">
      Gift message (optional)
    </label>
    <textarea
      id="gift-message-{{ product.id }}"
      name="properties[Gift message]"
      maxlength="200"
      rows="3"
      placeholder="Add a short note — we'll include it with the order."
    ></textarea>
    <p class="gift-message-hint">Up to 200 characters.</p>
  </div>
{% endif %}

Three details matter here:

  1. The name attribute must be properties[Your Label]. Whatever you put in the brackets becomes the property name shown in the cart and order. Use a clear label like Gift message — not properties[note], which reads poorly on packing slips.
  2. The id should be unique per product. If your theme renders related products with forms on the same page, a hardcoded id="gift-message" will break the label association.
  3. maxlength is enforced by the browser. It's not a security control, but it stops a customer pasting 4,000 characters into a field that will look terrible on a packing slip.

If you only want the field on certain products, wrap the block in a condition — for example, {% if product.tags contains 'giftable' %} — and tag the relevant products in admin.

Step 2: Style the Field So It Fits Your Theme

An unstyled <textarea> looks like a 1998 contact form. Add CSS that inherits your theme's input styling. In Dawn-based themes, inputs use CSS custom properties, so this will usually blend in:

.gift-message-field {
  margin: 1.5rem 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.gift-message-field label {
  font-size: 1.4rem;
  font-weight: 600;
}

.gift-message-field textarea {
  width: 100%;
  padding: 1rem;
  border: 1px solid rgba(var(--color-foreground), 0.2);
  border-radius: var(--inputs-radius, 4px);
  font-family: inherit;
  font-size: 1.4rem;
  resize: vertical;
}

.gift-message-hint {
  font-size: 1.2rem;
  opacity: 0.7;
  margin: 0;
}

Put this in your theme's base.css or component-form.css, or in Theme settings → Custom CSS if your theme exposes it. Check the field on mobile — a textarea that's 100% wide with 1rem padding is fine, but the label can wrap awkwardly on narrow screens if your font size is large.

If your theme has a "collapsible" pattern for optional fields (Dawn uses <details> for things like gift wrapping notes), consider wrapping the field in one so it doesn't compete visually with the variant picker. That's a judgment call based on how prominently you want to promote gifting.

Step 3: Confirm the Message Shows in the Cart and Checkout

Line item properties render in the cart automatically in most themes, but not always in a readable format. Add the product to the cart with a test message and check cart.liquid or sections/main-cart-items.liquid. If the property doesn't appear, add this inside the line item loop:

{% for property in item.properties %}
  {% if property.last != blank %}
    <p class="cart-item-property">
      <strong>{{ property.first }}:</strong> {{ property.last }}
    </p>
  {% endif %}
{% endfor %}

The property.last != blank check matters. Shopify stores a hidden _ prefix on properties you don't want shown — anything starting with an underscore is suppressed from the cart and checkout display. If you ever need to store internal data (a timestamp, a source flag), prefix the name with _.

On checkout, line item properties appear under the product name in the order summary. You don't need to configure anything. If you're on Shopify Plus and using checkout extensibility, verify the property is visible in your custom checkout blocks before launch.

Step 4: Display Gift Messages in Orders and Emails

The message is already stored on the order line item, so the admin shows it under the product in the order detail view. For emails, edit Settings → Notifications → Order confirmation and add this near the line items loop:

{% for property in line.properties %}
  {% if property.last != blank %}
    <p><strong>{{ property.first }}:</strong> {{ property.last }}</p>
  {% endif %}
{% endfor %}

Repeat for New order (your internal notification), Shipping confirmation, and the packing slip template. The packing slip is the one people forget — a gift message that never reaches the warehouse is a gift message that never reaches the recipient.

If you use a fulfillment app or 3PL, check whether it reads line item properties. Most do, but some map only SKU and quantity by default.

Optional: Capture a Cart-Level Gift Note with Cart Attributes

Sometimes the note applies to the whole order, not one product — "leave at the back door" or "this is a gift for the whole family." For that, use cart attributes instead of line item properties. Add this to sections/main-cart-footer.liquid or your cart form:

<p class="cart-attribute">
  <label for="gift-note">Order gift note (optional)</label>
  <textarea id="gift-note" name="attributes[Gift note]" rows="2"></textarea>
</p>

Cart attributes appear on the order under Additional details and are accessible in email templates as {{ attributes['Gift note'] }}. Use line item properties for per-product messages and cart attributes for order-wide notes. Mixing them up is the most common source of "the note didn't show up" support tickets.

Testing Checklist and Common Mistakes to Avoid

Run this before you announce gifting anywhere:

Common mistake What happens Fix
Using name="note" instead of properties[...] Message attaches to the whole order, not the line item Use properties[Gift message]
Forgetting the _ prefix on internal fields Internal data shows in cart and emails Prefix with _
Editing the live theme with no backup Hard to roll back a broken form Duplicate the theme first
Adding the field outside the <form> tag Message never submits Place inside {% form 'product' %}
Skipping the packing slip template Warehouse never sees the message Edit the packing slip notification
Hardcoded id on the textarea Labels break on pages with multiple forms Use {{ product.id }} in the id

One more: if your theme uses an AJAX cart (Dawn does by default), the property submits fine, but the cart drawer may not refresh the property display until you update the JS that renders line items. Check assets/cart.js or assets/product-form.js for the rendering function if the message doesn't appear in the drawer.

Conclusion

Adding a gift message field to Shopify product pages is a 20-minute theme edit with no app subscription and no third-party script. Line item properties give you the right data model — per-product, visible everywhere from cart to packing slip — and a small amount of CSS keeps the field from looking bolted on. Do the test order before you launch, and update the packing slip template so the message actually reaches the box.

FAQ

Do I need a Shopify app to add a gift message field? No. Line item properties are a native Shopify feature and require only a Liquid edit to your product form. Apps are worth considering only if you need gift wrapping inventory, tiered gift pricing, or a dedicated gift-building flow.

Will the gift message show up on the customer's order confirmation email? Yes, once you add the property loop to your notification templates under Settings → Notifications. It's not always included by default, so check the Order confirmation, Shipping confirmation, and New order templates and add the loop where needed.

Can I make the gift message field required or limit it to certain products? You can limit it to products by wrapping the field in a tag or product-type condition, such as {% if product.tags contains 'giftable' %}. Making it required is harder — HTML required on a textarea will block add-to-cart, which is usually the opposite of what you want for an optional note. Use maxlength to cap length and let customers skip the field.