Shopify Development

Mastering Shopify Metafields: Handling Blank Values in Liquid for Flawless JSON Events

Hey there, fellow store owners and developers! Ever found yourself pulling your hair out trying to get your Shopify Flow automations or custom integrations to send perfectly formatted JSON data, only to have it break when a metafield is left blank? You're definitely not alone. This is a super common hurdle, and it was the hot topic in a recent community discussion that really sparked some great insights.

At Shopping Cart Mover, we often help merchants migrate their stores and optimize their e-commerce operations. A crucial part of this optimization involves robust data handling, especially when integrating Shopify with external systems like CRM, marketing automation platforms, or analytics tools. One area where things can get tricky is when dealing with Shopify metafields in Liquid templates, particularly when those metafields might be empty or unset.

Our friend @ctevan kicked off a Shopify Community thread with a classic scenario: trying to include an optional "Eco advisor" metafield from Draft Orders in a Klaviyo event. The challenge? When that metafield was empty, the JSON payload would just… well, break. They wanted it to send "none" instead of nothing, but Liquid wasn't cooperating with their attempts like {% if getDraftOrderDataForeachitem.ecoAdvisor.value %} or checking for nil.

Shopify Flow automation flowchart with metafield check
Shopify Flow automation flowchart with metafield check

The Metafield Mystery: Why Empty Isn't Always 'False' in Liquid

This is where things get a little quirky with Liquid. As @One-Sun1995 wisely pointed out in the thread, an unset list metafield still comes back as an empty array. And here's the kicker: an empty array is actually considered "truthy" in Liquid. So, your {% if eco %} condition passes, but then there's nothing for your loop to iterate over, or it just outputs an empty string, leaving your JSON malformed. It's a subtle but critical distinction!

The key takeaway here is that for list metafields, you often need to check for the size. So, instead of just {% if eco %}, you'd want something like {% if eco and eco.size > 0 %}. This ensures you're not just checking if the metafield object exists, but if it actually contains any values.

Solution 1: Checking for Size in List Metafields

When dealing with list metafields (e.g., "list.single_line_text_field"), even if no values are added, the .value property will return an empty array []. In Liquid, an empty array is truthy. To correctly handle this, you need to check its size:

{% assign eco_advisors = getDraftOrderDataForeachitem.ecoAdvisor.value %}
"eco_advisor":{% if eco_advisors and eco_advisors.size > 0 %}"{{ eco_advisors | join: ', ' }}"{% else %}"none"{% endif %},

This snippet first assigns the metafield value to a variable eco_advisors. Then, it checks if eco_advisors exists and if its size is greater than 0. If both conditions are met, it joins the list items into a comma-separated string. Otherwise, it outputs "none".

Solution 2: The Universal `blank` Check for Any Metafield Type

For most other metafield types (single line text, integer, boolean, etc.), or even when you want a more general approach, the != blank operator is your best friend. As @Josh-FiveAcreCode brilliantly demonstrated, this is often the cleanest and most reliable way to check if a metafield has a value.

{% assign event_code = order.metafields.custom.event_code.value %}

{
  "order_id": {{ order.id | json }},
  "event_code":
  {% if event_code != blank %}
    {{ event_code | json }}
  {% else %}
    null
  {% endif %}
}

Here, event_code != blank correctly evaluates to true only if event_code contains a non-empty value. If it's empty, nil, or an empty string, it will be considered blank, and the else branch will execute.

The JSON Filter: Your Best Friend for Robust Payloads

One of the most valuable pieces of advice from the community thread, echoed by several contributors, is to always use the | json filter. This filter is an absolute lifesaver for ensuring your Liquid-generated JSON is valid and correctly escaped. Manually adding quotes (e.g., "{{ value }}") is prone to errors, especially if your metafield value contains special characters or quotes itself.

The | json filter automatically:

  • Adds necessary double quotes around string values.
  • Escapes any internal double quotes or special characters (like newlines).
  • Formats numbers and booleans correctly without quotes.

Compare these two approaches:

// Manual quoting (prone to errors)
"product_name": "{{ product.title }}"

// Using the json filter (recommended)
"product_name": {{ product.title | json }}

The | json filter ensures that if product.title was "Men's T-Shirt with "Cool" Design", the output would be "product_name": "Men's T-Shirt with "Cool" Design", which is valid JSON. Without it, you'd end up with "product_name": "Men's T-Shirt with "Cool" Design", which breaks the JSON structure.

Handling Blank Metafields: "None", `null`, or Omission?

When a metafield is blank, you have a few options for how it appears in your JSON. The best choice often depends on the requirements of the external system you're sending data to.

Option 1: Sending a String "none"

This was @ctevan's initial goal. It's useful if the receiving system expects a string placeholder.

{% assign eco_advisor_value = getDraftOrderDataForeachitem.ecoAdvisor.value %}
"eco_advisor": {% if eco_advisor_value != blank %}{{ eco_advisor_value | json }}{% else %}"none"{% endif %},

Remember to quote "none" if you want it to be a JSON string.

Option 2: Sending JSON `null`

Often, null is the semantically correct way to represent an absent or unknown value in JSON. Many APIs prefer this.

{% assign event_code = order.metafields.custom.event_code.value %}
"event_code":
{% if event_code != blank %}
  {{ event_code | json }}
{% else %}
  null
{% endif %}

Notice that null is written without quotes, as it's a JSON primitive, not a string.

Option 3: Completely Omitting the Field

Sometimes, if a value is absent, you might want to remove the field entirely from the JSON payload. This keeps your JSON cleaner and leaner.

{% assign event_code = order.metafields.custom.event_code.value %}

{
  "order_id": {{ order.id | json }}
  {% if event_code != blank %},
  "event_code": {{ event_code | json }}
  {% endif %}
}

This approach requires careful placement of the comma before the optional field. The comma should only be included if the field itself is included.

Best Practices for Robust Shopify Integrations

  • Always Use | json: Make it a habit for any value you output into JSON. It handles quoting and escaping automatically, preventing countless headaches.
  • Test All Scenarios: Always test your Liquid logic with metafields that are:
    • Set with a valid value.
    • Set but empty (e.g., an empty string for a text field, an empty array for a list field).
    • Completely unset.
  • Understand Liquid's Truthiness: Be aware that empty arrays and objects are truthy in Liquid. Use .size > 0 for lists and != blank for general checks.
  • Define Metafield Types Carefully: Choose the correct metafield type from the start (e.g., "single line text" vs. "list of single line text") to simplify your Liquid logic.
  • Consult API Documentation: When integrating with external services, always check their API documentation to understand how they expect missing or null values to be handled.

Conclusion

Mastering the nuances of Liquid when working with Shopify metafields and JSON is a critical skill for any developer or merchant building robust integrations. By understanding Liquid's truthiness, leveraging the powerful | json filter, and employing smart conditional logic, you can ensure your data payloads are always perfectly formed, preventing errors and streamlining your e-commerce operations.

Whether you're sending events to Klaviyo, syncing data with a CRM, or building custom applications, these techniques will save you time and frustration. For those looking to build a powerful and efficient online presence, remember that a solid foundation starts with understanding your platform. If you're considering starting a new Shopify store or migrating an existing one, get started with Shopify today and unlock its full potential for your business!

At Shopping Cart Mover, we specialize in making these complex migrations and integrations seamless. Don't let tricky Liquid logic hold back your Shopify success!

Share:

Use cases

Explore use cases

Agencies, store owners, enterprise — find the migration path that fits.

Explore use cases