WARNING! This code is no longer maintained. Although the code in this post should still work, please use at your own risk. I recommend using the Shopify Facebook Marketing App to sync your product catalog.
Below is a free customizable DIY solution to create a Facebook Product Feed in Shopify.
- This is an advanced topic and assumes you have the required understanding of HTML/XML/Liquid, the Shopify Store Admin and Facebook Business Manager.
- 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 Products > Use 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!