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](https://businessdotczartodotcom.files.wordpress.com/2020/08/shopping-sale-price.png?w=920)
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: '&', '&' }}</title>
<link>{{ shop.url }}</link>
<description>{{ collection.description | strip_html | strip_newlines | replace: '&', '&' }}</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>
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
Name | Feed Update Script |
Feed Type | Scheduled Fetch |
File Name | google-update |
File Url | yourstoredomain.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.
23 replies on “Enhance Shopify’s Google Shopping feed”
Here is a question for you. Say I have one product with multiple variants, largely differentiated by color and quantity. I currently advertise on Googel Ads, but when I search only one of the products in that that master product shows up in searches. How might I have additional variants show up in the search results. Say I have White, Black, Blue, and Gray under one product. If I search for the product it might show the white product. How do I get it to show say white, blue and black and so on?
LikeLike
I have found that the code is not working for me. I just see my shop’s URL when I view the collection. Any ideas?
LikeLike
Did you add any products to the collection?
LikeLike
I’m an idiot. Thank you.
LikeLike
Has anyone noticed that the Item ID or SKU are now one and the same? I just noticed it in the Product Page in Google Merchant Center. Does anyone know how to make the default ID equal the SKU?
LikeLike
Hi Alex,
We are using 3rd party app to set the sale price. Google always disapprove the listings and the reason is Mismatched value (page crawl) [price]. Google mentioned the Price found on your site is different from the sale price that we set up by 3rd party app. Would you please advise how can we fix it?
Thanks,
Cher
LikeLike
You should use microdata on your product page that specifies “price” (your sale price) and “compare_at_price” (yout full price).
LikeLike
Hello Alex,
first of all, I want to thank you for your useful articles.
We are still fighting with the product images problem on Google and Facebook feed. What we want to achieve is to show our second product image as the main image.
Is there any option for how to set up showing the second product image as the main product image?
Thank you very much in advance for your help.
George
LikeLike
He George,
Sorry for the late reply. I don’t have a proven solution for you, but I think to accomplish this, you would need to setup a Merchant Center feed rule that overrides the primary image with the value of the second image. I’m not familiar with how arrays are handled by the feed rules engine, so you may need to write some regex to extract the image you want from the “additional_images” field.
Hope this helps.
Alex
LikeLike
Alex, thanks for the write up!
I really like the concept behind this approach as it gives me full control.
One flaw I believe, is that we can’t paginate by more than 50 items, while your code lists 1000. (https://shopify.dev/docs/themes/liquid/reference/tags/theme-tags/#paginate)
Unfortunately I believe this technique will only works for stores with less than 50 products, as I can’t think of a way to get the feed consumer to paginate.
Thank you for posting this, great stuff!
LikeLike
Hi Max,
Thanks for pointing this out. I mostly work with Shopify Plus stores, and I’ve never hit a pagination limit that I am aware of, so I assume Shopify Plus removes the pagination limit.
A possible workaround would be to create multiple feeds in Google Merchant centre, with ?page=2, ?page=3, etc… appended to each url. This becomes less and less of a viable workaround as the quantity of products increases.
Another workaround would be to create a separate feed for each of your product types / collections (keeping # of products below 50).
Best,
Alex
LikeLike
I’m getting an error on the merchant centre feed when its loading it in. Its says “delimiter detection failed”
“The column delimiter could not be automatically detected from your feed. To select a column delimiter, click edit next to your feed name in your account and select the correct option.”
What delimiters are used (tabs, space or pipe or something else)? These are the options you can set. I currently have autodetect which is failing.
LikeLike
Hi Mike,
The file is XML and doesn’t use delimiters. Check to make sure that there are no extra spaces or lines at the very beginning of the file, and that you have set the collection template properly for your collection (double check this by loading the url — there shouldn’t be any images showing up).
Alex
LikeLike
Hi Alex, I’m still having trouble getting the supplementary feed to work. I’m getting the following error:
Invalid attribute name:
“This attribute name is not allowed. It may contain punctuation or conflict with an official attribute.”
I’d give you a screenshot but I’m not sure this format allows that.
Properties
Input method:
Internal Upload
Total file size:
258.50 KB
Detected encoding:
UTF-8
Detected delimiter:
Tab (\t)
I have 4,744 items but zero matching.
Here’s my feed: https://axessorize.com.au/collections/google-update
Please let me know if you have a solution to this.
Regards,
Mike.
LikeLike
Hi Mike,
Sorry for the late reply.
On line 8 of your feed (when viewing source) I see a “}” character.
You probably have a mis-closed variable somewhere in your liquid, towards the start of the file (somewhere before the tag).
If you delete the extra character, I think you’ll be ok.
LikeLiked by 1 person
With Shopify’s Google integration, is it necessary to create your own feed as you have described above?
And if so, should I delete the Google integration and the feed created from that?
LikeLike
forget that…i see its a supplemental feed.
I am having difficulty locating the configuration section in Step 2. Are you able to help with that please?
(“located towards the top of your template file in the “configuration” section.)” – not sure where you are referring to.
LikeLike
This is on line 16 of the script, right after the line: {% comment %} Settings {% endcomment %}
LikeLike
This is really cool, 1 question. Would something like this app Im using be possible? Im interested at the Google product category feed-gpc-XXX setting my Google Product Category. What about settings all products to custom
clearing g:gtin-field + g:mpn-field and set g:identifier_exists-field to false?
Set g:id-field to variant sku ?
LikeLike
Hi Γιάννης Αθανασίου,
This post is specifically about using Shopify’s Shopping. Although similar techniques should in theory work to augment the feeds generated by other tools.
You can set all your products to custom, but then you’re not giving Google all the information it needs to properly serve your products. But it’s a solution if it’s your only option.
Best,
Alex
LikeLike
can’t your feed pull and include those options? google product category and all (clearing g:gtin-field + g:mpn-field and set g:identifier_exists-field to false Set g:id-field to variant sku)
LikeLike
Yes, you would just need to modify the feed code.
LikeLike
Could you please do it? I could pay you if needed. I have no idea about code. Thanks
LikeLike