How to use Full Picture’s Custom Events

Setting up Full Picture’s Custom Events is recommended for users with at least basic understanding of HTML, CSS and Javascript.

Full Picture lets you quickly and easily send events to Google Analytics, Facebook Pixel and other integrated platforms when:

  1. a product is added or removed from cart
  2. checkout has started
  3. an order has been made
  4. a conversion (of any type) has happened
  5. a product or any piece of content is being viewed
  6. and much more

FP Events are plugin agnostic, meanining that you can grab data from ANY plugin. The only requirement is having enough data.

How do Full Picture’s Custom Events work

The basic concept is simple.

  1. You add a custom event’s code anywhere on the page. In this code you specify what content should be grabbed from the HTML of the page and when it should be grabbed (pageload, click, etc.).
  2. When the page finishes loading then Full Picture’s scripts will read your events code and grab the content from HTML when the event that you specified happens.
  3. Finally, Full Picture’s script sends the data to tracking platforms you enabled in format that they require.

To set up Full Picture Custom Events you can use a Javascript code or a shortcode (examples later).

Since they both work and look very similar, in this guide I will concentrate on the JS implementation and will only mention differences in the shortcodes by the end.

Basic example

This is an example of a Javascript code that is used to configure a custom event.

FP.set('product data', {
	'product id' : '{{.product form.options|get:data-id}}',
	'product name' : '{{h1|get:text}}',
	'product category' : '{{#breadcrumbs a:last-of-type|get:text}}',
	'product qty' : '{{!.product form.options input.qty|get:value}}',
	'product price' : '{{!.product form.options .price|get:text|replace:$:|to:float}}',
	'currency' : 'USD',
	'ga interaction' : true

FP.track('product data', 'add to cart', 'click', 'button.add_to_cart');

Function FP.set() contains information what data should be grabbed from the HTML.

Function FP.track() contains information when this data should be grabbed and in what format it should be sent (in this case it will be a format for “add to cart” events).

Full list of supported events is available in this document (I will tell you more about this document later, so keep it open).

FP.set() and FP.track() do not need to come one after another.

While in most cases this is how they will be placed, there may also be cases where a different placement will be required.

FP.set can, for example, be set in an external file loaded in the document head while FP.track() can be e.g. added dynamically by a script or an AJAX load.

The only thing that you actually need to remember is that FP.set() needs to come before FP.track().


FP.set([data object name], [data object recipe])

FP.set takes 2 parameters:

  1. The name of the data object (string) – required. It can be any name you want.
  2. The data object – required and it cannot be empty, e.g. {}


FP.set('product data', {
	'product id' : '{{.product form.options|get:data-id}}',
	'product name' : '{{h1|get:text}}',
	'product category' : '{{#breadcrumbs a:last-of-type|get:text}}',
	'product qty' : '{{!.product form.options input.qty|get:value}}',
	'product price' : '{{.product form.options .price|get:text|replace:$:|to:float}}',
	'currency' : 'USD',
	'ga interaction' : true


FP.track([data object name], [event name], [trigger], [condition])

FP.track() takes 4 parameters:

  1. data object name (string) – this must be the same name as provided in the FP.set()
  2. event name (string) – this must be one of the names from the “Event name” column from this document
  3. trigger (string) – states when the object should be sent
  4. condition (string) – says when exactly to fire the event

Trigger types and available conditions:

instantnone – the data will be sent the moment the page loads or the FP.track() is called with JavaScript.
after(integer) time in miliseconds – similar to “instant” condition, but the data will be sent after a set time from the moment the page loads.

This may be useful if parts of your page take longer to load.
clickCSS selector(s) of the element(s) that needs to be clicked to send the data, e.g. “body.checkout .order-btn”

Please mind, that the names of triggers need to be written in small caps.


The script below can be translated to “send ‘add to cart’ event with product details when a button is clicked”

FP.track( 'product data', 'add to cart', 'click', '#product form.details .add-to-cart' );

The script below can be translated to “send a “purchase” event with order details after the page loads (or when this function is called by a JS callback)”

FP.track( 'order info', 'purchase', 'instant' );

The script below can be translated to “send an ‘add to wishlist’ event with the product details 2 seconds (2000 miliseconds) after the page loads”.

FP.track( 'product details', 'add to wishlist', 'after', '2000' );

Creating an object with data

Full Picture requires you to provide in FP.set() a non-empty object.

The names of object’s properties are specified and their full list is available in this spreadsheet.

The screenshot below comes from this spreadsheet.

As you can see names of properties for an “add to cart” event are “content name”, “product id”, product name”, “product category”, etc.

Object built with these properties might look like this in FP.set():

	'product id' : '{{.product form.options|get:data-id}}',
	'product name' : '{{h1|get:text}}',
	'product category' : '{{#breadcrumbs a:last-of-type|get:text}}',
	'product qty' : '{{!.product form.options input.qty|get:value}}',
	'product price' : '{{.product form.options .price|get:text|replace:$:|to:float}}',
	'currency' : 'USD',
	'ga interaction' : true

As you can see, some values are strings, like “USD” or boolean true/false. Apart from them however, there are also other ones that start and end with “{{..}}”. They are called “recipies” and you need to learn how to use them.


Recipies are short instructions of how to grab content from the page and how to format it.

For example the recipe below grabs the text from the last link from the breadcrumbs.

{{#breadcrumbs a:last-of-type|get:text}}

This one on the other hand takes the “id” from the “data-id” attribute of a form and changes it from a string to an integer.

{{.product form.options|get:data-id|to:integer}}

By default the recipies are processed and “changed” into values the moment the page loads.

Both of the examples above are like that.

However, very often there is a need to grab a value later, e.g. after a user entered something in a form.

In such situations, we need to instruct the Full Picture’s functions to process the recipe and grab the data right before the event is sent.

Thankfully this is done very easily – by simply adding a “!” sign after starting “{{“.

For example, the recipe below grabs the product quantity from a product details form, the moment the event is sent.

{{!.product form.details input.qty|get:value}}'

Parts of recipies

There are a few rules of formatting a recipe.

  1. All recipies are strings that start with “{{” and end with “}}”.
  2. If the value is to be grabbed from HTML right before the event is sent, the “!” needs to be put right after the opening “{{“.
  3. “Steps” of the recipe need to be separated by a “pipe” symbol “|”.
  4. Recipe cannot contain any colons “:” apart from the CSS selector and the “steps” listed in the table below
  5. “Steps” need to follow the following order:
    1. CSS selector (required)
    2. limit (optional)
    3. get (required)
    4. remove colons (optional)
    5. to / add before / add after / trim / replace / count / encode – all of them are optional and may be used multiple times

Here’s a full list of elements that can go into a recipe after a selector.

limitnofirstget first elementlimit:first
lastget last elementlimit:last
getyesidget value of the element’s idget:id
data-[name]get value of the data attributeget:data-name
valueget value of a form fieldget:value
textget textget:text
[any attribute]get any attribute of an elementget:target or
remove colonsnouse to remove “:” before doing “replace”remove colons
tonointegerchange value to integerget:integer
floatchange value to a number with a floating pointget:float
add beforeno[string or number]add a string to the begining of the previous valueadd before:Price
add afterno[string or number]add a string to the end of the previous valueadd after: USD
trimnoremove whitespace from the begining and end of the stringtrim
replaceno[string]:[string]replace a string with another string (spaces and letter size are respected). It can also be used to remove parts of the text if no text to replace the original one is given.replace:Price :Your price
countnoCounts the number of elements in an array or letters in a stringcount
encodenoEncodes data before sending. Useful for personal data, like emailsencode

Example 1

Grab the product name and remove a part of its text.

'{{body.product h1.product-title|get:text|replace: - SALE!!:}}'

If the page is titled, “iPad Air 2020 – SALE!!” the result of running the above recipe would be “iPad Air 2020”. Please pay attention to spaces!

Example 2

Grab the last product price, remove the currency symbol and turn it into a number with a decimal point

'{{body.product form.details .price, body.product .final-price|limit:last|replace:$:|to:float}}'

Example 3

Grab the value of an email field and encode it

'{{form.subscribe input[type="email"]|get:value|encode}}'

Special properties – “unique” and “unique session”

Apart from the recipies there is also one more twist about Full Picture’s Custom Events – “unique” and “unique session” properties.

These two are used to limit the number of times an event is sent.

  1. “unique” limits it to just a single time (forever)
  2. and “unique session” limits it to a single time in a session

Take a look here.

FP.set('purchased products', {
  'product ids' : '{{.product|get:data-id}}',
  'product qtys' : '{{.product .qty span|get:text|to:integer}}',
  'product names' : '{{.product .name|get:text}}',
  'currency' : 'PLN',
  'order value' : '{{.total-purchase|get:text|to:float}}',
  'product prices' : '{{.product .price span|get:text|to:float}}',
  'order id' : '{{#ord-id|get:text|replace:order :}}',
  'unique' : 'order id'

FP.track('purchased products', 'purchase', 'instant');

As you can see ‘unique’ is set to ‘order id’. It means that this event with this order id will be sent only once.


As I’ve already said, you can configure FP Custom Events using either Javascript or shortcodes.

To use shortcodes however you need to enable them in Full Picture settings.

After you do that, you will be able to use 2 new shortcodes “fp_set” and “fp_track” like below.

[fp_set name="product data"]
	^product id^ : ^{{.product form.options|get:data-id}}^
	^product name^ : ^{{h1|get:text}}^
	^product category^ : ^{{#breadcrumbs a:last-of-type|get:text}}^
	^product qty^ : ^{{!.product form.options input.qty|get:value}}^
	^product price^ : ^{{!.product form.options .price|get:text|replace:$:|to:float}}^
	^currency^: ^USD^
	^ga interaction^ : true

[fp_track data="product data" event="add to cart" trigger="click" condition="button.add_to_cart"]

As you can see they look very similar to Javascript and they don’t require much explanation. The only thing you need to remember when using these shortcodes is that you have to switch all single quotes to ^ symbols.

Please pay attention to ends of lines of fp_set. Do not enter there any extra characters like comas for example (developers may do this our of habit)

Solutions to common problems

When I update page with <script> in Gutenberg I am getting an error “Updating failed. The response is not a valid JSON response.”

This may be caused by many reasons. The best way around it is to enter the custom event codes with shortcodes. To do this you should enable them in Full Picture’s settings.

My scripts/shortcodes do not work!

Make sure that your code is error-free. It won’t work otherwise.

The most common errors for scripts and shortcodes are:

  1. missing/too many comas
  2. using semi-colons instead of comas at the end of lines with object properties
  3. missing/too many quotes

Get a 50% early-bird discount and a chance to win a free licence?!

Subscribe to the launch notification