Categories
Facebook Ads Shopify

DIY Facebook Product Feed for Shopify

A free customizable DIY solution to create a Facebook Product Feed in Shopify using custom collection templates. Coding required.

WARNING! I am no longer updating / maintaining this code. It should still work but use at your own risk.

UPDATE Oct 10, 2019: I have switched to using the Shopify Facebook Marketing App to sync my product catalogs with Facebook. Although not perfect, it does the job well enough!

UPDATE Dec 11, 2019: Shopify Facebook Marketing App does not upload all product attributes (Product Type is missing). If you need these missing attributes, I have documented a way to upload the missing data via a custom xml feed.

Below is a free customizable DIY solution to create a Facebook Product Feed in Shopify.

  1. This is an advanced topic and assumes you have the required understanding of HTML/XML/Liquid, the Shopify Store Admin and Facebook Business Manager.
  2. There are several existing paid apps that allow you to do this without coding (Flexify and DataFeedWatch) and a free app (Facebook Marketing App by Shopify).

1. Install the Google Shopping Channel

Install Shopify’s free Google Shopping app. This will allow you to configure product properties such as Age Group, Gender, and Product Category.

2. Create an XML Collection Template

Create a custom collection template that will output your products as XML instead of HTML.

  • In the Shopify admin, go to Online Store > Themes > Action > Edit Code
  • Under Templates, choose Add a new Template
  • Choose collection from the drop down and name your template fb-product-feed

Paste the code below into your new template and click Save. (Best to copy the code from this link: Shopify Facebook Product Feed 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 -%}
{%- assign CountryCode = 'US' -%}
{%- if shop.currency == 'CAD' -%}{%- assign CountryCode = 'CA' -%}{%- endif -%}
{%- assign PriceAdjustment = 1.0 -%}
{%- assign PriceAdjustmentEffectiveDate =  '20181226T080000-0500/20190102T235900-0800' -%}

<channel>
<title>{{ shop.name }} {{ collection.title | replace: '&', '&' }}</title>
<link>{{ shop.url }}</link>
<description>{{ collection.description | strip_html }}</description>
{%- for product in collection.products -%} 
  {%- assign GoogleProductCategory = product.metafields.mm-google-shopping.google_product_category -%}
  {%- assign Gender = product.metafields.mm-google-shopping.gender -%}
  {%- assign AgeGroup = product.metafields.mm-google-shopping.age_group -%}
  {%- assign Color = "" -%}
  {%- assign Size = "" -%}

  {%- if product.variants.size > 0 -%}
  {%- for variant in product.variants -%}
    {%- for option in product.options -%}
  	  {%- if option == 'Color' -%}{% capture Color %}{{ variant.options[forloop.index0] }}{% endcapture %}
  	  {%- elsif option == 'Size' -%}{% capture Size %}{{ variant.options[forloop.index0] }}{% endcapture %}
  	  {%- endif -%}
    {%- endfor -%}

    {% comment %} Calculate Sales vs Base Pricing {% endcomment %} 
    {%- if variant.compare_at_price == blank -%}
      {%- assign BasePrice = variant.price -%}
    {%- else -%}
      {%- assign BasePrice = variant.compare_at_price -%}
    {%- endif -%}
    {%- assign SalePrice = variant.price | times: PriceAdjustment -%}

<item>
<title>{{ product.title | strip_html | strip_newlines | replace: '&', '&' }}{% unless product.title contains Color %} {{ Color | replace: '&', '&' }}{% endunless %}</title>
<link>{{ shop.url }}{{ variant.url }}</link>
<description>{{ product.title | strip_html | strip_newlines | replace: '&', '&' }} {{ variant.title | strip_html | strip_newlines | replace: '&', '&' }} {{ product.description | replace: '</', ' </' | strip_html | strip_newlines | replace: '&', '&' }}</description>
<g:google_product_category>{{ GoogleProductCategory | replace: '&', '&'  }}</g:google_product_category>
<g:item_group_id>{{ product.id }}</g:item_group_id>
<g:id>{{ variant.id }}</g:id>
<g:condition>new</g:condition>
<g:price>{{ BasePrice | money_without_currency }} {{ shop.currency }}</g:price>
{%- if SalePrice < BasePrice -%}<g:sale_price>{{ SalePrice  | money_without_currency }} {{ shop.currency }}</g:sale_price>{%-  endif -%}
{%- if PriceAdjustment < 1 -%}<g:sale_price_effective_date>{{ PriceAdjustmentEffectiveDate }}</g:sale_price_effective_date>{%- endif -%}
<g:availability>{% if variant.available %}in stock{% else %}out of stock{% endif %}</g:availability>
<g:image_link>http:{% if variant.image.src %}{{ variant.image.src | product_img_url: 'grande' }}{% else %}{{ product.featured_image.src | product_img_url: 'grande' }}{% endif %}</g:image_link>
<g:gtin>{{ variant.barcode }}</g:gtin>
<g:brand>{{ product.vendor }}</g:brand>
<g:mpn>{{ variant.sku }}</g:mpn>
<g:product_type>{{ product.type | replace: '&', '&' }}</g:product_type>
<g:age_group>{{ AgeGroup }}</g:age_group>
{% unless Color == "" %}<g:color>{{ Color | strip_html | strip_newlines | replace: '&', '&' }}</g:color>{% endunless %}
{% unless Size == "" %}<g:size>{{ Size | strip_html | strip_newlines | replace: '&', '&' }}</g:size><g:size_system>US</g:size_system>{% endunless %}
<g:gender>{{ Gender }}</g:gender>
<g:custom_label_0>{{ product.metafields.mm-google-shopping.custom_label_0 }}</g:custom_label_0>
<g:custom_label_1>{{ product.metafields.mm-google-shopping.custom_label_1 }}</g:custom_label_1>
<g:custom_label_2>{{ product.metafields.mm-google-shopping.custom_label_2 }}</g:custom_label_2>
<g:custom_label_3>{{ product.metafields.mm-google-shopping.custom_label_3 }}</g:custom_label_3>
<g:custom_label_4>{{ product.metafields.mm-google-shopping.custom_label_4 }}</g:custom_label_4>
<g:shipping_weight>{{ variant.weight | weight_with_unit }}</g:shipping_weight>
</item>

  {% endfor %}
  {% else %}

  {% comment %} Calculate Sales vs Base Pricing {% endcomment %} 
  {%- if product.compare_at_price_min == blank -%}
    {%- assign BasePrice = product.price -%}
  {%- else -%}
    {%- assign BasePrice = product.compare_at_price_min -%}
  {%- endif -%}
  {%- assign SalePrice = product.price | times: PriceAdjustment -%}

<item>
<title>{{ product.title | strip_html | strip_newlines | replace: '&', '&' }}</title>
<link>{{ shop.url }}{{ product.url }}</link>
<description>{{ product.title | strip_html | strip_newlines | replace: '&', '&' }} {{ product.description | replace: '</', ' </' | strip_html | strip_newlines | replace: '&', '&' }}</description>
<g:google_product_category>{{ GoogleProductCategory | replace: '&', '&'  }}</g:google_product_category>
<g:item_group_id>{{ product.id }}</g:item_group_id>
<g:id>{{ product.id }}</g:id>
<g:condition>new</g:condition>
<g:price>{{ BasePrice | money_without_currency }} {{ shop.currency }}</g:price>
{%- if SalePrice < BasePrice -%}<g:sale_price>{{ SalePrice  | money_without_currency }} {{ shop.currency }}</g:sale_price>{%-  endif -%}
{%- if PriceAdjustment < 1 -%}<g:sale_price_effective_date>{{ PriceAdjustmentEffectiveDate }}</g:sale_price_effective_date>{%- endif -%}
<g:availability>{% if product.available %}in stock{% else %}out of stock{% endif %}</g:availability>
<g:image_link>http:{{ product.featured_image.src | product_img_url: 'grande' }}</g:image_link>
<g:gtin>{{ product.barcode }}</g:gtin>
<g:brand>{{ product.vendor }}</g:brand>
<g:mpn>{{ product.sku }}</g:mpn>
<g:product_type>{{ product.type }}</g:product_type>
<g:age_group>{{ AgeGroup }}</g:age_group>
<g:gender>{{ Gender }}</g:gender>
<g:custom_label_0>{{ product.metafields.mm-google-shopping.custom_label_0 }}</g:custom_label_0>
<g:custom_label_1>{{ product.metafields.mm-google-shopping.custom_label_1 }}</g:custom_label_1>
<g:custom_label_2>{{ product.metafields.mm-google-shopping.custom_label_2 }}</g:custom_label_2>
<g:custom_label_3>{{ product.metafields.mm-google-shopping.custom_label_3 }}</g:custom_label_3>
<g:custom_label_4>{{ product.metafields.mm-google-shopping.custom_label_4 }}</g:custom_label_4>
<g:shipping_weight>{{ variant.weight | weight_with_unit }}</g:shipping_weight>
</item>
  {% endif %}
{% endfor %}
</channel>
</rss>
{% endpaginate %}

or Download from Github:  Shopify Facebook Product Feed Template

3. Assign products to your Feed

In Step 2 you created your feed template. Now you need to assign products to this feed:

  • In Shopify Admin, go to Products > Collections > Create Collection
  • Enter a Title: “Facebook Product Feed”
  • Add Products to the collection (either manually or using conditions)
  • IMPORTANT! Assign your feed TEMPLATE to this collection.
    In the bottom right column choose collection.fb-product-feed as the Theme Template.
  • Save and Preview the collection. You should see unformatted text on the screen. This is your Facebook feed.
  • Copy the url as you need it in the next step.

4. Upload your Feed to Facebook

  • In Facebook Business Manager go to Assets > Catalogs > Create Catalog.
  • Catalog Type: E-Commerce
  • Click Add ProductsUse Datafeed
  • Enter the feed collection url you copied in step 3 above. Leave the username & password blank. Choose a time for your daily upload to occur (early morning is usually a good time). Choose your currency.
  • Click Start Upload and wait for the feed to be fetched and processed.
  • Fix errors: If there are errors, go back, fix them, re-fetch, and keep doing so until the feed is error free. Sometimes it is necessary to delete and re-create your catalog in Facebook for some changes to appear.
  • If you have more than 1000 product variants, you will need to submit multiple feeds with a ?page=x querystring appended like so: http://mystore.myshopify.com/collections/facebook-product-feed?page=1 (This will send products 1-1000) and http://mystore.myshopify.com/collections/facebook-product-feed?page=2 (This will send products 1001-2000)

5. Prevent the Facebook Feed from Showing on your Store

Depending on how your store is setup, you may need to add some code to prevent your Facebook feed collection from showing up on your store. The exact way to do this may depend on your theme, but generally you will want to have an “unless” statement within the loop that displays your collections:

{% unless collection.title contains "Facebook" %}
... your collection code ...
{% endunless %}

Done!

You are now ready to setup your Dynamic Product Remarketing campaigns!

Related Posts

By Alex Czartoryski

Alex is the director of digital marketing for Manitobah Mukluks, Canada’s fastest growing footwear brand, where he helps the luxury winter boot manufacturer accelerate growth profitably via digital marketing. Alex has over 20 years experience in e-commerce and digital marketing.

23 replies on “DIY Facebook Product Feed for Shopify”

Hi Alex! When you say “The instructions and code below are no longer supported!” does it mean that the code doesn’t work anymore? We have a special case where our shop is multilingual and our products have both language like that: “frech title || english title”. We used your google product feed and customized it to create a feed for both language and it worked perfectly. So I’m wondering if this one is still good to start with for our facebook product feed?

Also, the code for the facebook feed and google feed seems pretty similar, do you know if we could use the same feed for both google and facebook or if that would break something?

Like

Hi Tommy,

So the code is no longer supported “by me”. It still works on Facebook. (And I actually use a very similar version of this code to upload missing product attributes — https://business.czarto.com/2019/12/11/update-your-shopify-facebook-product-feed-with-missing-attributes/ )

The main difference between the Facebook and Google templates are how the product Ids are formatted. Shopify tends to use the following format for product Id’s on Google: Shopify_US_{{ product.id}}_{variant.id}}; while on Facebook they only use the product.id or variant.id. Using the same feed for both would cause any built-in dynamic remarketing tags to stop working. **BUT** if you are not using Shopify’s Google Shopping app anyway, then you theoretically *should* be able to use the Facebook version of the feed to upload your products to Merchant center…

Best,
Alex

Like

Thank you for the information, this will be useful! And thanks a lot for providing this piece of code, I still have to make some modifications to make it work for our use case but it’s making my life a little easier!

Like

Hey Alex! Been using this for a couple years now, but for about the last month I started to get an invalid character error. Do you know what this could be or how to figure this out?

Like

Hi Anthony — My *guess* would be that it’s a product title or description that has a special character that isn’t allowed in XML. Best way to solve this, if you have a line number for the error, is to access the feed link in your web browser, do a view source, and go to the error line and see if there are any special characters there. Then it would be a case of either removing that character from the description or adding an extra Replace statement in the liquid.

Hope this helps!

Alex

Like

Hi Francisco,

Memory limits exceeded is likely that you have “too many” products to be included in a single file. One solution is to upgrade to Shopify Plus (which removes most limits). A cheaper solution is one or some of:

– Create multiple collections/feeds for each of your product categories
– Reduce the number in the “paginate collection.products by 1000” line at the top of the template script. Try reducing this to 100 and keep increasing until you get at a number that doesn’t give you the memory error. Then you will need to submit multiple versions of this feed with a &page=2, &page=3, etc… appended to the end of the url to access each page of products. Not ideal, but it’s a workaround.

Best,

Alex

Like

Hi Francisco,

It seems there’s no products showing up on page=2 — I suspect page 1 is getting all the products, and so page 2 is just blank. (FYI, if you do a “view source” on page 2, you will in fact see the xml code, just with no products listed)

Try reducing the pagination down until page 1 is displayed consistently.

Alex

Liked by 1 person

Hi Alex, first of all, thanks a lot !

Second, a little help.
When visiting the collections page I’m gettin Liquid error: Memory limits exceeded.
and then, when uploading the catalog, Facebook says that the file is unsupported. (the template is assigned to the collection).

Any ideas?
Thanks again

Like

Hi Francisco — Sorry for taking over 18 months to reply! 😦

The error is because you have too many products & variants. The work-arounds are to either (1) upgrade to Shopify Plus or (2) create multiple feeds with less products in each. (I don’t know exactly how many is “too many”) or (3) wait for Shopify to increase memory resources for non-plus merchants.

Unfortunately those are the only work-arounds I know of…

Like

Hi Tanner,

Although this script (and the Google Merchant Script) will run without the Shopify Google Shopping App, it relies on the app to properly set the Google Shopping Category, as well as Age and Gender properties. So if you don’t want to use the app, you will need to modify the script to assign these values in some other way (either hard-coded, or using an “if” statement)

Hope this helps?

Best,
Alex

Like

Alex this helps a ton.

I was reading through forums on people experiencing an issue involving variants and you mentioned here: https://ecommerce.shopify.com/c/shopify-discussion/t/problem-with-facebook-pixel-and-products-variants-352328

That if you land directly on the variant page, the Facebook Pixel Helper should show the variant ID, but for me it is not the case.

Shopify’s new Facebook Pixel integration should automatically be adding the variant shouldn’t it?

Like

Hi Tanner,

I’ve had issues with the default Shopify integration as well (I believe the implementation has changed several times over the past year). Currently I see the same behaviour — only the top product id is being passed to Facebook.

The work-around would be to add some custom event code to your product page to trigger an additional “viewcontent” event. I’ll try to implement this and post it as I have time (hopefully in the next couple of months).

Best,

Alex

Like

Hi Tanner,

I left a reply on the original shopify thread here: https://ecommerce.shopify.com/c/shopify-discussion/t/problem-with-facebook-pixel-and-products-variants-352328 but I’ll duplicate it here again:

You are correct — currently Shopify only fires the pixel with the product_group / product.id and NOT with the product / variant.id.

What you **could** do is fire another facebook event on your product page that sends the VariantId (like here: https://github.com/Czarto/ShopifyScripts/blob/master/snippets/facebook-remarketing.liquid )

HOWEVER, I’m not sure if this is a good idea, as you will now have double the product views, and double the add to cart events, etc… Which may lead to double attribution, and double the conversion value being sent to your Facebook business manager:

But, on the positive side, your dynamic product remarketing should show the correct image / product variant, which should lead to better performance.

It will all come down to if Facebook is smart enough to figure out that the product_group + product are actually the same thing and dedublicate it.

Long term, I think that you either have to wait for Shopify to update their implementation, or to NOT use the default Shopify implementation and make your own custom implementation…

Like

Hi Alex,

Thanks for getting back to me. I really appreciate it. This stuff is definitely testing my technical know how! I had been looking at various product feed management services as a solution the downside being that they are all quite expensive and could possibly be overkill?

Following on from your reply I also had a look and found a variety of apps (both free and paid) in the Shopify app store that seems to offer pretty powerful options when it comes to adding metafields. For instance…

https://apps.shopify.com/custom-fields-2

https://apps.shopify.com/metafields-editor

So with the metafields option am I correct in thinking that I could create additional metafields in order to create an alternate title and alternate product description and somehow configure it so that those fields did not display on my actual Shopify store but were used by the product feed instead of the standard title and product feed. I am not sure that the standard Google Shopping Shopify app that most stores use allows for this type of functionality?

Would really appreciate your advice on this one.

Like

Hi Scott,

A tool I would recommend trying first is the ShopifyFD Chrome Plugin: https://chrome.google.com/webstore/detail/shopifyfd-dashboard-tool/lffljkleilfpjlmcdnoaghhcbnemelge?hl=en

By default, MetaFields DO NOT show up on your store unless you explicitly want them to. So you would create 2 new metafields (You need to specify a “namespace” for them — like a top level category — I recommend you use the “google” namespace to keep things consistent with how the Google Shopping app work). Assuming you call the metafields google.title and google.description, you would just update the script code to use product.metafields.google.tilte and product.metafields.google.description (instead of product.title and product.description).

A bigger question for you to ask yourself: Is the extra effort and overhead worth the extra sales you are expecting to generate? Going this route means you will theoretically have to manage 3 sets of Titles and Descriptions (The public description, the SEO description, and then your custom Shopping descriptions). I’m not sure what your assumptions are about increased sales due to these optimizations, but I would crunch some numbers first to see if your sales volume supports the overhead of optimizing the descriptions. (Eg: Assume a 10% increase in sales — what does that come to over the period of a year).

Additionally, in my experience, product description does very little to influence Google Shopping sales (Titles **DO** have a big influence, but not descriptions): http://searchengineland.com/advanced-optimization-google-shopping-campaigns-224627 — and so I would consider just using the SEO description for this. (..and focus heavily on negative keywords in your PLA campaigns).

Hope some of this helps!

Like

Hi Scott,

I just realized that we are talking about the Facebook shopping feed and not the Google shopping feed. My previous comment was related to Google Shopping and not facebook (although all the metafields comments are still correct).

RE: Facebook – I assume you want to display the description in the product ads, and so need to make it shorter, etc… That makes sense. But I would again make the calculation of how much conversion lift you are expecting from a slightly better description, and if that’s worth the additional short & long term administrative overhead.

Like

Hi Alex, I am wanting the product descriptions for my products on Google Shopping and my Facebook Feed to be different from those on my Shopify store (basically optimised for these channels). Most of the apps I have come across ( the free Google Shopping Shopify app for instance) just pull the product descriptions directly from your Shopify store and don’t give you the option to edit/change them. Can you recommend a solution that would allow me to edit the product descriptions so they differ from those on my Shopify store?

Like

Hi Scott,

One option is to use the Shopify SEO Title and SEO Description for your feed’s description. But if you’re already using this for your actual SEO description, then that’s not an option.

The other option would be to use a custom Shopify MetaField to store a third description for each product. There are various metafield editor apps available, as well as a Chrome extension that will allow you to edit them easily. That’s probably your best bet.

Hope that helps.

Like

Holy ****ing ****!!! You finally got this to work for me! I’ve been trying to get a shopify collection feed to spit out a product feed readable by Facebook for about 3 weeks. Your solution has lead me to believe that we may have stripped essential code from our standard collection template file. The one caveat I’ve found is that you have to make the collection visible on online store in order for it the link to be readable by Facebook’s Product Feed input. This means people could hit that collection page and see a giant block of text. Maybe we can find a work around but again, THANK YOU kind sir. You are a saint.

Like