Categories
Digital Marketing Google Ads Shopify Shopping

Enhance Shopify’s Google Shopping feed

The following script will allow you to enhance Shopify’s Google Shopping app feed to include:

  • Additional Images by Variant: More control over which product images get associated with which variant.
  • Exclude Out of Stock items from Google Programs. If you are paying to advertise, make sure you are only paying to display products you can sell.
  • Exclude Low Stock variants from Google Programs. Exclude color ways that have low size options. Show other color options or products instead.
  • GTIN: Optionally set GTIN to be your barcode value
Sale annotation in Google Shopping
SALE labels and price markdown annotations usually only appear if you provide Google Shopping with both your regular price (compare_at_price) and your sale price.

To add the above functionality, you must create and upload a supplemental data feed to Google Merchant Center.

Step 1
Create a Supplemental Data Feed in Shopify

The first step is to create a data feed in Shopify. We can accomplish this by creating a custom Shopify Collection Template that will output XML data instead of HTML:

1. Create a new Collection Template called collection.google-update.liquid with the following code:

{% layout none %}<?xml version="1.0"?>
<rss xmlns:g="http://base.google.com/ns/1.0" version="2.0">

{% comment %}
Google Shopping / Merchant Center + Shopify Product Update Feed by Alex Czartoryski
https://business.czarto.com/2020/10/14/enhance-shopify-google-shopping/

This version: Aug 30, 2022
The latest version of this script available here:
https://github.com/Czarto/ShopifyScripts/blob/master/Templates/collection.google-feed-update.liquid

TODO: Test & handle products without variants
TODO: Test & hanlde products without color
TODO: Specify Sizes to never exclude. eg: Women's 7,8
{% endcomment %}

{% comment %} Settings {% endcomment %}
{%- assign exclude_unavailable_variants = true -%}
{%- assign exclude_variant_colors_with_limited_availability = false -%}
{%- assign ignore_x_smallest_sizes = 1 -%}
{%- assign ignore_x_largest_sizes = 1 -%}
{%- assign minimum_percentage_availability = 50 -%}
{%- assign filter_variantImages_byColor = false -%}
{%- assign use_barcode_as_gtin = false -%}

{%- comment -%}
TODO: Move this into a snippet and use capture to assign the variable
{%- endcomment -%}}
{%- case shop.currency -%}
{%- when 'USD' -%}{%- assign CountryCode = 'US' -%}
{%- when 'CAD' -%}{%- assign CountryCode = 'CA' -%}
{%- when 'GBP' -%}{%- assign CountryCode = 'GB' -%}
{%- when 'AUD' -%}{%- assign CountryCode = 'AU' -%}
{%- else -%}{%- assign CountryCode = 'US' -%}
{%- endcase -%}

<channel>
<title>{{ shop.name }} {{ collection.title | strip_html | strip_newlines | replace: '&', '&amp;' }}</title>
<link>{{ shop.url }}</link>
<description>{{ collection.description | strip_html | strip_newlines | replace: '&', '&amp;' }}</description>

{%- paginate collection.products by 1000 -%}
{%- for product in collection.products -%}

    {%- comment -%} Get color option {%- endcomment -%}
    {%- for option in product.options -%}
      {%- if option == 'Color' -%}{% capture option_color %}option{{ forloop.index }}{% endcapture %}{%- endif -%}
    {%- endfor -%}

    {%- comment -%} Make a list of Colors to exclude {%- endcomment -%}
    {%- assign colors_to_exclude = "" -%}
    {%- if exclude_variant_colors_with_limited_availability -%}
        {%- for color in product.options_by_name['Color'].values -%}
            {%- assign variants = product.variants | where: option_color, color -%}
            {%- assign variants_to_process_count = variants.size | minus:ignore_x_smallest_sizes | minus:ignore_x_largest_sizes -%}
            {%- assign available_count = 0 -%}
            {%- assign total_processed_count = 0 -%}
            {%- for variant in variants offset:ignore_x_smallest_sizes limit:variants_to_process_count -%}
                {%- assign total_processed_count = total_processed_count | plus:1 -%}
                {%- if variant.available -%}{%- assign available_count = available_count | plus:1 -%}{%- endif -%}
            {%- endfor -%}
            {%- if total_processed_count == 0 -%}
              {%- continue -%}
            {%- endif -%}
            {%- assign percentage_availability = available_count | times: 100.0 | divided_by: total_processed_count | round -%}
            {%- if percentage_availability < minimum_percentage_availability -%}
            {% capture colors_to_exclude %}{{colors_to_exclude}}#{{ color }}{%endcapture%}
            {%- endif -%}
        {%- endfor -%}
        {%- assign colors_to_exclude = colors_to_exclude | split: "#" -%}
    {%- endif -%}

    {%- for variant in product.variants -%}
<item>
    <g:item_group_id>shopify_{{ CountryCode }}_{{ product.id }}</g:item_group_id>
    <g:id>shopify_{{ CountryCode }}_{{ product.id }}_{{ variant.id }}</g:id>
    <g:mpn>{{ variant.sku }}</g:mpn>
    <g:barcode>{{ variant.barcode }}</g:barcode>
    {% if use_barcode_as_gtin %}<g:gtin>{{ variant.barcode }}</g:gtin>{% endif %}

    {%- comment -%} Additional Images by Color {%- endcomment -%}
    {%- assign additional_images = product.images -%}
    {%- for option in product.options -%}
    {%- if option == 'Color' -%}{% capture variant_color %}{{ variant.options[forloop.index0] }}{% endcapture %}{%- endif -%}
    {%- endfor -%}
    {% if filter_variantImages_byColor %}{% assign additional_images = product.images | where: "alt", variant_color | sort: 'attached_to_variant' | reverse%}{% endif %}
    {% if additional_images.size > 1 %}{%- for image in additional_images offset:1 limit:10 -%}
    <g:additional_image_link>https:{{ image.src | product_img_url: 'master' }}</g:additional_image_link>
    {% endfor %}{% endif %}

    {%- comment -%} Exclude Out of Stock Variants {%- endcomment -%}
    {% if exclude_unavailable_variants and variant.available == false %}
    <g:pause>ads</g:pause>
    {% elsif exclude_variant_colors_with_limited_availability and colors_to_exclude contains variant_color %}
    <g:pause>ads</g:pause>
    {% endif %}
</item>

  {% endfor %}
{% endfor %}
{% endpaginate %}
</channel>
</rss>

Available on github here

2. Create a new collection called “google-update” and choose google-update as your collection template.

3. Preview the collection and copy the url. Your url should look something like this: yourstoredomain.com/collections/google-update

Step 2
Configure your Feed

There are a few options you can configure in your feed, all located towards the top of your template file in the “configuration” section.

Exclude Out of Stock Variants
exclude_unavailable_variants

true
Exclude Limited Stock Color Variants
exclude_variant_colors_with_limited_availability
ignore_x_smallest_sizes
ignore_x_largest_sizes
minimum_percentage_availability

false
1
1
50
Filter Variant Images by Color + Alt Text Matching
filter_variantImages_byColor

false
Set GTIN to Variant’s Barcode Value
use_barcode_as_gtin

false

Exclude Out of Stock Variants

exclude_unavailable_variants = true

By default, any variants that are out of stock will be excluded from Google Shopping, Google Shopping Actions, and Dynamic Remarketing. Change the value of exclude_unavailable_variants = false if you want to disable this behaviour.

Exclude Limited Stock Color Variants

exclude_variant_colors_with_limited_availability = true

This setting is intended for apparel products, where you may have many colors of a product, but limited sizes available in a specific product. Setting this value to true will cause the script to attempt to exclude the colors with low availability (so that alternative colors or products can show instead).

There are a few additional configuration items for this setting that you can change:

minimum_percentage_availability
default = 50
Minimum % of sizes available before all variants of this color are excluded.
ignore_x_smallest_sizes
default = 1
Ignore the x smallest sizes in the % available calculation
ignore_x_largest_sizes
default = 1
Ignore the x largest sizes in the % available calculation

Filter Variant Images by Color
and Alt Text Matching

filter_variantImages_byColor = true

Setting this value to true will assign additional images to the current variant where the image’s Alt Text matches the variant’s color. Note that the primary variant’s image will always be included in the feed regardless of Alt text.

Set GTIN to Variant’s Barcode Value

use_barcode_as_gtin = true

Setting this value to true will assign your barcode value to GTIN. If you would like the option to set a different value than Barcode, it should be pretty straightforward to edit the code.

Step 3
Add a Supplemental Data Feed in Google Merchant Center

1. Open Merchant Center and go to
Products > Feeds > Supplemental Feeds > Add Supplemental Feed

NameFeed Update Script
Feed TypeScheduled Fetch
File Namegoogle-update
File Urlyourstoredomain.com/collections/google-update

Leave everything else as default values and click Continue

2. Make sure there’s a checkmark beside Content API and click Create Feed

3. You should now see your newly created feed in the Supplemental Feeds section. Click on your feed’s name and then click on Fetch Now to update your product data now.

Testing

It may take up to 30 minutes for your main feed to be updated. It is a good idea to review your products and feed to ensure that everything is coming through as expected, and tweak as required.

If everything looks good, your new sale pricing, variant images, and program availability should now be updated once per day.

Related Reading

Categories
Digital Marketing Google Ads Shopify Shopping

Add Sale Price to Shopify’s Google Shopping feed

DEPRECATED: As of at least Aug 30, 2022, the defautlt Google sales channel properly sends the product’s sale price to Google. This post and code are no longer being maintained, and are here only for reference.

Sale annotation in Google Shopping
SALE labels and price markdown annotations usually only appear if you provide Google Shopping with both your regular price (compare_at_price) and your sale price.

Create a Price Feed in Shopify

The first step is to create a data feed in Shopify containing your products sale and regular prices. We can accomplish this by creating a custom Shopify Collection Template that will output XML data instead of HTML:

1. Create a new Collection Template

{% layout none %}<?xml version="1.0"?>
<rss xmlns:g="http://base.google.com/ns/1.0" version="2.0">
{% paginate collection.products by 1000 %}
{%- case shop.currency -%}
{%- when 'USD' -%}{%- assign CountryCode = 'US' -%}
{%- when 'CAD' -%}{%- assign CountryCode = 'CA' -%}
{%- when 'GBP' -%}{%- assign CountryCode = 'GB' -%}
{%- when 'AUD' -%}{%- assign CountryCode = 'AU' -%}
{%- else -%}{%- assign CountryCode = 'US' -%}
{%- endcase -%}
<channel>
<title>{{ shop.name }} {{ collection.title | strip_html | strip_newlines | replace: '&', '&amp;' }}</title>
<link>{{ shop.url }}</link>
<description>{{ collection.description | strip_html | strip_newlines | replace: '&', '&amp;' }}</description>
{% for product in collection.products %} 
  {% for variant in product.variants %}
    {%- if variant.compare_at_price > variant.price -%}
      {%- assign OnSale = true -%}
      {%- assign Price = variant.compare_at_price -%}
      {%- assign SalePrice = variant.price -%}
        <item>
            <g:item_group_id>shopify_{{ CountryCode }}_{{ product.id }}</g:item_group_id>
            <g:id>shopify_{{ CountryCode }}_{{ product.id }}_{{ variant.id }}</g:id>
            <g:price>{{ Price | money_without_currency }} {{ shop.currency }}</g:price>
            <g:sale_price>{{ SalePrice | money_without_currency }} {{ shop.currency }}</g:sale_price>
        </item>
    {%- endif -%}
{% endfor %}
{% endfor %}
</channel>
</rss>
{% endpaginate %}

Also available on github

2. Create a new collection called “google-feed-sale-price” based on your Collection Template

  • IMPORTANT Choose xml-pricing-feed as your collection template
  • Add products to the collection (or you can create an automatic collection with Compare At Price is Greater than 1)

3. Preview the collection and copy the url.

  • Your url should look something like this: yourstoredomain.com/collections/google-feed-sale-price
  • When you preview your page, it should look like a bunch of unformatted text on your page. If you see images, then you probably skipped the first bullet point in Step 2.

Add a Supplemental Data Feed in Google Merchant Center

4. Open Merchant Center and go to
Products > Feeds > Supplemental Feeds > Add Supplemental Feed

  • Name: Sale Pricing Update
  • Feed Type: Scheduled Fetch
  • File Name: google-feed-sale-price
  • File Url: yourstoredomain.com/collections/google-feed-sale-price

Leave everything else as default values and click Continue

5. Make sure there’s a checkmark beside Content API and click Create Feed

6. You should now see your newly created feed in the Supplemental Feeds section. Click on your feed’s name and then click on Fetch Now to update pricing data immediately.

Done

It may take up to 30 minutes for your main feed to be updated. Any new sale pricing will now be uploaded once per day.

Related Reading