Next Commerce
ThemesGuides

Personalized Products Guide

Some products need customer input at the time of purchase — an engraving on a mug, a monogram on a bag, a gift message on a card. This information is captured as line item properties: name and value pairs attached to a cart line rather than to the product itself. No variant, SKU, or inventory is required for each possible value.

Add Property Inputs to the Product Template

Property inputs are named properties[<name>], where <name> is the label stored with the line. Add them inside the add-to-cart form alongside the fields generated by the cart_form tag.

The engraving label and input are the only addition to the add-to-cart form.

templates/catalogue/product.html
{% purchase_info_for_product request product as session %}
{% if session.availability.is_available_to_buy %}
    {% cart_form request product 'single' as cart_form %}
    <form id="add-to-cart" action="{% url 'cart:add' pk=product.pk %}" method="post">
        {% csrf_token %}
        {% include "partials/form_fields.html" with form=cart_form %}
        <label for="engraving">Engraving</label>
        <input type="text" id="engraving" name="properties[Engraving]">
        <button type="submit">{% t "store.catalogue.add_to_cart" %}</button>
    </form>
{% else %}
    {% t "store.catalogue.out_of_stock" %}
{% endif %}

Add one input per property. A mug with an engraving and a font choice uses properties[Engraving] and properties[Font].

Display Properties in the Cart

The cart template receives a formset of cart line forms. Each form.instance is a line with a properties list of key and value pairs.

partials/cart_line_properties.html
{% for property in properties %}
    {% if property.value %}
        <div>{{ property.key }}: {{ property.value }}</div>
    {% endif %}
{% endfor %}
templates/cart.html
{% for form in formset %}
    {% with line=form.instance %}
        {% include "partials/cart_line_properties.html" with properties=line.properties %}
    {% endwith %}
{% endfor %}

Themes that ship their own side cart JavaScript need to render properties there too. Request properties { key value } on the cart lines in your side cart query and output them alongside the product title.

Behavior to Expect

BehaviorDetail
Unique linesThe same product added with different property values creates a separate cart line for each combination. Adding it again with identical values increases the quantity of the existing line.
Empty valuesA property submitted with an empty value does not create a separate line. It is still recorded on the line, so guard your display with {% if property.value %}.
Hidden propertiesProperty names starting with an underscore, such as properties[_source], are stored but excluded from line.properties and from the Storefront GraphQL API. Use them for data that should not be shown to customers.
Value lengthValues longer than 500 characters are truncated to 500 characters.
CheckboxesWhen a checkbox named properties[...] changes, the value submitted is yes or no.
File uploadsFile inputs are not supported. Inputs with type="file" are ignored.
Set onceProperties are captured when the line is added to the cart. There is no update path for changing them afterwards.

Add Properties with the Storefront GraphQL API

Themes that add to the cart through the Storefront GraphQL API pass properties on each line as a JSON object of name and value pairs. The field is available on createCart and addCartLines, and is returned on cart lines as properties { key value }.

addCartLines Variables
{
  "input": {
    "cartId": "<cart-id>",
    "lines": [
      {
        "productPk": 1,
        "quantity": 1,
        "properties": { "Engraving": "Alex" }
      }
    ]
  }
}

properties must be a JSON object. Any other value returns the error Properties must be a JSON object.

On this page