choreograph-create-pixel 1.3.3 β 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -5
- package/dist/bundle.cjs.js +96 -48
- package/dist/bundle.esm.js +96 -48
- package/dist/bundle.iife.min.js +2 -2
- package/package.json +13 -9
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ This library lets you apply best practises to [Create](https://www.lemonpi.io/)
|
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
- [x] Supports [scraper](#scraper-pixels), [segment](#segment-pixels) and [
|
|
7
|
+
- [x] Supports [scraper](#scraper-pixels), [segment](#segment-pixels) and [post-click](#post-click-pixels) pixels
|
|
8
8
|
- [x] Supports dynamic page content updates
|
|
9
9
|
- [x] Prevents scraping browser-translated content
|
|
10
10
|
- [x] Continuous URL validation
|
|
@@ -15,7 +15,7 @@ This library lets you apply best practises to [Create](https://www.lemonpi.io/)
|
|
|
15
15
|
|
|
16
16
|
<small>Type: `scraper`</small>
|
|
17
17
|
|
|
18
|
-
Scraper pixels are used to scrape (
|
|
18
|
+
Scraper pixels are used to scrape (collect) data from websites, and store that data as products within an advertiser's product store.
|
|
19
19
|
|
|
20
20
|
### Segment pixels
|
|
21
21
|
|
|
@@ -23,9 +23,11 @@ Scraper pixels are used to scrape (read) data from websites, and store that data
|
|
|
23
23
|
|
|
24
24
|
Products in ads are shown by recommendation. Segment pixels determine this recommendation on a consumer level, by storing a **cookie** at different moments or events during the consumer's journey.
|
|
25
25
|
|
|
26
|
-
###
|
|
26
|
+
### Post-click pixels
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
<small>Types: `attribution` and `conversion`</small>
|
|
29
|
+
|
|
30
|
+
Post-click conversion attribution tracks which clicked creative variant attributed to a website conversion. The **attribution** pixel collects the creative's impression ID from the URL (`ccpid` query parameter) on the landing page, and the **conversion** pixel logs this ID as a performance metric in Create when a user performed a conversion, like a purchase.
|
|
29
31
|
|
|
30
32
|
## Quickstart
|
|
31
33
|
|
|
@@ -44,7 +46,7 @@ new Pixel({
|
|
|
44
46
|
// Where on the website should this pixel be enabled?
|
|
45
47
|
url: /example\.com\/products\/\d/,
|
|
46
48
|
|
|
47
|
-
//
|
|
49
|
+
// Scrape functions are continuously re-evaluated for value changes
|
|
48
50
|
scrape: {
|
|
49
51
|
// Data layer example
|
|
50
52
|
sku: () => window.dataLayer[0].product.sku,
|
|
@@ -97,6 +99,33 @@ new Pixel({
|
|
|
97
99
|
// Segment pixels support multiple SKUs
|
|
98
100
|
scrape: () => window.dataLayer[0].cart.map((product) => product.sku),
|
|
99
101
|
});
|
|
102
|
+
|
|
103
|
+
// Attribution post-click pixel
|
|
104
|
+
new Pixel({
|
|
105
|
+
advertiser: 0,
|
|
106
|
+
type: "attribution",
|
|
107
|
+
|
|
108
|
+
// Uniquely label each set of post-click pixels
|
|
109
|
+
label: "example",
|
|
110
|
+
|
|
111
|
+
// Match this URL to the landing page of your campaign
|
|
112
|
+
url: /example\.com\/products\/\d/,
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// Conversion post-click pixel
|
|
116
|
+
new Pixel({
|
|
117
|
+
advertiser: 0,
|
|
118
|
+
type: "conversion",
|
|
119
|
+
label: "example",
|
|
120
|
+
|
|
121
|
+
// Match this URL to the conversion page of your campaign
|
|
122
|
+
url: /example\.com\/cart/,
|
|
123
|
+
|
|
124
|
+
trigger: {
|
|
125
|
+
event: "click",
|
|
126
|
+
elements: "button.checkout",
|
|
127
|
+
},
|
|
128
|
+
});
|
|
100
129
|
```
|
|
101
130
|
|
|
102
131
|
> ES modules require manual bundling and transpiling before they can be safely embedded on websites.
|
|
@@ -128,6 +157,7 @@ Enable browser console debugging by adding `?pixel_debug` or `#pixel_debug` to t
|
|
|
128
157
|
| ------------------------------- | ----------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- |
|
|
129
158
|
| `advertiser` | Number | You can retrieve the advertiser ID from the URL in Create: _manage.lemonpi.io/r/AGENCY_ID/advertiser/`ADVERTISER_ID`_. | _Required_ |
|
|
130
159
|
| `type` | String | Pixel type. One of: `"scraper"`, `"viewed"`, `"basketed"` or `"purchased"`. | _Required_ |
|
|
160
|
+
| `label`<br>_(post-click only)_ | String | Conversion label, used for aggregation in reporting. | _Required_ |
|
|
131
161
|
| `url` | RegExp | Only enables the pixel on page URLs that are matched by this pattern. | _Required_ |
|
|
132
162
|
| `scrape`<br>_(segments only)_ | String, Array or Function | Scrapes the product's SKU for segments. | _Required_ |
|
|
133
163
|
| `scrape.*`<br>_(scrapers only)_ | String, Number, Boolean or Function | Scrapes arbitrary product data. `*` should always match with existing field names in the advertiser's product store. | _Required_ |
|
package/dist/bundle.cjs.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! choreograph-create-pixel v1.
|
|
1
|
+
/*! choreograph-create-pixel v1.4.0 2023/02/01 */
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
class ChoreographCreatePixel {
|
|
@@ -14,7 +14,7 @@ class ChoreographCreatePixel {
|
|
|
14
14
|
basketed: "π",
|
|
15
15
|
purchased: "π§Ύ",
|
|
16
16
|
attribution: "π",
|
|
17
|
-
conversion: "
|
|
17
|
+
conversion: "π",
|
|
18
18
|
},
|
|
19
19
|
debug: /(pixel|lemonpi)_debug/i.test(location.href),
|
|
20
20
|
before: (data, callback) => callback(data),
|
|
@@ -85,8 +85,8 @@ class ChoreographCreatePixel {
|
|
|
85
85
|
if (!this.config.debug || this.logs.includes(message)) return;
|
|
86
86
|
|
|
87
87
|
const args = [
|
|
88
|
-
`%cβΈ¬ create%c ${this.config.type} ${
|
|
89
|
-
this.config.
|
|
88
|
+
`%cβΈ¬ create%c ${this.config.icons[this.config.type]} ${this.config.type}${
|
|
89
|
+
this.config.label ? ` (${this.config.label})` : ""
|
|
90
90
|
} %c${message}`,
|
|
91
91
|
"background:black;color:white;border-radius:3px;padding:3px 6px",
|
|
92
92
|
"font-weight:bold",
|
|
@@ -104,16 +104,35 @@ class ChoreographCreatePixel {
|
|
|
104
104
|
advertiser: this.config.advertiser,
|
|
105
105
|
});
|
|
106
106
|
else if (
|
|
107
|
-
![
|
|
107
|
+
![
|
|
108
|
+
"scraper",
|
|
109
|
+
"viewed",
|
|
110
|
+
"basketed",
|
|
111
|
+
"purchased",
|
|
112
|
+
"attribution",
|
|
113
|
+
"conversion",
|
|
114
|
+
].includes(this.config.type)
|
|
108
115
|
)
|
|
109
|
-
this.log(
|
|
110
|
-
|
|
116
|
+
this.log(
|
|
117
|
+
"error",
|
|
118
|
+
"Please use scraper, viewed, basketed, purchased, attribution or conversion",
|
|
119
|
+
{ type: this.config.type }
|
|
120
|
+
);
|
|
121
|
+
else if (
|
|
122
|
+
["attribution", "conversion"].includes(this.config.type) &&
|
|
123
|
+
typeof this.config.label !== "string"
|
|
124
|
+
)
|
|
125
|
+
this.log("error", "Please use a string", {
|
|
126
|
+
label: this.config.label,
|
|
111
127
|
});
|
|
112
128
|
else if (!(this.config.url instanceof RegExp))
|
|
113
129
|
this.log("error", "Please use a regular expression", {
|
|
114
130
|
url: this.config.url,
|
|
115
131
|
});
|
|
116
|
-
else if (
|
|
132
|
+
else if (
|
|
133
|
+
!["attribution", "conversion"].includes(this.config.type) &&
|
|
134
|
+
!this.config.scrape
|
|
135
|
+
)
|
|
117
136
|
this.log("error", "Please provide something to scrape", {
|
|
118
137
|
scrape: this.config.scrape,
|
|
119
138
|
});
|
|
@@ -134,7 +153,8 @@ class ChoreographCreatePixel {
|
|
|
134
153
|
"This page has been translated by the browser, and won't be scraped"
|
|
135
154
|
);
|
|
136
155
|
else if (this.config.trigger) {
|
|
137
|
-
|
|
156
|
+
// TO-DO: replace this.config.type with a unique pixel instance ID
|
|
157
|
+
const elementAttribute = `create-${this.config.type}-${this.config.trigger.event}`;
|
|
138
158
|
|
|
139
159
|
try {
|
|
140
160
|
let elements =
|
|
@@ -145,12 +165,14 @@ class ChoreographCreatePixel {
|
|
|
145
165
|
if (!elements.forEach) elements = [elements];
|
|
146
166
|
|
|
147
167
|
elements.forEach((element) => {
|
|
148
|
-
if (!element.hasAttribute(
|
|
168
|
+
if (!element.hasAttribute(elementAttribute)) {
|
|
149
169
|
element.addEventListener(this.config.trigger.event, () =>
|
|
150
|
-
this.
|
|
170
|
+
this.config.type === "conversion"
|
|
171
|
+
? this.convert()
|
|
172
|
+
: this.scrape(element)
|
|
151
173
|
);
|
|
152
174
|
|
|
153
|
-
element.setAttribute(
|
|
175
|
+
element.setAttribute(elementAttribute, "");
|
|
154
176
|
}
|
|
155
177
|
});
|
|
156
178
|
} catch (error) {
|
|
@@ -159,12 +181,53 @@ class ChoreographCreatePixel {
|
|
|
159
181
|
});
|
|
160
182
|
}
|
|
161
183
|
} else {
|
|
162
|
-
this.
|
|
184
|
+
switch (this.config.type) {
|
|
185
|
+
case "attribution":
|
|
186
|
+
this.attribute();
|
|
187
|
+
break;
|
|
188
|
+
|
|
189
|
+
case "conversion":
|
|
190
|
+
this.convert();
|
|
191
|
+
break;
|
|
192
|
+
|
|
193
|
+
default:
|
|
194
|
+
this.scrape();
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
163
197
|
}
|
|
164
198
|
|
|
165
199
|
setTimeout(() => this.cycle(), 750);
|
|
166
200
|
}
|
|
167
201
|
|
|
202
|
+
attribute() {
|
|
203
|
+
const ccpid = this.constructor.getQueryParameter("ccpid");
|
|
204
|
+
if (!ccpid) return this.log("warn", "ccpid query parameter not present");
|
|
205
|
+
|
|
206
|
+
if (
|
|
207
|
+
!/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/.test(
|
|
208
|
+
ccpid
|
|
209
|
+
)
|
|
210
|
+
)
|
|
211
|
+
return this.log(
|
|
212
|
+
"error",
|
|
213
|
+
"ccpid query parameter is not formatted correctly"
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
const storageItemLabel = `choreograph-${this.config.label}`;
|
|
217
|
+
const storedCcpid = localStorage.getItem(storageItemLabel);
|
|
218
|
+
if (storedCcpid !== ccpid) localStorage.setItem(storageItemLabel, ccpid);
|
|
219
|
+
this.log("success", "Successful!", ccpid);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
convert() {
|
|
223
|
+
const ccpid = localStorage.getItem(`choreograph-${this.config.label}`);
|
|
224
|
+
|
|
225
|
+
if (!ccpid)
|
|
226
|
+
return this.log("warn", `"${this.config.label}" attribution not present`);
|
|
227
|
+
|
|
228
|
+
this.send(ccpid);
|
|
229
|
+
}
|
|
230
|
+
|
|
168
231
|
scrape(element) {
|
|
169
232
|
let hasErrors = false;
|
|
170
233
|
let data;
|
|
@@ -178,11 +241,9 @@ class ChoreographCreatePixel {
|
|
|
178
241
|
} catch (error) {
|
|
179
242
|
if (this.config.optional.includes(fieldName)) return undefined;
|
|
180
243
|
|
|
181
|
-
this.log(
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
{ [fieldName ? `scrape.${fieldName}` : "scrape"]: result }
|
|
185
|
-
);
|
|
244
|
+
this.log("error", error.message, {
|
|
245
|
+
[fieldName ? `scrape.${fieldName}` : "scrape"]: result,
|
|
246
|
+
});
|
|
186
247
|
|
|
187
248
|
hasErrors = true;
|
|
188
249
|
}
|
|
@@ -195,11 +256,9 @@ class ChoreographCreatePixel {
|
|
|
195
256
|
(result == null || result === "") &&
|
|
196
257
|
!this.config.optional.includes(fieldName)
|
|
197
258
|
) {
|
|
198
|
-
this.log(
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
{ [fieldName ? `scrape.${fieldName}` : "scrape"]: result }
|
|
202
|
-
);
|
|
259
|
+
this.log("error", "Value is empty", {
|
|
260
|
+
[fieldName ? `scrape.${fieldName}` : "scrape"]: result,
|
|
261
|
+
});
|
|
203
262
|
|
|
204
263
|
hasErrors = true;
|
|
205
264
|
}
|
|
@@ -207,17 +266,7 @@ class ChoreographCreatePixel {
|
|
|
207
266
|
return result;
|
|
208
267
|
};
|
|
209
268
|
|
|
210
|
-
if (this.config.type
|
|
211
|
-
data = {
|
|
212
|
-
conversion: handleField(this.config.scrape),
|
|
213
|
-
attribution: localStorage.getItem("create-attribution-id"),
|
|
214
|
-
};
|
|
215
|
-
|
|
216
|
-
if (typeof data.attribution !== "string") {
|
|
217
|
-
this.log("warn", "There's no attribution ID stored yet");
|
|
218
|
-
hasErrors = true;
|
|
219
|
-
}
|
|
220
|
-
} else if (this.config.type !== "scraper") {
|
|
269
|
+
if (this.config.type !== "scraper") {
|
|
221
270
|
data = handleField(this.config.scrape);
|
|
222
271
|
} else {
|
|
223
272
|
data = Object.keys(this.config.scrape).reduce(
|
|
@@ -234,19 +283,7 @@ class ChoreographCreatePixel {
|
|
|
234
283
|
if (!hasErrors && this.previouslyScrapedHash !== dataHash) {
|
|
235
284
|
try {
|
|
236
285
|
this.config.before(data, (newData) => {
|
|
237
|
-
if (
|
|
238
|
-
localStorage.setItem("create-attribution-id", data);
|
|
239
|
-
this.log("success", "Successful!", { attribution: data });
|
|
240
|
-
|
|
241
|
-
try {
|
|
242
|
-
this.config.after(data);
|
|
243
|
-
} catch (error) {
|
|
244
|
-
this.log("error", error.message, {
|
|
245
|
-
after: this.config.after,
|
|
246
|
-
});
|
|
247
|
-
}
|
|
248
|
-
} else if (Array.isArray(newData))
|
|
249
|
-
newData.forEach((id) => this.send(id));
|
|
286
|
+
if (Array.isArray(newData)) newData.forEach((id) => this.send(id));
|
|
250
287
|
else this.send(newData);
|
|
251
288
|
});
|
|
252
289
|
} catch (error) {
|
|
@@ -268,10 +305,20 @@ class ChoreographCreatePixel {
|
|
|
268
305
|
url = `https://d.lemonpi.io/scrapes${
|
|
269
306
|
this.config.debug ? "?validate=true" : ""
|
|
270
307
|
}`;
|
|
308
|
+
|
|
271
309
|
break;
|
|
272
310
|
|
|
273
311
|
case "conversion":
|
|
274
|
-
url =
|
|
312
|
+
url = `https://content.lemonpi.io/track/event?e=${encodeURIComponent(
|
|
313
|
+
JSON.stringify({
|
|
314
|
+
version: 1,
|
|
315
|
+
type: "conversion",
|
|
316
|
+
name: this.config.label,
|
|
317
|
+
"conversion-attribution-id": data,
|
|
318
|
+
"advertiser-id": this.config.advertiser,
|
|
319
|
+
})
|
|
320
|
+
)}`;
|
|
321
|
+
|
|
275
322
|
break;
|
|
276
323
|
|
|
277
324
|
default:
|
|
@@ -283,6 +330,7 @@ class ChoreographCreatePixel {
|
|
|
283
330
|
sku: data,
|
|
284
331
|
})
|
|
285
332
|
)}`;
|
|
333
|
+
|
|
286
334
|
break;
|
|
287
335
|
}
|
|
288
336
|
|
package/dist/bundle.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! choreograph-create-pixel v1.
|
|
1
|
+
/*! choreograph-create-pixel v1.4.0 2023/02/01 */
|
|
2
2
|
class ChoreographCreatePixel {
|
|
3
3
|
constructor(userConfig) {
|
|
4
4
|
this.previouslyScrapedHash = null;
|
|
@@ -12,7 +12,7 @@ class ChoreographCreatePixel {
|
|
|
12
12
|
basketed: "π",
|
|
13
13
|
purchased: "π§Ύ",
|
|
14
14
|
attribution: "π",
|
|
15
|
-
conversion: "
|
|
15
|
+
conversion: "π",
|
|
16
16
|
},
|
|
17
17
|
debug: /(pixel|lemonpi)_debug/i.test(location.href),
|
|
18
18
|
before: (data, callback) => callback(data),
|
|
@@ -83,8 +83,8 @@ class ChoreographCreatePixel {
|
|
|
83
83
|
if (!this.config.debug || this.logs.includes(message)) return;
|
|
84
84
|
|
|
85
85
|
const args = [
|
|
86
|
-
`%cβΈ¬ create%c ${this.config.type} ${
|
|
87
|
-
this.config.
|
|
86
|
+
`%cβΈ¬ create%c ${this.config.icons[this.config.type]} ${this.config.type}${
|
|
87
|
+
this.config.label ? ` (${this.config.label})` : ""
|
|
88
88
|
} %c${message}`,
|
|
89
89
|
"background:black;color:white;border-radius:3px;padding:3px 6px",
|
|
90
90
|
"font-weight:bold",
|
|
@@ -102,16 +102,35 @@ class ChoreographCreatePixel {
|
|
|
102
102
|
advertiser: this.config.advertiser,
|
|
103
103
|
});
|
|
104
104
|
else if (
|
|
105
|
-
![
|
|
105
|
+
![
|
|
106
|
+
"scraper",
|
|
107
|
+
"viewed",
|
|
108
|
+
"basketed",
|
|
109
|
+
"purchased",
|
|
110
|
+
"attribution",
|
|
111
|
+
"conversion",
|
|
112
|
+
].includes(this.config.type)
|
|
106
113
|
)
|
|
107
|
-
this.log(
|
|
108
|
-
|
|
114
|
+
this.log(
|
|
115
|
+
"error",
|
|
116
|
+
"Please use scraper, viewed, basketed, purchased, attribution or conversion",
|
|
117
|
+
{ type: this.config.type }
|
|
118
|
+
);
|
|
119
|
+
else if (
|
|
120
|
+
["attribution", "conversion"].includes(this.config.type) &&
|
|
121
|
+
typeof this.config.label !== "string"
|
|
122
|
+
)
|
|
123
|
+
this.log("error", "Please use a string", {
|
|
124
|
+
label: this.config.label,
|
|
109
125
|
});
|
|
110
126
|
else if (!(this.config.url instanceof RegExp))
|
|
111
127
|
this.log("error", "Please use a regular expression", {
|
|
112
128
|
url: this.config.url,
|
|
113
129
|
});
|
|
114
|
-
else if (
|
|
130
|
+
else if (
|
|
131
|
+
!["attribution", "conversion"].includes(this.config.type) &&
|
|
132
|
+
!this.config.scrape
|
|
133
|
+
)
|
|
115
134
|
this.log("error", "Please provide something to scrape", {
|
|
116
135
|
scrape: this.config.scrape,
|
|
117
136
|
});
|
|
@@ -132,7 +151,8 @@ class ChoreographCreatePixel {
|
|
|
132
151
|
"This page has been translated by the browser, and won't be scraped"
|
|
133
152
|
);
|
|
134
153
|
else if (this.config.trigger) {
|
|
135
|
-
|
|
154
|
+
// TO-DO: replace this.config.type with a unique pixel instance ID
|
|
155
|
+
const elementAttribute = `create-${this.config.type}-${this.config.trigger.event}`;
|
|
136
156
|
|
|
137
157
|
try {
|
|
138
158
|
let elements =
|
|
@@ -143,12 +163,14 @@ class ChoreographCreatePixel {
|
|
|
143
163
|
if (!elements.forEach) elements = [elements];
|
|
144
164
|
|
|
145
165
|
elements.forEach((element) => {
|
|
146
|
-
if (!element.hasAttribute(
|
|
166
|
+
if (!element.hasAttribute(elementAttribute)) {
|
|
147
167
|
element.addEventListener(this.config.trigger.event, () =>
|
|
148
|
-
this.
|
|
168
|
+
this.config.type === "conversion"
|
|
169
|
+
? this.convert()
|
|
170
|
+
: this.scrape(element)
|
|
149
171
|
);
|
|
150
172
|
|
|
151
|
-
element.setAttribute(
|
|
173
|
+
element.setAttribute(elementAttribute, "");
|
|
152
174
|
}
|
|
153
175
|
});
|
|
154
176
|
} catch (error) {
|
|
@@ -157,12 +179,53 @@ class ChoreographCreatePixel {
|
|
|
157
179
|
});
|
|
158
180
|
}
|
|
159
181
|
} else {
|
|
160
|
-
this.
|
|
182
|
+
switch (this.config.type) {
|
|
183
|
+
case "attribution":
|
|
184
|
+
this.attribute();
|
|
185
|
+
break;
|
|
186
|
+
|
|
187
|
+
case "conversion":
|
|
188
|
+
this.convert();
|
|
189
|
+
break;
|
|
190
|
+
|
|
191
|
+
default:
|
|
192
|
+
this.scrape();
|
|
193
|
+
break;
|
|
194
|
+
}
|
|
161
195
|
}
|
|
162
196
|
|
|
163
197
|
setTimeout(() => this.cycle(), 750);
|
|
164
198
|
}
|
|
165
199
|
|
|
200
|
+
attribute() {
|
|
201
|
+
const ccpid = this.constructor.getQueryParameter("ccpid");
|
|
202
|
+
if (!ccpid) return this.log("warn", "ccpid query parameter not present");
|
|
203
|
+
|
|
204
|
+
if (
|
|
205
|
+
!/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/.test(
|
|
206
|
+
ccpid
|
|
207
|
+
)
|
|
208
|
+
)
|
|
209
|
+
return this.log(
|
|
210
|
+
"error",
|
|
211
|
+
"ccpid query parameter is not formatted correctly"
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
const storageItemLabel = `choreograph-${this.config.label}`;
|
|
215
|
+
const storedCcpid = localStorage.getItem(storageItemLabel);
|
|
216
|
+
if (storedCcpid !== ccpid) localStorage.setItem(storageItemLabel, ccpid);
|
|
217
|
+
this.log("success", "Successful!", ccpid);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
convert() {
|
|
221
|
+
const ccpid = localStorage.getItem(`choreograph-${this.config.label}`);
|
|
222
|
+
|
|
223
|
+
if (!ccpid)
|
|
224
|
+
return this.log("warn", `"${this.config.label}" attribution not present`);
|
|
225
|
+
|
|
226
|
+
this.send(ccpid);
|
|
227
|
+
}
|
|
228
|
+
|
|
166
229
|
scrape(element) {
|
|
167
230
|
let hasErrors = false;
|
|
168
231
|
let data;
|
|
@@ -176,11 +239,9 @@ class ChoreographCreatePixel {
|
|
|
176
239
|
} catch (error) {
|
|
177
240
|
if (this.config.optional.includes(fieldName)) return undefined;
|
|
178
241
|
|
|
179
|
-
this.log(
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
{ [fieldName ? `scrape.${fieldName}` : "scrape"]: result }
|
|
183
|
-
);
|
|
242
|
+
this.log("error", error.message, {
|
|
243
|
+
[fieldName ? `scrape.${fieldName}` : "scrape"]: result,
|
|
244
|
+
});
|
|
184
245
|
|
|
185
246
|
hasErrors = true;
|
|
186
247
|
}
|
|
@@ -193,11 +254,9 @@ class ChoreographCreatePixel {
|
|
|
193
254
|
(result == null || result === "") &&
|
|
194
255
|
!this.config.optional.includes(fieldName)
|
|
195
256
|
) {
|
|
196
|
-
this.log(
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
{ [fieldName ? `scrape.${fieldName}` : "scrape"]: result }
|
|
200
|
-
);
|
|
257
|
+
this.log("error", "Value is empty", {
|
|
258
|
+
[fieldName ? `scrape.${fieldName}` : "scrape"]: result,
|
|
259
|
+
});
|
|
201
260
|
|
|
202
261
|
hasErrors = true;
|
|
203
262
|
}
|
|
@@ -205,17 +264,7 @@ class ChoreographCreatePixel {
|
|
|
205
264
|
return result;
|
|
206
265
|
};
|
|
207
266
|
|
|
208
|
-
if (this.config.type
|
|
209
|
-
data = {
|
|
210
|
-
conversion: handleField(this.config.scrape),
|
|
211
|
-
attribution: localStorage.getItem("create-attribution-id"),
|
|
212
|
-
};
|
|
213
|
-
|
|
214
|
-
if (typeof data.attribution !== "string") {
|
|
215
|
-
this.log("warn", "There's no attribution ID stored yet");
|
|
216
|
-
hasErrors = true;
|
|
217
|
-
}
|
|
218
|
-
} else if (this.config.type !== "scraper") {
|
|
267
|
+
if (this.config.type !== "scraper") {
|
|
219
268
|
data = handleField(this.config.scrape);
|
|
220
269
|
} else {
|
|
221
270
|
data = Object.keys(this.config.scrape).reduce(
|
|
@@ -232,19 +281,7 @@ class ChoreographCreatePixel {
|
|
|
232
281
|
if (!hasErrors && this.previouslyScrapedHash !== dataHash) {
|
|
233
282
|
try {
|
|
234
283
|
this.config.before(data, (newData) => {
|
|
235
|
-
if (
|
|
236
|
-
localStorage.setItem("create-attribution-id", data);
|
|
237
|
-
this.log("success", "Successful!", { attribution: data });
|
|
238
|
-
|
|
239
|
-
try {
|
|
240
|
-
this.config.after(data);
|
|
241
|
-
} catch (error) {
|
|
242
|
-
this.log("error", error.message, {
|
|
243
|
-
after: this.config.after,
|
|
244
|
-
});
|
|
245
|
-
}
|
|
246
|
-
} else if (Array.isArray(newData))
|
|
247
|
-
newData.forEach((id) => this.send(id));
|
|
284
|
+
if (Array.isArray(newData)) newData.forEach((id) => this.send(id));
|
|
248
285
|
else this.send(newData);
|
|
249
286
|
});
|
|
250
287
|
} catch (error) {
|
|
@@ -266,10 +303,20 @@ class ChoreographCreatePixel {
|
|
|
266
303
|
url = `https://d.lemonpi.io/scrapes${
|
|
267
304
|
this.config.debug ? "?validate=true" : ""
|
|
268
305
|
}`;
|
|
306
|
+
|
|
269
307
|
break;
|
|
270
308
|
|
|
271
309
|
case "conversion":
|
|
272
|
-
url =
|
|
310
|
+
url = `https://content.lemonpi.io/track/event?e=${encodeURIComponent(
|
|
311
|
+
JSON.stringify({
|
|
312
|
+
version: 1,
|
|
313
|
+
type: "conversion",
|
|
314
|
+
name: this.config.label,
|
|
315
|
+
"conversion-attribution-id": data,
|
|
316
|
+
"advertiser-id": this.config.advertiser,
|
|
317
|
+
})
|
|
318
|
+
)}`;
|
|
319
|
+
|
|
273
320
|
break;
|
|
274
321
|
|
|
275
322
|
default:
|
|
@@ -281,6 +328,7 @@ class ChoreographCreatePixel {
|
|
|
281
328
|
sku: data,
|
|
282
329
|
})
|
|
283
330
|
)}`;
|
|
331
|
+
|
|
284
332
|
break;
|
|
285
333
|
}
|
|
286
334
|
|
package/dist/bundle.iife.min.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/*! choreograph-create-pixel v1.
|
|
2
|
-
var ChoreographCreatePixel=function(){"use strict";function e(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function t(t){for(var r=1;r<arguments.length;r++){var i=null!=arguments[r]?arguments[r]:{};r%2?e(Object(i),!0).forEach((function(e){n(t,e,i[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(i)):e(Object(i)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(i,e))}))}return t}function r(e,t){for(var r=0;r<t.length;r++){var n=t[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,i(n.key),n)}}function n(e,t,r){return(t=i(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e){var t=function(e,t){if("object"!=typeof e||null===e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var n=r.call(e,t||"default");if("object"!=typeof n)return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"==typeof t?t:String(t)}var o=function(){function e(r){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this.previouslyScrapedHash=null,this.logs=[],this.config=t({colors:{error:"red",warn:"orange",success:"green"},icons:{scraper:"π",viewed:"π",basketed:"π",purchased:"π§Ύ",attribution:"π",conversion:"
|
|
1
|
+
/*! choreograph-create-pixel v1.4.0 2023/02/01 */
|
|
2
|
+
var ChoreographCreatePixel=function(){"use strict";function e(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function t(t){for(var r=1;r<arguments.length;r++){var i=null!=arguments[r]?arguments[r]:{};r%2?e(Object(i),!0).forEach((function(e){n(t,e,i[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(i)):e(Object(i)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(i,e))}))}return t}function r(e,t){for(var r=0;r<t.length;r++){var n=t[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,i(n.key),n)}}function n(e,t,r){return(t=i(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e){var t=function(e,t){if("object"!=typeof e||null===e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var n=r.call(e,t||"default");if("object"!=typeof n)return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"==typeof t?t:String(t)}var o=function(){function e(r){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this.previouslyScrapedHash=null,this.logs=[],this.config=t({colors:{error:"red",warn:"orange",success:"green"},icons:{scraper:"π",viewed:"π",basketed:"π",purchased:"π§Ύ",attribution:"π",conversion:"π"},debug:/(pixel|lemonpi)_debug/i.test(location.href),before:function(e,t){return t(e)},after:function(){},optional:[]},r),this.validateConfig()&&this.cycle()}var i,o,c;return i=e,o=[{key:"log",value:function(e,t){var r,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;if(this.config.debug&&!this.logs.includes(t)){var i=["%cβΈ¬ create%c ".concat(this.config.icons[this.config.type]," ").concat(this.config.type).concat(this.config.label?" (".concat(this.config.label,")"):""," %c").concat(t),"background:black;color:white;border-radius:3px;padding:3px 6px","font-weight:bold","color:".concat(this.config.colors[e])];n&&i.push(n),(r=console).info.apply(r,i),this.logs.push(t)}}},{key:"validateConfig",value:function(){if("number"!=typeof this.config.advertiser)this.log("error","Please use a number",{advertiser:this.config.advertiser});else if(["scraper","viewed","basketed","purchased","attribution","conversion"].includes(this.config.type))if(["attribution","conversion"].includes(this.config.type)&&"string"!=typeof this.config.label)this.log("error","Please use a string",{label:this.config.label});else if(this.config.url instanceof RegExp){if(["attribution","conversion"].includes(this.config.type)||this.config.scrape)return!0;this.log("error","Please provide something to scrape",{scrape:this.config.scrape})}else this.log("error","Please use a regular expression",{url:this.config.url});else this.log("error","Please use scraper, viewed, basketed, purchased, attribution or conversion",{type:this.config.type})}},{key:"cycle",value:function(){var e=this;if(this.config.url.test(location.href))if("scraper"===this.config.type&&document.querySelector('html[class*="translated-"]'))this.log("warn","This page has been translated by the browser, and won't be scraped");else if(this.config.trigger){var t="create-".concat(this.config.type,"-").concat(this.config.trigger.event);try{var r="string"==typeof this.config.trigger.elements?document.querySelectorAll(this.config.trigger.elements):this.config.trigger.elements();r.forEach||(r=[r]),r.forEach((function(r){r.hasAttribute(t)||(r.addEventListener(e.config.trigger.event,(function(){return"conversion"===e.config.type?e.convert():e.scrape(r)})),r.setAttribute(t,""))}))}catch(e){this.log("error",e.message,{"trigger.elements":this.config.trigger.elements})}}else switch(this.config.type){case"attribution":this.attribute();break;case"conversion":this.convert();break;default:this.scrape()}else this.log("warn",'URL pattern does not match "'.concat(location.href,'"'),{url:this.config.url});setTimeout((function(){return e.cycle()}),750)}},{key:"attribute",value:function(){var e=this.constructor.getQueryParameter("ccpid");if(!e)return this.log("warn","ccpid query parameter not present");if(!/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/.test(e))return this.log("error","ccpid query parameter is not formatted correctly");var t="choreograph-".concat(this.config.label);localStorage.getItem(t)!==e&&localStorage.setItem(t,e),this.log("success","Successful!",e)}},{key:"convert",value:function(){var e=localStorage.getItem("choreograph-".concat(this.config.label));if(!e)return this.log("warn",'"'.concat(this.config.label,'" attribution not present'));this.send(e)}},{key:"scrape",value:function(e){var r,i=this,o=!1,c=function(t,r){var c=t;if("function"==typeof c)try{c=c(e)}catch(e){if(i.config.optional.includes(r))return;i.log("error",e.message,n({},r?"scrape.".concat(r):"scrape",c)),o=!0}return"string"==typeof c&&(c=c.replace(/\s+/g," ").trim()),null!=c&&""!==c||i.config.optional.includes(r)||(i.log("error","Value is empty",n({},r?"scrape.".concat(r):"scrape",c)),o=!0),c};r="scraper"!==this.config.type?c(this.config.scrape):Object.keys(this.config.scrape).reduce((function(e,r){return t(t({},e),{},n({},r,c(i.config.scrape[r],r)))}),{});var s=JSON.stringify(r);if(!o&&this.previouslyScrapedHash!==s){try{this.config.before(r,(function(e){Array.isArray(e)?e.forEach((function(e){return i.send(e)})):i.send(e)}))}catch(e){this.log("error",e.message,{before:this.config.before})}this.previouslyScrapedHash=s,this.logs.length=0}}},{key:"send",value:function(e){var r,n=this;switch(this.config.type){case"scraper":r="https://d.lemonpi.io/scrapes".concat(this.config.debug?"?validate=true":"");break;case"conversion":r="https://content.lemonpi.io/track/event?e=".concat(encodeURIComponent(JSON.stringify({version:1,type:"conversion",name:this.config.label,"conversion-attribution-id":e,"advertiser-id":this.config.advertiser})));break;default:r="https://d.lemonpi.io/a/".concat(this.config.advertiser,"/product/event?e=").concat(encodeURIComponent(JSON.stringify({"event-type":"product-".concat(this.config.type),sku:e})))}"scraper"===this.config.type||this.config.debug?fetch(r,"scraper"===this.config.type?{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({"advertiser-id":this.config.advertiser,sku:e.sku,fields:t(t({},e),{},{sku:void 0})})}:null).then((function(t){return t.json().then((function(r){if(t.ok){n.log("warn","Successful, with warnings. Details:",r);try{n.config.after(e)}catch(e){n.log("error",e.message,{after:n.config.after})}}else n.log("error","Failed: ".concat(t.status," (").concat(t.statusText,"). Details:"),r);n.logs.length=0})).catch((function(){if(t.ok){n.log("success","Successful!",["viewed","basketed","purchased"].includes(n.config.type)?{sku:e}:e);try{n.config.after(e)}catch(e){n.log("error",e.message,{after:n.config.after})}}else n.log("error","Failed: ".concat(t.status," (").concat(t.statusText,"). Details:"),t);n.logs.length=0}))})).catch((function(e){n.log("error","Failed: ".concat(e.message)),n.logs.length=0})):(new Image).src=r}}],c=[{key:"getUrl",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.allowedQueryParameters,r=void 0===t?[]:t,n=e.allowHash,i=void 0!==n&&n,o="".concat(location.protocol,"//").concat(location.host).concat(location.pathname),c=new URLSearchParams(location.search);return r.reduce((function(e,t){var r=e?"&":"?",n=encodeURI(t),i=c.get(t);return null!=i?(o+="".concat(r).concat(n).concat(""===i?"":"=".concat(encodeURI(i))),!0):e}),!1),i&&(o+=location.hash),o}},{key:"getAllPathSegments",value:function(){return location.pathname.split("/").filter((function(e){return e})).map((function(e){return decodeURI(e)}))}},{key:"getPathSegment",value:function(e){return this.getAllPathSegments()[e]}},{key:"getAllQueryParameters",value:function(){return location.search.replace(/^\?/,"").split("&").filter((function(e){return e})).reduce((function(e,r){return t(t({},e),{},n({},decodeURI(r.split("=")[0]),decodeURI(r.split("=")[1]||"")))}),{})}},{key:"getQueryParameter",value:function(e){return this.getAllQueryParameters()[e]}}],o&&r(i.prototype,o),c&&r(i,c),Object.defineProperty(i,"prototype",{writable:!1}),e}();return o}();
|
package/package.json
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "choreograph-create-pixel",
|
|
3
3
|
"description": "This library lets you apply best practises to Choreograph Create pixel development and implementation.",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.4.0",
|
|
5
|
+
"type": "module",
|
|
5
6
|
"keywords": [
|
|
6
7
|
"wpp",
|
|
7
8
|
"groupm",
|
|
8
9
|
"lemonpi",
|
|
9
10
|
"odc",
|
|
10
|
-
"opendc"
|
|
11
|
+
"opendc",
|
|
12
|
+
"greenhouse"
|
|
11
13
|
],
|
|
12
14
|
"author": "Rick Stevens <rick.stevens@choreograph.com> (https://lemonpi.io)",
|
|
13
15
|
"repository": "gitlab:2sixty/choreograph-create/solutions/choreograph-create-pixel",
|
|
@@ -28,16 +30,18 @@
|
|
|
28
30
|
"prepublishOnly": "npm run build"
|
|
29
31
|
},
|
|
30
32
|
"devDependencies": {
|
|
31
|
-
"@babel/core": "^7.20.
|
|
33
|
+
"@babel/core": "^7.20.12",
|
|
34
|
+
"@babel/eslint-parser": "^7.19.1",
|
|
35
|
+
"@babel/plugin-syntax-import-assertions": "^7.20.0",
|
|
32
36
|
"@babel/preset-env": "^7.20.2",
|
|
33
37
|
"@rollup/plugin-babel": "^6.0.3",
|
|
34
|
-
"@rollup/plugin-eslint": "^9.0.
|
|
35
|
-
"@rollup/plugin-terser": "^0.
|
|
36
|
-
"eslint": "^8.
|
|
37
|
-
"eslint-config-prettier": "^8.
|
|
38
|
+
"@rollup/plugin-eslint": "^9.0.3",
|
|
39
|
+
"@rollup/plugin-terser": "^0.4.0",
|
|
40
|
+
"eslint": "^8.33.0",
|
|
41
|
+
"eslint-config-prettier": "^8.6.0",
|
|
38
42
|
"eslint-plugin-prettier": "^4.2.1",
|
|
39
43
|
"moment": "^2.29.4",
|
|
40
|
-
"prettier": "^2.8.
|
|
41
|
-
"rollup": "^
|
|
44
|
+
"prettier": "^2.8.3",
|
|
45
|
+
"rollup": "^3.12.0"
|
|
42
46
|
}
|
|
43
47
|
}
|