diff --git a/.travis.yml b/.travis.yml
index 938fe03..7f81c3a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,11 +1,9 @@
language: ruby
sudo: false
rvm:
- - 1.9.3
- 2.0.0
- 2.1.5
- 2.2.3
- - jruby
gemfile:
- Gemfile.rails-3.2
- Gemfile.rails-4.2
diff --git a/README.md b/README.md
index 60fb18f..fb5c3d9 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@ Google Analytics comes first but its likely that more are added as the project g
Normally you'd go ahead and add some partials to your application that will render out the
needed tracking codes. As time passes by you'll find yourself with lots of tracking
snippets, that will clutter your codebase :) When just looking at Analytics there are
-solutions like `rack-google-analytics` but they just soley tackle the existence of one
+solutions like `rack-google-analytics` but they just solely tackle the existence of one
service.
We wanted a solution that ties all services together in one place and offers
@@ -23,7 +23,7 @@ but to get you started we're shipping support for the following services out of
* [Google Analytics](#google-analytics)
* [Google Adwords Conversion](#google-adwords-conversion)
* [Google Tag Manager](#google-tag-manager)
-* [Facebook](#facebook)
+* [Facebook Pixel](#facebook-pixel)
* [Visual Website Optimizer (VWO)](#visual-website-optimizer-vwo)
* [GoSquared](#gosquared)
* [Criteo](#criteo)
@@ -52,7 +52,7 @@ Add it to your middleware stack
config.middleware.use(Rack::Tracker) do
handler :google_analytics, { tracker: 'U-XXXXX-Y' }
end
-````
+```
This will add Google Analytics as a tracking handler.
@@ -84,7 +84,7 @@ request.env['tracker'] = {
}
```
-### Google Analytics
+## Google Analytics
* `:anonymize_ip` - sets the tracker to remove the last octet from all IP addresses, see https://developers.google.com/analytics/devguides/collection/gajs/methods/gaJSApi_gat?hl=de#_gat._anonymizeIp for details.
* `:cookie_domain` - sets the domain name for the [GATC cookies](https://developers.google.com/analytics/devguides/collection/analyticsjs/domains#implementation). If not set its the website domain, with the www. prefix removed.
@@ -190,7 +190,7 @@ take care of the plugin on your own.
end
```
-### Google Adwords Conversion
+## Google Adwords Conversion
You can configure the handler with default options:
```ruby
@@ -227,7 +227,7 @@ You can also specify a different value from default options:
end
```
-### Google Tag Manager
+## Google Tag Manager
Google Tag manager code snippet doesn't support any option other than the container id
@@ -252,28 +252,62 @@ To add events or variables to the dataLayer from the server side, just call the
```
-### Facebook
+## Facebook Pixel
+
+For implementing [Facebook Pixel](https://www.facebook.com/business/a/facebook-pixel).
+
+Use in conjunction with the [Facebook Pixel Helper](https://developers.facebook.com/docs/facebook-pixel/pixel-helper) to confirm your event fires correctly.
+
+First, add the following to your config:
+
+```ruby
+ config.middleware.use(Rack::Tracker) do
+ handler :facebook_pixel, { id: 'PIXEL_ID' }
+ end
+```
+
+This will add the Facebook Pixel base code and a PageView event to your application.
-* `custom_audience` - adds the [Custom audience](https://developers.facebook.com/docs/reference/ads-api/custom-audience-website-faq) segmentation pixel
+#### Standard Events
-#### Conversions
+For the list of Standard Events, check Facebook's [documentation](https://www.facebook.com/business/help/952192354843755?helpref=faq_content#addeventcode).
-To track [Conversions](https://www.facebook.com/help/435189689870514) from the server side just call the `tracker` method in your controller.
+To track Standard Events from the server side just call the `tracker` method in your controller.
```ruby
def show
tracker do |t|
- t.facebook :track, { id: '123456789', value: 1, currency: 'EUR' }
+ t.facebook_pixel :track, { type: 'Purchase', options: { value: 100, currency: 'USD' } }
end
end
```
-Will result in the following:
+This will result in the following:
```javascript
- window._fbq.push(["track", "123456789", {'value': 1, 'currency': 'EUR'}]);
+ fbq("track", "Purchase", {"value":"100.0","currency":"USD"});
```
-### Visual website Optimizer (VWO)
+
+#### Custom Events
+
+For tracking custom events, add the `custom` parameter and set it to `true`.
+Then use any type or options you want to include.
+
+```ruby
+ def show
+ tracker do |t|
+ t.facebook_pixel :track, { type: 'Login', options: { group: 'Students' }, custom: true }
+ end
+ end
+```
+
+This will result in the following:
+
+```javascript
+ fbq("trackCustom", "Login", {"group":"Students"});
+```
+
+## Visual website Optimizer (VWO)
Just integrate the handler with your matching account_id and you will be ready to go
```ruby
@@ -282,7 +316,7 @@ Just integrate the handler with your matching account_id and you will be ready t
end
```
-### GoSquared
+## GoSquared
To enable GoSquared tracking:
@@ -290,7 +324,7 @@ To enable GoSquared tracking:
config.middleware.use(Rack::Tracker) do
handler :go_squared, { tracker: 'ABCDEFGH' }
end
-````
+```
This will add the tracker to the page like so:
@@ -309,7 +343,7 @@ config.middleware.use(Rack::Tracker) do
}
}
end
-````
+```
This will add the specified trackers to the page like so:
@@ -363,7 +397,7 @@ It will render the following to the site source:
_gs("set", "visitor", { "age": 35, "favorite_food": "pizza" });
```
-### Criteo
+## Criteo
[Criteo](http://www.criteo.com/) retargeting service.
@@ -408,7 +442,7 @@ Another example
t.criteo :track_transaction, { id: 'id', item: { id: "P0038", price: "6.54", quantity: 1 } }
```
-### Zanox
+## Zanox
[Zanox](http://www.zanox.com/us/)
@@ -466,7 +500,7 @@ def show
end
```
-### Custom Handlers
+## Custom Handlers
Tough we give you handlers for a few tracking services right out of the box, you might
be interested adding support for your custom tracking/analytics service.
@@ -507,7 +541,7 @@ Lets give it a try! We need to mount our new handler in the `Rack::Tracker` midd
config.middleware.use(Rack::Tracker) do
handler MyHandler, { awesome: true }
end
-````
+```
Everything you're passing to the `handler` will be available as `#options` in your
template, so you'll also gain access to the `env`-hash belonging to the current request.
diff --git a/lib/rack/tracker.rb b/lib/rack/tracker.rb
index 5f3dbf9..a7e1780 100644
--- a/lib/rack/tracker.rb
+++ b/lib/rack/tracker.rb
@@ -16,6 +16,7 @@
require "rack/tracker/google_tag_manager/google_tag_manager"
require "rack/tracker/google_adwords_conversion/google_adwords_conversion"
require "rack/tracker/facebook/facebook"
+require "rack/tracker/facebook_pixel/facebook_pixel"
require "rack/tracker/vwo/vwo"
require "rack/tracker/go_squared/go_squared"
require "rack/tracker/criteo/criteo"
diff --git a/lib/rack/tracker/facebook/facebook.rb b/lib/rack/tracker/facebook/facebook.rb
index 67cdd69..3f87247 100644
--- a/lib/rack/tracker/facebook/facebook.rb
+++ b/lib/rack/tracker/facebook/facebook.rb
@@ -1,17 +1,7 @@
class Rack::Tracker::Facebook < Rack::Tracker::Handler
class Event < OpenStruct
def write
- options.present? ? type_to_json << options_to_json : type_to_json
- end
-
- private
-
- def type_to_json
- self.type.to_json
- end
-
- def options_to_json
- ", #{self.options.to_json}"
+ ['track', self.id, to_h.except(:id).compact].to_json
end
end
@@ -24,4 +14,5 @@ def render
def self.track(name, *event)
{ name.to_s => [event.last.merge('class_name' => 'Event')] }
end
+
end
diff --git a/lib/rack/tracker/facebook/template/facebook.erb b/lib/rack/tracker/facebook/template/facebook.erb
index 3a31a87..c6f6fe9 100644
--- a/lib/rack/tracker/facebook/template/facebook.erb
+++ b/lib/rack/tracker/facebook/template/facebook.erb
@@ -1,20 +1,40 @@
+
+<% if options[:custom_audience] %>
+
+
+<% end %>
<% if events.any? %>
-
+
+
+
<% end %>
diff --git a/lib/rack/tracker/facebook_pixel/facebook_pixel.rb b/lib/rack/tracker/facebook_pixel/facebook_pixel.rb
new file mode 100644
index 0000000..18b6b40
--- /dev/null
+++ b/lib/rack/tracker/facebook_pixel/facebook_pixel.rb
@@ -0,0 +1,31 @@
+class Rack::Tracker::FacebookPixel < Rack::Tracker::Handler
+ class Event < OpenStruct
+ def write
+ options.present? ? type_to_json << options_to_json : type_to_json
+ end
+
+ def custom?
+ custom.present? && custom == true ? custom : false
+ end
+
+ private
+
+ def type_to_json
+ type.to_json
+ end
+
+ def options_to_json
+ ", #{options.to_json}"
+ end
+ end
+
+ self.position = :body
+
+ def render
+ Tilt.new( File.join( File.dirname(__FILE__), 'template/facebook_pixel.erb') ).render(self)
+ end
+
+ def self.track(name, *event)
+ { name.to_s => [event.last.merge('class_name' => 'Event')] }
+ end
+end
diff --git a/lib/rack/tracker/facebook_pixel/template/facebook_pixel.erb b/lib/rack/tracker/facebook_pixel/template/facebook_pixel.erb
new file mode 100644
index 0000000..a45331d
--- /dev/null
+++ b/lib/rack/tracker/facebook_pixel/template/facebook_pixel.erb
@@ -0,0 +1,24 @@
+
+
+
+<% if events.any? %>
+
+<% end %>
diff --git a/lib/rack/tracker/google_tag_manager/template/google_tag_manager.erb b/lib/rack/tracker/google_tag_manager/template/google_tag_manager.erb
index 8fd4d3d..9a3743f 100644
--- a/lib/rack/tracker/google_tag_manager/template/google_tag_manager.erb
+++ b/lib/rack/tracker/google_tag_manager/template/google_tag_manager.erb
@@ -3,6 +3,12 @@
dataLayer = [];
+
+
-
<% end %>
diff --git a/lib/rack/tracker/version.rb b/lib/rack/tracker/version.rb
index 9c92cfb..1017e3f 100644
--- a/lib/rack/tracker/version.rb
+++ b/lib/rack/tracker/version.rb
@@ -1,5 +1,5 @@
module Rack
class Tracker
- VERSION = '1.1.0'
+ VERSION = '1.1.7'
end
end
diff --git a/spec/handler/facebook_pixel_spec.rb b/spec/handler/facebook_pixel_spec.rb
new file mode 100644
index 0000000..5629e14
--- /dev/null
+++ b/spec/handler/facebook_pixel_spec.rb
@@ -0,0 +1,92 @@
+RSpec.describe Rack::Tracker::FacebookPixel do
+ # describe Rack::Tracker::FacebookPixel::Event do
+
+ # subject { described_class.new({id: 'id', foo: 'bar'}) }
+
+ # describe '#write' do
+ # specify { expect(subject.write).to eq(['track', 'id', {foo: 'bar'}].to_json) }
+ # end
+ # end
+
+ def env
+ {}
+ end
+
+ it 'will be placed in the body' do
+ expect(described_class.position).to eq(:body)
+ expect(described_class.new(env).position).to eq(:body)
+ end
+
+ describe 'with id' do
+ subject { described_class.new(env, id: 'PIXEL_ID').render }
+
+ it 'will push the tracking events to the queue' do
+ expect(subject).to match(%r{fbq\('init', 'PIXEL_ID'\)})
+ end
+
+ it 'will add the noscript fallback' do
+ expect(subject).to match(%r{https://www.facebook.com/tr\?id=PIXEL_ID&ev=PageView&noscript=1})
+ end
+ end
+
+ describe 'with events' do
+ def env
+ {
+ 'tracker' => {
+ 'facebook_pixel' =>
+ [
+ {
+ 'type' => 'Purchase',
+ 'class_name' => 'Event',
+ 'options' =>
+ {
+ 'value' => '23',
+ 'currency' => 'EUR'
+ }
+ }
+ ]
+ }
+ }
+ end
+ subject { described_class.new(env).render }
+
+ it 'will push the tracking events to the queue' do
+ expect(subject).to match(%r{"track", "Purchase", \{"value":"23","currency":"EUR"\}})
+ end
+
+ it 'will add the noscript fallback' do
+ expect(subject).to match(%r{https://www.facebook.com/tr\?id=&ev=PageView&noscript=1})
+ end
+ end
+
+ describe 'with custom events' do
+ def env
+ {
+ 'tracker' => {
+ 'facebook_pixel' =>
+ [
+ {
+ 'type' => 'Login',
+ 'class_name' => 'Event',
+ 'options' =>
+ {
+ 'organization' => 'TestCompany',
+ 'country' => 'USA'
+ },
+ 'custom' => true
+ }
+ ]
+ }
+ }
+ end
+ subject { described_class.new(env).render }
+
+ it 'will push the custom tracking events to the queue' do
+ expect(subject).to match(%r{"trackCustom", "Login", \{"organization":"TestCompany","country":"USA"\}})
+ end
+
+ it 'will add the noscript fallback' do
+ expect(subject).to match(%r{https://www.facebook.com/tr\?id=&ev=PageView&noscript=1})
+ end
+ end
+end
diff --git a/spec/integration/facebook_pixel_integration_spec.rb b/spec/integration/facebook_pixel_integration_spec.rb
new file mode 100644
index 0000000..809bc38
--- /dev/null
+++ b/spec/integration/facebook_pixel_integration_spec.rb
@@ -0,0 +1,17 @@
+require 'support/capybara_app_helper'
+
+RSpec.describe "Facebook Pixel Integration" do
+ before do
+ setup_app(action: :facebook_pixel) do |tracker|
+ tracker.handler :facebook_pixel, { id: 'PIXEL_ID' }
+ end
+ visit '/'
+ end
+
+ subject { page }
+
+ it "embeds the script tag with tracking event from the controller action" do
+ expect(page).to have_content("fbq('init', 'PIXEL_ID');")
+ expect(page.body).to include('https://www.facebook.com/tr?id=PIXEL_ID&ev=PageView&noscript=1')
+ end
+end
diff --git a/spec/support/metal_controller.rb b/spec/support/metal_controller.rb
index 3a69364..6dd9911 100644
--- a/spec/support/metal_controller.rb
+++ b/spec/support/metal_controller.rb
@@ -29,6 +29,13 @@ def facebook
render "metal/index"
end
+ def facebook_pixel
+ tracker do |t|
+ t.facebook_pixel :track, { id: 'conversion-event', value: '1', currency: 'EUR' }
+ end
+ render "metal/index"
+ end
+
def google_analytics
tracker do |t|
t.google_analytics :ecommerce, { type: 'addTransaction', id: 1234, affiliation: 'Acme Clothing', revenue: 11.99, shipping: 5, tax: 1.29 }