choreograph-create-pixel 1.4.0 → 1.4.2
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 +12 -12
- package/dist/bundle.cjs.js +112 -98
- package/dist/bundle.esm.js +112 -98
- package/dist/bundle.iife.min.js +2 -2
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Choreograph Create Pixel
|
|
2
2
|
|
|
3
|
-
This library lets you apply best practises to [Create](https://
|
|
3
|
+
This library lets you apply best practises to [Create](https://create.choreograph.com/) pixel development and implementation.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
@@ -11,25 +11,25 @@ This library lets you apply best practises to [Create](https://www.lemonpi.io/)
|
|
|
11
11
|
- [x] User interaction triggers
|
|
12
12
|
- [x] [Console debugger](#debugging)
|
|
13
13
|
|
|
14
|
-
### Scraper
|
|
14
|
+
### Scraper pixel
|
|
15
15
|
|
|
16
16
|
<small>Type: `scraper`</small>
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
A scraper pixel is 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
|
|
|
22
22
|
<small>Types: `viewed`, `basketed` and `purchased`</small>
|
|
23
23
|
|
|
24
|
-
Products in ads are
|
|
24
|
+
Products in ads are sorted 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
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
|
|
30
|
+
Post-click conversion attribution tracks which clicked creative variant from an ad attributed to a website conversion. The **attribution** pixel collects and stores (through [`localStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage)) the creative's impression ID from the landing URL's `ccpid` query parameter, and the **conversion** pixel logs this ID as a performance metric in Create whenever a user performed a conversion, like a purchase.
|
|
31
31
|
|
|
32
|
-
##
|
|
32
|
+
## Quick start
|
|
33
33
|
|
|
34
34
|
The following theoretical snippet includes all pixel types, can be embedded on every page of _example.com_, and will automatically determine which pixel to enable and disable through continuous URL validation.
|
|
35
35
|
|
|
@@ -38,7 +38,7 @@ The following theoretical snippet includes all pixel types, can be embedded on e
|
|
|
38
38
|
```js
|
|
39
39
|
import Pixel from "choreograph-create-pixel";
|
|
40
40
|
|
|
41
|
-
// Scraper pixel
|
|
41
|
+
// Scraper pixel example
|
|
42
42
|
new Pixel({
|
|
43
43
|
advertiser: 0,
|
|
44
44
|
type: "scraper",
|
|
@@ -59,7 +59,7 @@ new Pixel({
|
|
|
59
59
|
},
|
|
60
60
|
});
|
|
61
61
|
|
|
62
|
-
// Viewed segment pixel
|
|
62
|
+
// Viewed segment pixel example
|
|
63
63
|
new Pixel({
|
|
64
64
|
advertiser: 0,
|
|
65
65
|
type: "viewed",
|
|
@@ -69,7 +69,7 @@ new Pixel({
|
|
|
69
69
|
scrape: () => window.dataLayer[0].product.sku,
|
|
70
70
|
});
|
|
71
71
|
|
|
72
|
-
// Basketed segment pixel
|
|
72
|
+
// Basketed segment pixel example
|
|
73
73
|
new Pixel({
|
|
74
74
|
advertiser: 0,
|
|
75
75
|
type: "basketed",
|
|
@@ -85,7 +85,7 @@ new Pixel({
|
|
|
85
85
|
scrape: (element) => element.getAttribute("data-sku"),
|
|
86
86
|
});
|
|
87
87
|
|
|
88
|
-
// Purchased segment pixel
|
|
88
|
+
// Purchased segment pixel example
|
|
89
89
|
new Pixel({
|
|
90
90
|
advertiser: 0,
|
|
91
91
|
type: "purchased",
|
|
@@ -100,7 +100,7 @@ new Pixel({
|
|
|
100
100
|
scrape: () => window.dataLayer[0].cart.map((product) => product.sku),
|
|
101
101
|
});
|
|
102
102
|
|
|
103
|
-
// Attribution post-click pixel
|
|
103
|
+
// Attribution post-click pixel example
|
|
104
104
|
new Pixel({
|
|
105
105
|
advertiser: 0,
|
|
106
106
|
type: "attribution",
|
|
@@ -112,7 +112,7 @@ new Pixel({
|
|
|
112
112
|
url: /example\.com\/products\/\d/,
|
|
113
113
|
});
|
|
114
114
|
|
|
115
|
-
// Conversion post-click pixel
|
|
115
|
+
// Conversion post-click pixel example
|
|
116
116
|
new Pixel({
|
|
117
117
|
advertiser: 0,
|
|
118
118
|
type: "conversion",
|
package/dist/bundle.cjs.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! choreograph-create-pixel v1.4.
|
|
1
|
+
/*! choreograph-create-pixel v1.4.2 2024/08/27 */
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
class ChoreographCreatePixel {
|
|
@@ -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.icons[this.config.type]} ${
|
|
89
|
-
this.config.
|
|
88
|
+
`%c⸬ create%c ${this.config.icons[this.config.type]} ${
|
|
89
|
+
this.config.type
|
|
90
90
|
} %c${message}`,
|
|
91
91
|
"background:black;color:white;border-radius:3px;padding:3px 6px",
|
|
92
92
|
"font-weight:bold",
|
|
@@ -196,6 +196,7 @@ class ChoreographCreatePixel {
|
|
|
196
196
|
}
|
|
197
197
|
}
|
|
198
198
|
|
|
199
|
+
// TO-DO: Move this to each method's end? Pageview conversions are currently recursive
|
|
199
200
|
setTimeout(() => this.cycle(), 750);
|
|
200
201
|
}
|
|
201
202
|
|
|
@@ -203,11 +204,7 @@ class ChoreographCreatePixel {
|
|
|
203
204
|
const ccpid = this.constructor.getQueryParameter("ccpid");
|
|
204
205
|
if (!ccpid) return this.log("warn", "ccpid query parameter not present");
|
|
205
206
|
|
|
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
|
-
)
|
|
207
|
+
if (!/^[0-9a-f]{20}$/.test(ccpid))
|
|
211
208
|
return this.log(
|
|
212
209
|
"error",
|
|
213
210
|
"ccpid query parameter is not formatted correctly"
|
|
@@ -216,16 +213,18 @@ class ChoreographCreatePixel {
|
|
|
216
213
|
const storageItemLabel = `choreograph-${this.config.label}`;
|
|
217
214
|
const storedCcpid = localStorage.getItem(storageItemLabel);
|
|
218
215
|
if (storedCcpid !== ccpid) localStorage.setItem(storageItemLabel, ccpid);
|
|
219
|
-
this.log("success", "
|
|
216
|
+
this.log("success", `Stored CCPID "${ccpid}" for "${this.config.label}"`);
|
|
220
217
|
}
|
|
221
218
|
|
|
222
219
|
convert() {
|
|
223
|
-
const
|
|
220
|
+
const label = `choreograph-${this.config.label}`;
|
|
221
|
+
const ccpid = localStorage.getItem(label);
|
|
224
222
|
|
|
225
223
|
if (!ccpid)
|
|
226
224
|
return this.log("warn", `"${this.config.label}" attribution not present`);
|
|
227
225
|
|
|
228
226
|
this.send(ccpid);
|
|
227
|
+
localStorage.removeItem(label);
|
|
229
228
|
}
|
|
230
229
|
|
|
231
230
|
scrape(element) {
|
|
@@ -298,113 +297,128 @@ class ChoreographCreatePixel {
|
|
|
298
297
|
}
|
|
299
298
|
|
|
300
299
|
send(data) {
|
|
300
|
+
let payload;
|
|
301
301
|
let url;
|
|
302
|
+
let method = "GET";
|
|
302
303
|
|
|
303
304
|
switch (this.config.type) {
|
|
304
|
-
case "scraper":
|
|
305
|
+
case "scraper": {
|
|
306
|
+
const { sku } = data;
|
|
307
|
+
delete data.sku;
|
|
308
|
+
|
|
309
|
+
payload = {
|
|
310
|
+
"advertiser-id": this.config.advertiser,
|
|
311
|
+
sku,
|
|
312
|
+
fields: data,
|
|
313
|
+
};
|
|
314
|
+
|
|
305
315
|
url = `https://d.lemonpi.io/scrapes${
|
|
306
316
|
this.config.debug ? "?validate=true" : ""
|
|
307
317
|
}`;
|
|
308
318
|
|
|
319
|
+
method = "POST";
|
|
309
320
|
break;
|
|
321
|
+
}
|
|
310
322
|
|
|
311
|
-
case "
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
"advertiser-id": this.config.advertiser,
|
|
319
|
-
})
|
|
320
|
-
)}`;
|
|
321
|
-
|
|
322
|
-
break;
|
|
323
|
+
case "viewed":
|
|
324
|
+
case "basketed":
|
|
325
|
+
case "purchased":
|
|
326
|
+
payload = {
|
|
327
|
+
"event-type": `product-${this.config.type}`,
|
|
328
|
+
sku: data,
|
|
329
|
+
};
|
|
323
330
|
|
|
324
|
-
default:
|
|
325
331
|
url = `https://d.lemonpi.io/a/${
|
|
326
332
|
this.config.advertiser
|
|
327
|
-
}/product/event?e=${encodeURIComponent(
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
333
|
+
}/product/event?e=${encodeURIComponent(JSON.stringify(payload))}`;
|
|
334
|
+
|
|
335
|
+
break;
|
|
336
|
+
|
|
337
|
+
case "conversion":
|
|
338
|
+
payload = {
|
|
339
|
+
version: 1,
|
|
340
|
+
type: "conversion",
|
|
341
|
+
name: this.config.label,
|
|
342
|
+
"conversion-attribution-id": data,
|
|
343
|
+
"advertiser-id": this.config.advertiser,
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
url = `https://content.lemonpi.io/track/event?e=${encodeURIComponent(
|
|
347
|
+
JSON.stringify(payload)
|
|
332
348
|
)}`;
|
|
333
349
|
|
|
334
350
|
break;
|
|
335
351
|
}
|
|
336
352
|
|
|
337
|
-
if (
|
|
353
|
+
if (
|
|
354
|
+
["viewed", "basketed", "purchased"].includes(this.config.type) &&
|
|
355
|
+
!this.config.debug
|
|
356
|
+
) {
|
|
338
357
|
new Image().src = url;
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
fetch(
|
|
362
|
+
url,
|
|
363
|
+
method === "POST"
|
|
364
|
+
? {
|
|
365
|
+
method: "POST",
|
|
366
|
+
headers: { "Content-Type": "application/json" },
|
|
367
|
+
body: JSON.stringify(payload),
|
|
368
|
+
}
|
|
369
|
+
: null
|
|
370
|
+
)
|
|
371
|
+
.then((response) =>
|
|
372
|
+
response
|
|
373
|
+
.json()
|
|
374
|
+
.then((result) => {
|
|
375
|
+
if (response.ok) {
|
|
376
|
+
this.log("warn", "Successful, with warnings. Details:", {
|
|
377
|
+
payload,
|
|
378
|
+
result,
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
try {
|
|
382
|
+
this.config.after(data);
|
|
383
|
+
} catch (error) {
|
|
384
|
+
this.log("error", error.message, {
|
|
385
|
+
after: this.config.after,
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
} else
|
|
389
|
+
this.log(
|
|
390
|
+
"error",
|
|
391
|
+
`Failed: ${response.status} (${response.statusText}). Details:`,
|
|
392
|
+
{ payload, result }
|
|
393
|
+
);
|
|
394
|
+
|
|
395
|
+
this.logs.length = 0;
|
|
396
|
+
})
|
|
397
|
+
.catch(() => {
|
|
398
|
+
if (response.ok) {
|
|
399
|
+
this.log("success", "Successful!", { payload });
|
|
400
|
+
|
|
401
|
+
try {
|
|
402
|
+
this.config.after(data);
|
|
403
|
+
} catch (error) {
|
|
404
|
+
this.log("error", error.message, {
|
|
405
|
+
after: this.config.after,
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
} else
|
|
409
|
+
this.log(
|
|
410
|
+
"error",
|
|
411
|
+
`Failed: ${response.status} (${response.statusText}). Details:`,
|
|
412
|
+
{ payload, response }
|
|
413
|
+
);
|
|
414
|
+
|
|
415
|
+
this.logs.length = 0;
|
|
416
|
+
})
|
|
353
417
|
)
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
if (response.ok) {
|
|
359
|
-
this.log("warn", "Successful, with warnings. Details:", result);
|
|
360
|
-
|
|
361
|
-
try {
|
|
362
|
-
this.config.after(data);
|
|
363
|
-
} catch (error) {
|
|
364
|
-
this.log("error", error.message, {
|
|
365
|
-
after: this.config.after,
|
|
366
|
-
});
|
|
367
|
-
}
|
|
368
|
-
} else
|
|
369
|
-
this.log(
|
|
370
|
-
"error",
|
|
371
|
-
`Failed: ${response.status} (${response.statusText}). Details:`,
|
|
372
|
-
result
|
|
373
|
-
);
|
|
374
|
-
|
|
375
|
-
this.logs.length = 0;
|
|
376
|
-
})
|
|
377
|
-
.catch(() => {
|
|
378
|
-
if (response.ok) {
|
|
379
|
-
this.log(
|
|
380
|
-
"success",
|
|
381
|
-
"Successful!",
|
|
382
|
-
["viewed", "basketed", "purchased"].includes(this.config.type)
|
|
383
|
-
? { sku: data }
|
|
384
|
-
: data
|
|
385
|
-
);
|
|
386
|
-
|
|
387
|
-
try {
|
|
388
|
-
this.config.after(data);
|
|
389
|
-
} catch (error) {
|
|
390
|
-
this.log("error", error.message, {
|
|
391
|
-
after: this.config.after,
|
|
392
|
-
});
|
|
393
|
-
}
|
|
394
|
-
} else
|
|
395
|
-
this.log(
|
|
396
|
-
"error",
|
|
397
|
-
`Failed: ${response.status} (${response.statusText}). Details:`,
|
|
398
|
-
response
|
|
399
|
-
);
|
|
400
|
-
|
|
401
|
-
this.logs.length = 0;
|
|
402
|
-
})
|
|
403
|
-
)
|
|
404
|
-
.catch((error) => {
|
|
405
|
-
this.log("error", `Failed: ${error.message}`);
|
|
406
|
-
this.logs.length = 0;
|
|
407
|
-
});
|
|
418
|
+
.catch((error) => {
|
|
419
|
+
this.log("error", `Failed: ${error.message}`, { payload });
|
|
420
|
+
this.logs.length = 0;
|
|
421
|
+
});
|
|
408
422
|
}
|
|
409
423
|
}
|
|
410
424
|
|
package/dist/bundle.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! choreograph-create-pixel v1.4.
|
|
1
|
+
/*! choreograph-create-pixel v1.4.2 2024/08/27 */
|
|
2
2
|
class ChoreographCreatePixel {
|
|
3
3
|
constructor(userConfig) {
|
|
4
4
|
this.previouslyScrapedHash = null;
|
|
@@ -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.icons[this.config.type]} ${
|
|
87
|
-
this.config.
|
|
86
|
+
`%c⸬ create%c ${this.config.icons[this.config.type]} ${
|
|
87
|
+
this.config.type
|
|
88
88
|
} %c${message}`,
|
|
89
89
|
"background:black;color:white;border-radius:3px;padding:3px 6px",
|
|
90
90
|
"font-weight:bold",
|
|
@@ -194,6 +194,7 @@ class ChoreographCreatePixel {
|
|
|
194
194
|
}
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
+
// TO-DO: Move this to each method's end? Pageview conversions are currently recursive
|
|
197
198
|
setTimeout(() => this.cycle(), 750);
|
|
198
199
|
}
|
|
199
200
|
|
|
@@ -201,11 +202,7 @@ class ChoreographCreatePixel {
|
|
|
201
202
|
const ccpid = this.constructor.getQueryParameter("ccpid");
|
|
202
203
|
if (!ccpid) return this.log("warn", "ccpid query parameter not present");
|
|
203
204
|
|
|
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
|
-
)
|
|
205
|
+
if (!/^[0-9a-f]{20}$/.test(ccpid))
|
|
209
206
|
return this.log(
|
|
210
207
|
"error",
|
|
211
208
|
"ccpid query parameter is not formatted correctly"
|
|
@@ -214,16 +211,18 @@ class ChoreographCreatePixel {
|
|
|
214
211
|
const storageItemLabel = `choreograph-${this.config.label}`;
|
|
215
212
|
const storedCcpid = localStorage.getItem(storageItemLabel);
|
|
216
213
|
if (storedCcpid !== ccpid) localStorage.setItem(storageItemLabel, ccpid);
|
|
217
|
-
this.log("success", "
|
|
214
|
+
this.log("success", `Stored CCPID "${ccpid}" for "${this.config.label}"`);
|
|
218
215
|
}
|
|
219
216
|
|
|
220
217
|
convert() {
|
|
221
|
-
const
|
|
218
|
+
const label = `choreograph-${this.config.label}`;
|
|
219
|
+
const ccpid = localStorage.getItem(label);
|
|
222
220
|
|
|
223
221
|
if (!ccpid)
|
|
224
222
|
return this.log("warn", `"${this.config.label}" attribution not present`);
|
|
225
223
|
|
|
226
224
|
this.send(ccpid);
|
|
225
|
+
localStorage.removeItem(label);
|
|
227
226
|
}
|
|
228
227
|
|
|
229
228
|
scrape(element) {
|
|
@@ -296,113 +295,128 @@ class ChoreographCreatePixel {
|
|
|
296
295
|
}
|
|
297
296
|
|
|
298
297
|
send(data) {
|
|
298
|
+
let payload;
|
|
299
299
|
let url;
|
|
300
|
+
let method = "GET";
|
|
300
301
|
|
|
301
302
|
switch (this.config.type) {
|
|
302
|
-
case "scraper":
|
|
303
|
+
case "scraper": {
|
|
304
|
+
const { sku } = data;
|
|
305
|
+
delete data.sku;
|
|
306
|
+
|
|
307
|
+
payload = {
|
|
308
|
+
"advertiser-id": this.config.advertiser,
|
|
309
|
+
sku,
|
|
310
|
+
fields: data,
|
|
311
|
+
};
|
|
312
|
+
|
|
303
313
|
url = `https://d.lemonpi.io/scrapes${
|
|
304
314
|
this.config.debug ? "?validate=true" : ""
|
|
305
315
|
}`;
|
|
306
316
|
|
|
317
|
+
method = "POST";
|
|
307
318
|
break;
|
|
319
|
+
}
|
|
308
320
|
|
|
309
|
-
case "
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
"advertiser-id": this.config.advertiser,
|
|
317
|
-
})
|
|
318
|
-
)}`;
|
|
319
|
-
|
|
320
|
-
break;
|
|
321
|
+
case "viewed":
|
|
322
|
+
case "basketed":
|
|
323
|
+
case "purchased":
|
|
324
|
+
payload = {
|
|
325
|
+
"event-type": `product-${this.config.type}`,
|
|
326
|
+
sku: data,
|
|
327
|
+
};
|
|
321
328
|
|
|
322
|
-
default:
|
|
323
329
|
url = `https://d.lemonpi.io/a/${
|
|
324
330
|
this.config.advertiser
|
|
325
|
-
}/product/event?e=${encodeURIComponent(
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
331
|
+
}/product/event?e=${encodeURIComponent(JSON.stringify(payload))}`;
|
|
332
|
+
|
|
333
|
+
break;
|
|
334
|
+
|
|
335
|
+
case "conversion":
|
|
336
|
+
payload = {
|
|
337
|
+
version: 1,
|
|
338
|
+
type: "conversion",
|
|
339
|
+
name: this.config.label,
|
|
340
|
+
"conversion-attribution-id": data,
|
|
341
|
+
"advertiser-id": this.config.advertiser,
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
url = `https://content.lemonpi.io/track/event?e=${encodeURIComponent(
|
|
345
|
+
JSON.stringify(payload)
|
|
330
346
|
)}`;
|
|
331
347
|
|
|
332
348
|
break;
|
|
333
349
|
}
|
|
334
350
|
|
|
335
|
-
if (
|
|
351
|
+
if (
|
|
352
|
+
["viewed", "basketed", "purchased"].includes(this.config.type) &&
|
|
353
|
+
!this.config.debug
|
|
354
|
+
) {
|
|
336
355
|
new Image().src = url;
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
fetch(
|
|
360
|
+
url,
|
|
361
|
+
method === "POST"
|
|
362
|
+
? {
|
|
363
|
+
method: "POST",
|
|
364
|
+
headers: { "Content-Type": "application/json" },
|
|
365
|
+
body: JSON.stringify(payload),
|
|
366
|
+
}
|
|
367
|
+
: null
|
|
368
|
+
)
|
|
369
|
+
.then((response) =>
|
|
370
|
+
response
|
|
371
|
+
.json()
|
|
372
|
+
.then((result) => {
|
|
373
|
+
if (response.ok) {
|
|
374
|
+
this.log("warn", "Successful, with warnings. Details:", {
|
|
375
|
+
payload,
|
|
376
|
+
result,
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
try {
|
|
380
|
+
this.config.after(data);
|
|
381
|
+
} catch (error) {
|
|
382
|
+
this.log("error", error.message, {
|
|
383
|
+
after: this.config.after,
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
} else
|
|
387
|
+
this.log(
|
|
388
|
+
"error",
|
|
389
|
+
`Failed: ${response.status} (${response.statusText}). Details:`,
|
|
390
|
+
{ payload, result }
|
|
391
|
+
);
|
|
392
|
+
|
|
393
|
+
this.logs.length = 0;
|
|
394
|
+
})
|
|
395
|
+
.catch(() => {
|
|
396
|
+
if (response.ok) {
|
|
397
|
+
this.log("success", "Successful!", { payload });
|
|
398
|
+
|
|
399
|
+
try {
|
|
400
|
+
this.config.after(data);
|
|
401
|
+
} catch (error) {
|
|
402
|
+
this.log("error", error.message, {
|
|
403
|
+
after: this.config.after,
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
} else
|
|
407
|
+
this.log(
|
|
408
|
+
"error",
|
|
409
|
+
`Failed: ${response.status} (${response.statusText}). Details:`,
|
|
410
|
+
{ payload, response }
|
|
411
|
+
);
|
|
412
|
+
|
|
413
|
+
this.logs.length = 0;
|
|
414
|
+
})
|
|
351
415
|
)
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
if (response.ok) {
|
|
357
|
-
this.log("warn", "Successful, with warnings. Details:", result);
|
|
358
|
-
|
|
359
|
-
try {
|
|
360
|
-
this.config.after(data);
|
|
361
|
-
} catch (error) {
|
|
362
|
-
this.log("error", error.message, {
|
|
363
|
-
after: this.config.after,
|
|
364
|
-
});
|
|
365
|
-
}
|
|
366
|
-
} else
|
|
367
|
-
this.log(
|
|
368
|
-
"error",
|
|
369
|
-
`Failed: ${response.status} (${response.statusText}). Details:`,
|
|
370
|
-
result
|
|
371
|
-
);
|
|
372
|
-
|
|
373
|
-
this.logs.length = 0;
|
|
374
|
-
})
|
|
375
|
-
.catch(() => {
|
|
376
|
-
if (response.ok) {
|
|
377
|
-
this.log(
|
|
378
|
-
"success",
|
|
379
|
-
"Successful!",
|
|
380
|
-
["viewed", "basketed", "purchased"].includes(this.config.type)
|
|
381
|
-
? { sku: data }
|
|
382
|
-
: data
|
|
383
|
-
);
|
|
384
|
-
|
|
385
|
-
try {
|
|
386
|
-
this.config.after(data);
|
|
387
|
-
} catch (error) {
|
|
388
|
-
this.log("error", error.message, {
|
|
389
|
-
after: this.config.after,
|
|
390
|
-
});
|
|
391
|
-
}
|
|
392
|
-
} else
|
|
393
|
-
this.log(
|
|
394
|
-
"error",
|
|
395
|
-
`Failed: ${response.status} (${response.statusText}). Details:`,
|
|
396
|
-
response
|
|
397
|
-
);
|
|
398
|
-
|
|
399
|
-
this.logs.length = 0;
|
|
400
|
-
})
|
|
401
|
-
)
|
|
402
|
-
.catch((error) => {
|
|
403
|
-
this.log("error", `Failed: ${error.message}`);
|
|
404
|
-
this.logs.length = 0;
|
|
405
|
-
});
|
|
416
|
+
.catch((error) => {
|
|
417
|
+
this.log("error", `Failed: ${error.message}`, { payload });
|
|
418
|
+
this.logs.length = 0;
|
|
419
|
+
});
|
|
406
420
|
}
|
|
407
421
|
}
|
|
408
422
|
|
package/dist/bundle.iife.min.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/*! choreograph-create-pixel v1.4.
|
|
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
|
|
1
|
+
/*! choreograph-create-pixel v1.4.2 2024/08/27 */
|
|
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 o=null!=arguments[r]?arguments[r]:{};r%2?e(Object(o),!0).forEach((function(e){n(t,e,o[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(o)):e(Object(o)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(o,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,o(n.key),n)}}function n(e,t,r){return(t=o(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(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 i=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 o,i,c;return o=e,i=[{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 o=["%c⸬ create%c ".concat(this.config.icons[this.config.type]," ").concat(this.config.type," %c").concat(t),"background:black;color:white;border-radius:3px;padding:3px 6px","font-weight:bold","color:".concat(this.config.colors[e])];n&&o.push(n),(r=console).info.apply(r,o),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]{20}$/.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",'Stored CCPID "'.concat(e,'" for "').concat(this.config.label,'"'))}},{key:"convert",value:function(){var e="choreograph-".concat(this.config.label),t=localStorage.getItem(e);if(!t)return this.log("warn",'"'.concat(this.config.label,'" attribution not present'));this.send(t),localStorage.removeItem(e)}},{key:"scrape",value:function(e){var r,o=this,i=!1,c=function(t,r){var c=t;if("function"==typeof c)try{c=c(e)}catch(e){if(o.config.optional.includes(r))return;o.log("error",e.message,n({},r?"scrape.".concat(r):"scrape",c)),i=!0}return"string"==typeof c&&(c=c.replace(/\s+/g," ").trim()),null!=c&&""!==c||o.config.optional.includes(r)||(o.log("error","Value is empty",n({},r?"scrape.".concat(r):"scrape",c)),i=!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(o.config.scrape[r],r)))}),{});var a=JSON.stringify(r);if(!i&&this.previouslyScrapedHash!==a){try{this.config.before(r,(function(e){Array.isArray(e)?e.forEach((function(e){return o.send(e)})):o.send(e)}))}catch(e){this.log("error",e.message,{before:this.config.before})}this.previouslyScrapedHash=a,this.logs.length=0}}},{key:"send",value:function(e){var t,r,n=this,o="GET";switch(this.config.type){case"scraper":var i=e.sku;delete e.sku,t={"advertiser-id":this.config.advertiser,sku:i,fields:e},r="https://d.lemonpi.io/scrapes".concat(this.config.debug?"?validate=true":""),o="POST";break;case"viewed":case"basketed":case"purchased":t={"event-type":"product-".concat(this.config.type),sku:e},r="https://d.lemonpi.io/a/".concat(this.config.advertiser,"/product/event?e=").concat(encodeURIComponent(JSON.stringify(t)));break;case"conversion":t={version:1,type:"conversion",name:this.config.label,"conversion-attribution-id":e,"advertiser-id":this.config.advertiser},r="https://content.lemonpi.io/track/event?e=".concat(encodeURIComponent(JSON.stringify(t)))}!["viewed","basketed","purchased"].includes(this.config.type)||this.config.debug?fetch(r,"POST"===o?{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)}:null).then((function(r){return r.json().then((function(o){if(r.ok){n.log("warn","Successful, with warnings. Details:",{payload:t,result:o});try{n.config.after(e)}catch(e){n.log("error",e.message,{after:n.config.after})}}else n.log("error","Failed: ".concat(r.status," (").concat(r.statusText,"). Details:"),{payload:t,result:o});n.logs.length=0})).catch((function(){if(r.ok){n.log("success","Successful!",{payload:t});try{n.config.after(e)}catch(e){n.log("error",e.message,{after:n.config.after})}}else n.log("error","Failed: ".concat(r.status," (").concat(r.statusText,"). Details:"),{payload:t,response:r});n.logs.length=0}))})).catch((function(e){n.log("error","Failed: ".concat(e.message),{payload:t}),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,o=void 0!==n&&n,i="".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),o=c.get(t);return null!=o?(i+="".concat(r).concat(n).concat(""===o?"":"=".concat(encodeURI(o))),!0):e}),!1),o&&(i+=location.hash),i}},{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]}}],i&&r(o.prototype,i),c&&r(o,c),Object.defineProperty(o,"prototype",{writable:!1}),e}();return i}();
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
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.
|
|
4
|
+
"version": "1.4.2",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"wpp",
|
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
"opendc",
|
|
12
12
|
"greenhouse"
|
|
13
13
|
],
|
|
14
|
-
"author": "Rick Stevens <rick.stevens@choreograph.com> (https://
|
|
14
|
+
"author": "Rick Stevens <rick.stevens@choreograph.com> (https://create.choreograph.com)",
|
|
15
15
|
"repository": "gitlab:2sixty/choreograph-create/solutions/choreograph-create-pixel",
|
|
16
|
-
"homepage": "https://
|
|
16
|
+
"homepage": "https://create.choreograph.com",
|
|
17
17
|
"license": "ISC",
|
|
18
18
|
"main": "dist/bundle.cjs.js",
|
|
19
19
|
"module": "dist/bundle.esm.js",
|