Skip to content

Commit

Permalink
Merge pull request #17 from railslove/criteo
Browse files Browse the repository at this point in the history
Support for Criteo
  • Loading branch information
DonSchado committed Mar 26, 2015
2 parents 6303b21 + bbd5c7f commit d818e38
Show file tree
Hide file tree
Showing 7 changed files with 249 additions and 3 deletions.
30 changes: 27 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -328,24 +328,48 @@ It will render the following to the site source:

[Criteo](http://www.criteo.com/) retargeting service.

#### Basic configuration

```
config.middleware.use(Rack::Tracker) do
handler :criteo, { set_account: '1234' }
end
```

Other global criteo handler options are:
* `setCustomerId` (value can be a static or a dynamic, e.g. `lambda { |env| env['rack.session']['user_id'] }`)
* `setSiteType` (`m`, `t`, `d`)
* `set_customer_id: 'x'`
* `set_site_type: 'd'` - possible values are `m` (mobile), `t` (tablet), `d` (desktop)

Option values can be either static or dynamic by providing a lambda being reevaluated for each request, e.g. `set_customer_id: lambda { |env| env['rack.session']['user_id'] }`

#### Tracking events

This will track a basic event:

```
def show
tracker do |t|
t.criteo :track, { event: 'viewItem', item: 'P0001' }
t.criteo :view_item, { item: 'P0001' }
end
end
```

This will render to the follwing code in the JS:

```
window.criteo_q.push({"event": "viewItem", "item": "P001" });
```

The first argument for `t.criteo` is always the criteo event (e.g. `:view_item`, `:view_list`, `:track_transaction`, `:view_basket`) and the second argument are additional properties for the event.

Another example

```
t.criteo :track_transaction, { id: 'id', item: { id: "P0038", price: "6.54", quantity: 1 } }
```

end

### Custom Handlers

Tough we give you handlers for a few tracking services right out of the box, you might
Expand Down
1 change: 1 addition & 0 deletions lib/rack/tracker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
require "rack/tracker/facebook/facebook"
require "rack/tracker/vwo/vwo"
require "rack/tracker/go_squared/go_squared"
require "rack/tracker/criteo/criteo"

module Rack
class Tracker
Expand Down
36 changes: 36 additions & 0 deletions lib/rack/tracker/criteo/criteo.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
class Criteo < Rack::Tracker::Handler

TRACKER_EVENTS = {
# event name => event key name, e.g. { event: 'setSiteType', type: '' }
set_site_type: :type,
set_account: :account,
set_customer_id: :id
}

class Event < OpenStruct
def write
to_h.to_json
end
end

self.position = :body

# global events (setSiteType, setAccount, ...) for each tracker instance
def tracker_events
@tracker_events ||= [].tap do |tracker_events|
options.slice(*TRACKER_EVENTS.keys).each do |key, value|
if option_value = value.respond_to?(:call) ? value.call(env) : value
tracker_events << Event.new(:event => "#{key}".camelize(:lower), TRACKER_EVENTS[key] => "#{option_value}")
end
end
end
end

def render
Tilt.new( File.join( File.dirname(__FILE__), 'template', 'criteo.erb') ).render(self)
end

def self.track(name, event_name, event_args = {})
{ name.to_s => [{ 'class_name' => 'Event', 'event' => event_name.to_s.camelize(:lower) }.merge(event_args)] }
end
end
9 changes: 9 additions & 0 deletions lib/rack/tracker/criteo/template/criteo.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<% if events.any? %>
<script type='text/javascript' src='//static.criteo.net/js/ld/ld.js' async='true'></script>
<script type='text/javascript'>
window.criteo_q = window.criteo_q || [];
<% (tracker_events + events).each do |event| %>
window.criteo_q.push(<%= event.write %>);
<% end %>
</script>
<% end %>
122 changes: 122 additions & 0 deletions spec/handler/criteo_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
RSpec.describe Rack::Tracker::Criteo do

describe Rack::Tracker::Criteo::Event do

subject { described_class.new(event: "viewItem", item: 'P001') }

describe '#write' do
specify { expect(subject.write).to eq("{\"event\":\"viewItem\",\"item\":\"P001\"}") }
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 '#render' do
context 'with events' do
let(:env) {
{
'tracker' => {
'criteo' =>
[
{
'event' => 'viewItem',
'item' => 'P001',
'class_name' => 'Event'
}
]
}
}
}

subject { described_class.new(env).render }

it 'will push the tracking events to the queue' do
expect(subject).to include 'window.criteo_q.push({"event":"viewItem","item":"P001"});'
end
end

context 'without events' do
let(:env) {
{
'tracker' => {
'criteo' => []
}
}
}

subject { described_class.new(env, { user_id: ->(env){ '123' } }).render }

it 'should render nothing' do
expect(subject).to eql ""
end
end
end

describe '#tracker_events' do
subject { described_class.new(env, options) }

context 'nil value' do
let(:options) { { set_account: nil } }

it 'should ignore option' do
expect(subject.tracker_events).to match_array []
end
end

context 'static string value' do
let(:options) { { set_account: '1234' } }

it 'should set the value' do
expect(subject.tracker_events).to match_array [
Rack::Tracker::Criteo::Event.new(event: 'setAccount', account: '1234')
]
end
end

context 'static integer value' do
let(:options) { { set_customer_id: 1234 } }

it 'should set the value as string' do
expect(subject.tracker_events).to match_array [
Rack::Tracker::Criteo::Event.new(event: 'setCustomerId', id: '1234')
]
end
end

context 'unsupported option' do
let(:options) { { unsupported: "option" } }

subject { described_class.new(env, options) }

it 'should ignore the option' do
expect(subject.tracker_events).to match_array []
end
end

context 'proc returning value' do
let(:options) { { set_site_type: ->(env){ 'm' } } }

it 'should set the value' do
expect(subject.tracker_events).to match_array [
Rack::Tracker::Criteo::Event.new(event: 'setSiteType', type: 'm')
]
end
end

context 'proc returning nil' do
let(:options) { { set_account: ->(env){ nil } } }

it 'should ignore the option' do
expect(subject.tracker_events).to match_array []
end
end
end

end
44 changes: 44 additions & 0 deletions spec/integration/criteo_integration_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
require 'support/capybara_app_helper'

RSpec.describe "Criteo Integration" do
before do
setup_app(action: :criteo) do |tracker|
tracker.handler(:criteo, {
set_account: '1234',
set_customer_id: ->(env){ '4711' },
set_site_type: ->(env){ 'm' }
})
end
visit '/'
end

subject { page }

it 'should include all the events' do
# tracker_events
expect(page.find("body")).to have_content "window.criteo_q.push({\"event\":\"setAccount\",\"account\":\"1234\"});"
expect(page.find("body")).to have_content "window.criteo_q.push({\"event\":\"setSiteType\",\"type\":\"m\"});"
expect(page.find("body")).to have_content "window.criteo_q.push({\"event\":\"setCustomerId\",\"id\":\"4711\"});"

# events
expect(page.find("body")).to have_content "window.criteo_q.push({\"event\":\"viewItem\",\"item\":\"P001\"});"
expect(page.find("body")).to have_content "window.criteo_q.push({\"event\":\"viewList\",\"item\":[\"P001\",\"P002\"]});"
expect(page.find("body")).to have_content "window.criteo_q.push({\"event\":\"trackTransaction\",\"id\":\"id\",\"item\":{\"id\":\"P0038\",\"price\":\"6.54\",\"quantity\":1}});"
expect(page.find("body")).to have_content "window.criteo_q.push({\"event\":\"viewBasket\",\"item\":[{\"id\":\"P001\",\"price\":\"6.54\",\"quantity\":1},{\"id\":\"P0038\",\"price\":\"2.99\",\"quantity\":1}]});"
end

describe 'adjust tracker position via options' do
before do
setup_app(action: :criteo) do |tracker|
tracker.handler :criteo, { set_account: '1234', position: :head }
end
visit '/'
end

it "will be placed in the specified tag" do
expect(page.find("body")).to_not have_content('criteo')
expect(page.find("head")).to have_content("{\"event\":\"setAccount\",\"account\":\"1234\"}")
end

end
end
10 changes: 10 additions & 0 deletions spec/support/metal_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,14 @@ def go_squared
end
render "metal/index"
end

def criteo
tracker do |t|
t.criteo :view_item, { item: 'P001' }
t.criteo :view_list, { item: ['P001', 'P002'] }
t.criteo :track_transaction, { id: 'id', item: { id: "P0038", price:"6.54", quantity:1 } }
t.criteo :view_basket, { item: [{ id: "P001", price:"6.54", quantity:1 }, { id: "P0038", price:"2.99", quantity:1 }] }
end
render 'metal/index'
end
end

0 comments on commit d818e38

Please sign in to comment.