From a0a39272091ad6137f96b5bc5b3af6126552144a Mon Sep 17 00:00:00 2001 From: Marius Andra Date: Fri, 13 Dec 2024 09:48:27 +0100 Subject: [PATCH 01/14] feat(cdp): snapchat pixel --- frontend/public/services/snapchat.png | Bin 0 -> 7164 bytes frontend/src/loadPostHogJS.tsx | 1 + posthog/cdp/templates/__init__.py | 2 + .../templates/snapchat_ads/template_pixel.py | 268 ++++++++++++++++++ 4 files changed, 271 insertions(+) create mode 100644 frontend/public/services/snapchat.png create mode 100644 posthog/cdp/templates/snapchat_ads/template_pixel.py diff --git a/frontend/public/services/snapchat.png b/frontend/public/services/snapchat.png new file mode 100644 index 0000000000000000000000000000000000000000..4fd5486e6dd774947906056b39e002fc2fb931df GIT binary patch literal 7164 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 UA@!;k{x(vVdHydV!1?^Y074BUGXMYp literal 0 HcmV?d00001 diff --git a/frontend/src/loadPostHogJS.tsx b/frontend/src/loadPostHogJS.tsx index badabf1105246..4dfc4e30ee47f 100644 --- a/frontend/src/loadPostHogJS.tsx +++ b/frontend/src/loadPostHogJS.tsx @@ -67,6 +67,7 @@ export function loadPostHogJS(): void { capture_copied_text: true, }, person_profiles: 'always', + __preview_remote_config: true, // Helper to capture events for assertions in Cypress _onCapture: (window as any)._cypress_posthog_captures diff --git a/posthog/cdp/templates/__init__.py b/posthog/cdp/templates/__init__.py index 57a53d0ab9276..c29dc9e925814 100644 --- a/posthog/cdp/templates/__init__.py +++ b/posthog/cdp/templates/__init__.py @@ -47,6 +47,7 @@ from ._siteapps.template_debug_posthog import template as debug_posthog from ._internal.template_broadcast import template_new_broadcast as _broadcast from ._internal.template_blank import blank_site_destination, blank_site_app +from .snapchat_ads.template_pixel import template_snapchat_pixel as snapchat_pixel HOG_FUNCTION_TEMPLATES = [ _broadcast, @@ -98,6 +99,7 @@ notification_bar, pineapple_mode, debug_posthog, + snapchat_pixel, ] diff --git a/posthog/cdp/templates/snapchat_ads/template_pixel.py b/posthog/cdp/templates/snapchat_ads/template_pixel.py new file mode 100644 index 0000000000000..669fa0a4bc0dc --- /dev/null +++ b/posthog/cdp/templates/snapchat_ads/template_pixel.py @@ -0,0 +1,268 @@ +from posthog.cdp.templates.hog_function_template import HogFunctionMappingTemplate, HogFunctionTemplate + +template_snapchat_pixel: HogFunctionTemplate = HogFunctionTemplate( + status="client-side", + type="site_destination", + id="template-snapchat-pixel", + name="Snapchat Pixel", + description="Track how many Snapchat users interact with your website.", + icon_url="/static/services/snapchat.png", + category=["Advertisement"], + hog=""" +// Adds window.snaptr and lazily loads the Snapchat Pixel script +function initSnippet() { + console.log('SNAP: initSnippet'); + (function(e,t,n){if(e.snaptr)return;var a=e.snaptr=function() + {a.handleRequest?a.handleRequest.apply(a,arguments):a.queue.push(arguments)}; + a.queue=[];var s='script';r=t.createElement(s);r.async=!0; + r.src=n;var u=t.getElementsByTagName(s)[0]; + u.parentNode.insertBefore(r,u);})(window,document, + 'https://sc-static.net/scevent.min.js'); +} + +export function onLoad({ inputs }) { + initSnippet(); + console.log('SNAP: onLoad'); + let userProperties = {}; + for (const [key, value] of Object.entries(inputs.userProperties)) { + if (value) { + userProperties[key] = value; + } + }; + console.log('SNAP: onLoad/end', userProperties); + snaptr('init', inputs.pixelId, userProperties); +} +export function onEvent({ inputs }) { + console.log('SNAP: onEvent'); + let eventProperties = {}; + for (const [key, value] of Object.entries(inputs.eventProperties)) { + if (value) { + eventProperties[key] = value; + } + }; + for (const [key, value] of Object.entries(inputs.additionalProperties)) { + if (value) { + eventProperties[key] = value; + } + }; + console.log('SNAP: onEvent/end', eventProperties); + snaptr('track', 'PAGE_VIEW', eventProperties); +} +""".strip(), + inputs_schema=[ + { + "key": "pixelId", + "type": "string", + "label": "Pixel ID", + "description": "You must obtain a Pixel ID to use the Snapchat Pixel. If you've already set up a Pixel for your website, we recommend that you use the same Pixel ID for your browser and server events.", + "default": "", + "secret": False, + "required": True, + }, + { + "key": "userProperties", + "type": "dictionary", + "description": "Map of Snapchat user parameters and their values. Check out this page for more details: https://businesshelp.snapchat.com/s/article/pixel-direct-implementation", + "label": "User parameters", + "default": { + "user_email": "{person.properties.email}", + }, + "secret": False, + "required": False, + }, + { + "key": "eventProperties", + "type": "dictionary", + "description": "Map of Snapchat event attributes and their values. Check out this page for more details: https://businesshelp.snapchat.com/s/article/pixel-direct-implementation", + "label": "Event parameters", + "default": { + "price": "{toFloat(event.properties.price or event.properties.value or event.properties.revenue)}", + "currency": "{event.properties.currency}", + "item_category": "{event.properties.category}", + "description": "{event.properties.description}", + "search_string": "{event.properties.search_string}", + "number_items": "{toInt(event.properties.number_items or event.properties.quantity)}", + "payment_info_available": "{toInt(event.properties.payment_info_available)}", + "sign_up_method": "{event.properties.sign_up_method}", + "success": "{toInt(event.properties.success) in (0, 1) ? toInt(event.properties.success) : null}", + "payment_info_available": "{toInt(event.properties.payment_info_available) in (0, 1) ? toInt(event.properties.payment_info_available) : null}", + "client_deduplication_id": "{event.uuid}", + }, + "secret": False, + "required": False, + }, + { + "key": "itemIds", + "type": "string", + "label": "Item IDs", + "description": "Array of item IDs, for events that require it.", + "default": "{event.properties.item_ids}", + "required": True, + }, + { + "key": "transactionId", + "type": "string", + "label": "Transaction ID", + "description": "Unique key for this transaction, for events that require it", + "default": "{event.properties.orderId ?? event.properties.transactionId ?? event.properties.transaction_id ?? event.uuid}", + "required": True, + }, + ], + mapping_templates=[ + HogFunctionMappingTemplate( + name="Order completed", + include_by_default=True, + filters={"events": [{"id": "Order completed", "type": "events"}]}, + inputs_schema=[ + { + "key": "additionalProperties", + "type": "dictionary", + "description": "Additional properties to add for this event type", + "label": "Additional parameters", + "default": { + "item_ids": "{inputs.itemIds}", + "transaction_id": "{inputs.transactionId}", + }, + }, + ], + ), + HogFunctionMappingTemplate( + name="Checkout started", + filters={"events": [{"id": "Checkout started", "type": "events"}]}, + inputs_schema=[ + { + "key": "additionalProperties", + "type": "dictionary", + "description": "Additional properties to add for this event type", + "label": "Additional parameters", + "default": { + "item_ids": "{inputs.itemIds}", + "transaction_id": "{inputs.transactionId}", + }, + }, + ], + ), + HogFunctionMappingTemplate( + name="Product added", + filters={"events": [{"id": "Product added", "type": "events"}]}, + inputs_schema=[ + { + "key": "additionalProperties", + "type": "dictionary", + "description": "Additional properties to add for this event type", + "label": "Additional parameters", + "default": { + "item_ids": "{inputs.itemIds}", + }, + }, + ], + ), + HogFunctionMappingTemplate( + name="Payment info entered", + filters={"events": [{"id": "Payment info entered", "type": "events"}]}, + inputs_schema=[ + { + "key": "additionalProperties", + "type": "dictionary", + "description": "Additional properties to add for this event type", + "label": "Additional parameters", + "default": { + "item_ids": "{inputs.itemIds}", + "transaction_id": "{inputs.transactionId}", + }, + }, + ], + ), + HogFunctionMappingTemplate( + name="Promotion clicked", + filters={"events": [{"id": "Promotion clicked", "type": "events"}]}, + inputs_schema=[ + { + "key": "additionalProperties", + "type": "dictionary", + "description": "Additional properties to add for this event type", + "label": "Additional parameters", + "default": { + "item_ids": "{inputs.itemIds}", + }, + }, + ], + ), + HogFunctionMappingTemplate( + name="Promotion viewed", + filters={"events": [{"id": "Promotion viewed", "type": "events"}]}, + inputs_schema=[ + { + "key": "additionalProperties", + "type": "dictionary", + "description": "Additional properties to add for this event type", + "label": "Additional parameters", + "default": { + "item_ids": "{inputs.itemIds}", + }, + }, + ], + ), + HogFunctionMappingTemplate( + name="Product added to wishlist", + filters={"events": [{"id": "Product added to wishlist", "type": "events"}]}, + inputs_schema=[ + { + "key": "additionalProperties", + "type": "dictionary", + "description": "Additional properties to add for this event type", + "label": "Additional parameters", + "default": { + "item_ids": "{inputs.itemIds}", + }, + }, + ], + ), + HogFunctionMappingTemplate( + name="Product viewed", + filters={"events": [{"id": "Product viewed", "type": "events"}]}, + inputs_schema=[ + { + "key": "additionalProperties", + "type": "dictionary", + "description": "Additional properties to add for this event type", + "label": "Additional parameters", + "default": { + "item_ids": "{inputs.itemIds}", + }, + }, + ], + ), + HogFunctionMappingTemplate( + name="Product list viewed", + filters={"events": [{"id": "Product list viewed", "type": "events"}]}, + inputs_schema=[ + { + "key": "additionalProperties", + "type": "dictionary", + "description": "Additional properties to add for this event type", + "label": "Additional parameters", + "default": { + "item_ids": "{inputs.itemIds}", + }, + }, + ], + ), + HogFunctionMappingTemplate( + name="Products searched", + filters={"events": [{"id": "Products searched", "type": "events"}]}, + inputs_schema=[ + { + "key": "additionalProperties", + "type": "dictionary", + "description": "Additional properties to add for this event type", + "label": "Additional parameters", + "default": { + "item_ids": "{inputs.itemIds}", + "search_string": "{event.properties.query}", + }, + }, + ], + ), + ], +) From 1a31100c084ebd6fdfc0c6731879459e7103becd Mon Sep 17 00:00:00 2001 From: MarconLP <13001502+MarconLP@users.noreply.github.com> Date: Sun, 15 Dec 2024 20:57:41 +0100 Subject: [PATCH 02/14] move properties outside of mappings and add event type input --- .../templates/snapchat_ads/template_pixel.py | 199 ++++++++++++------ 1 file changed, 136 insertions(+), 63 deletions(-) diff --git a/posthog/cdp/templates/snapchat_ads/template_pixel.py b/posthog/cdp/templates/snapchat_ads/template_pixel.py index 669fa0a4bc0dc..8f710867e7dda 100644 --- a/posthog/cdp/templates/snapchat_ads/template_pixel.py +++ b/posthog/cdp/templates/snapchat_ads/template_pixel.py @@ -46,7 +46,7 @@ } }; console.log('SNAP: onEvent/end', eventProperties); - snaptr('track', 'PAGE_VIEW', eventProperties); + snaptr('track', inputs.eventType, eventProperties); } """.strip(), inputs_schema=[ @@ -78,189 +78,262 @@ "default": { "price": "{toFloat(event.properties.price or event.properties.value or event.properties.revenue)}", "currency": "{event.properties.currency}", + "item_ids": "{event.properties.item_ids}", "item_category": "{event.properties.category}", "description": "{event.properties.description}", "search_string": "{event.properties.search_string}", "number_items": "{toInt(event.properties.number_items or event.properties.quantity)}", "payment_info_available": "{toInt(event.properties.payment_info_available)}", "sign_up_method": "{event.properties.sign_up_method}", + "brands": "{event.properties.brands}", "success": "{toInt(event.properties.success) in (0, 1) ? toInt(event.properties.success) : null}", - "payment_info_available": "{toInt(event.properties.payment_info_available) in (0, 1) ? toInt(event.properties.payment_info_available) : null}", - "client_deduplication_id": "{event.uuid}", + "transaction_id": "{event.properties.orderId ?? event.properties.transactionId ?? event.properties.transaction_id}", + "client_dedup_id": "{event.uuid}", }, "secret": False, "required": False, }, - { - "key": "itemIds", - "type": "string", - "label": "Item IDs", - "description": "Array of item IDs, for events that require it.", - "default": "{event.properties.item_ids}", - "required": True, - }, - { - "key": "transactionId", - "type": "string", - "label": "Transaction ID", - "description": "Unique key for this transaction, for events that require it", - "default": "{event.properties.orderId ?? event.properties.transactionId ?? event.properties.transaction_id ?? event.uuid}", - "required": True, - }, ], mapping_templates=[ + HogFunctionMappingTemplate( + name="Page viewed", + include_by_default=True, + filters={"events": [{"id": "$pageview", "name": "Pageview", "type": "events"}]}, + inputs_schema=[ + { + "key": "eventType", + "type": "string", + "label": "Event Type", + "description": "Check out this page for possible event types: https://businesshelp.snapchat.com/s/article/pixel-direct-implementation", + "default": "PAGE_VIEW", + "required": True, + }, + { + "key": "additionalProperties", + "type": "dictionary", + "description": "Additional properties to add for this event type", + "label": "Additional parameters", + "default": {}, + }, + ], + ), HogFunctionMappingTemplate( name="Order completed", include_by_default=True, - filters={"events": [{"id": "Order completed", "type": "events"}]}, + filters={"events": [{"id": "Order Completed", "type": "events"}]}, inputs_schema=[ + { + "key": "eventType", + "type": "string", + "label": "Event Type", + "description": "Check out this page for possible event types: https://businesshelp.snapchat.com/s/article/pixel-direct-implementation", + "default": "PURCHASE", + "required": True, + }, { "key": "additionalProperties", "type": "dictionary", "description": "Additional properties to add for this event type", "label": "Additional parameters", - "default": { - "item_ids": "{inputs.itemIds}", - "transaction_id": "{inputs.transactionId}", - }, + "default": {}, }, ], ), HogFunctionMappingTemplate( name="Checkout started", - filters={"events": [{"id": "Checkout started", "type": "events"}]}, + include_by_default=True, + filters={"events": [{"id": "Checkout Started", "type": "events"}]}, inputs_schema=[ + { + "key": "eventType", + "type": "string", + "label": "Event Type", + "description": "Check out this page for possible event types: https://businesshelp.snapchat.com/s/article/pixel-direct-implementation", + "default": "START_CHECKOUT", + "required": True, + }, { "key": "additionalProperties", "type": "dictionary", "description": "Additional properties to add for this event type", "label": "Additional parameters", - "default": { - "item_ids": "{inputs.itemIds}", - "transaction_id": "{inputs.transactionId}", - }, + "default": {}, }, ], ), HogFunctionMappingTemplate( name="Product added", - filters={"events": [{"id": "Product added", "type": "events"}]}, + include_by_default=True, + filters={"events": [{"id": "Product Added", "type": "events"}]}, inputs_schema=[ + { + "key": "eventType", + "type": "string", + "label": "Event Type", + "description": "Check out this page for possible event types: https://businesshelp.snapchat.com/s/article/pixel-direct-implementation", + "default": "ADD_CART", + "required": True, + }, { "key": "additionalProperties", "type": "dictionary", "description": "Additional properties to add for this event type", "label": "Additional parameters", - "default": { - "item_ids": "{inputs.itemIds}", - }, + "default": {}, }, ], ), HogFunctionMappingTemplate( name="Payment info entered", - filters={"events": [{"id": "Payment info entered", "type": "events"}]}, + include_by_default=True, + filters={"events": [{"id": "Payment Info Entered", "type": "events"}]}, inputs_schema=[ + { + "key": "eventType", + "type": "string", + "label": "Event Type", + "description": "Check out this page for possible event types: https://businesshelp.snapchat.com/s/article/pixel-direct-implementation", + "default": "ADD_BILLING", + "required": True, + }, { "key": "additionalProperties", "type": "dictionary", "description": "Additional properties to add for this event type", "label": "Additional parameters", - "default": { - "item_ids": "{inputs.itemIds}", - "transaction_id": "{inputs.transactionId}", - }, + "default": {}, }, ], ), HogFunctionMappingTemplate( name="Promotion clicked", - filters={"events": [{"id": "Promotion clicked", "type": "events"}]}, + include_by_default=True, + filters={"events": [{"id": "Promotion Clicked", "type": "events"}]}, inputs_schema=[ + { + "key": "eventType", + "type": "string", + "label": "Event Type", + "description": "Check out this page for possible event types: https://businesshelp.snapchat.com/s/article/pixel-direct-implementation", + "default": "AD_CLICK", + "required": True, + }, { "key": "additionalProperties", "type": "dictionary", "description": "Additional properties to add for this event type", "label": "Additional parameters", - "default": { - "item_ids": "{inputs.itemIds}", - }, + "default": {}, }, ], ), HogFunctionMappingTemplate( name="Promotion viewed", - filters={"events": [{"id": "Promotion viewed", "type": "events"}]}, + include_by_default=True, + filters={"events": [{"id": "Promotion Viewed", "type": "events"}]}, inputs_schema=[ + { + "key": "eventType", + "type": "string", + "label": "Event Type", + "description": "Check out this page for possible event types: https://businesshelp.snapchat.com/s/article/pixel-direct-implementation", + "default": "AD_VIEW", + "required": True, + }, { "key": "additionalProperties", "type": "dictionary", "description": "Additional properties to add for this event type", "label": "Additional parameters", - "default": { - "item_ids": "{inputs.itemIds}", - }, + "default": {}, }, ], ), HogFunctionMappingTemplate( name="Product added to wishlist", - filters={"events": [{"id": "Product added to wishlist", "type": "events"}]}, + include_by_default=True, + filters={"events": [{"id": "Product Added To Wishlist", "type": "events"}]}, inputs_schema=[ + { + "key": "eventType", + "type": "string", + "label": "Event Type", + "description": "Check out this page for possible event types: https://businesshelp.snapchat.com/s/article/pixel-direct-implementation", + "default": "ADD_TO_WISHLIST", + "required": True, + }, { "key": "additionalProperties", "type": "dictionary", "description": "Additional properties to add for this event type", "label": "Additional parameters", - "default": { - "item_ids": "{inputs.itemIds}", - }, + "default": {}, }, ], ), HogFunctionMappingTemplate( name="Product viewed", - filters={"events": [{"id": "Product viewed", "type": "events"}]}, + include_by_default=True, + filters={"events": [{"id": "Product Viewed", "type": "events"}]}, inputs_schema=[ + { + "key": "eventType", + "type": "string", + "label": "Event Type", + "description": "Check out this page for possible event types: https://businesshelp.snapchat.com/s/article/pixel-direct-implementation", + "default": "VIEW_CONTENT", + "required": True, + }, { "key": "additionalProperties", "type": "dictionary", "description": "Additional properties to add for this event type", "label": "Additional parameters", - "default": { - "item_ids": "{inputs.itemIds}", - }, + "default": {}, }, ], ), HogFunctionMappingTemplate( name="Product list viewed", - filters={"events": [{"id": "Product list viewed", "type": "events"}]}, + include_by_default=True, + filters={"events": [{"id": "Product List Viewed", "type": "events"}]}, inputs_schema=[ + { + "key": "eventType", + "type": "string", + "label": "Event Type", + "description": "Check out this page for possible event types: https://businesshelp.snapchat.com/s/article/pixel-direct-implementation", + "default": "VIEW_CONTENT", + "required": True, + }, { "key": "additionalProperties", "type": "dictionary", "description": "Additional properties to add for this event type", "label": "Additional parameters", - "default": { - "item_ids": "{inputs.itemIds}", - }, + "default": {}, }, ], ), HogFunctionMappingTemplate( name="Products searched", - filters={"events": [{"id": "Products searched", "type": "events"}]}, + include_by_default=True, + filters={"events": [{"id": "Products Searched", "type": "events"}]}, inputs_schema=[ + { + "key": "eventType", + "type": "string", + "label": "Event Type", + "description": "Check out this page for possible event types: https://businesshelp.snapchat.com/s/article/pixel-direct-implementation", + "default": "SEARCH", + "required": True, + }, { "key": "additionalProperties", "type": "dictionary", "description": "Additional properties to add for this event type", "label": "Additional parameters", - "default": { - "item_ids": "{inputs.itemIds}", - "search_string": "{event.properties.query}", - }, + "default": {}, }, ], ), From 6aa1fb0d808946723f7f4a5d42351815afd369cf Mon Sep 17 00:00:00 2001 From: MarconLP <13001502+MarconLP@users.noreply.github.com> Date: Sun, 15 Dec 2024 21:29:42 +0100 Subject: [PATCH 03/14] fix event names --- .../templates/snapchat_ads/template_pixel.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/posthog/cdp/templates/snapchat_ads/template_pixel.py b/posthog/cdp/templates/snapchat_ads/template_pixel.py index 8f710867e7dda..e11d6670b05ea 100644 --- a/posthog/cdp/templates/snapchat_ads/template_pixel.py +++ b/posthog/cdp/templates/snapchat_ads/template_pixel.py @@ -120,7 +120,7 @@ HogFunctionMappingTemplate( name="Order completed", include_by_default=True, - filters={"events": [{"id": "Order Completed", "type": "events"}]}, + filters={"events": [{"id": "Order completed", "type": "events"}]}, inputs_schema=[ { "key": "eventType", @@ -142,7 +142,7 @@ HogFunctionMappingTemplate( name="Checkout started", include_by_default=True, - filters={"events": [{"id": "Checkout Started", "type": "events"}]}, + filters={"events": [{"id": "Checkout started", "type": "events"}]}, inputs_schema=[ { "key": "eventType", @@ -164,7 +164,7 @@ HogFunctionMappingTemplate( name="Product added", include_by_default=True, - filters={"events": [{"id": "Product Added", "type": "events"}]}, + filters={"events": [{"id": "Product added", "type": "events"}]}, inputs_schema=[ { "key": "eventType", @@ -186,7 +186,7 @@ HogFunctionMappingTemplate( name="Payment info entered", include_by_default=True, - filters={"events": [{"id": "Payment Info Entered", "type": "events"}]}, + filters={"events": [{"id": "Payment info entered", "type": "events"}]}, inputs_schema=[ { "key": "eventType", @@ -208,7 +208,7 @@ HogFunctionMappingTemplate( name="Promotion clicked", include_by_default=True, - filters={"events": [{"id": "Promotion Clicked", "type": "events"}]}, + filters={"events": [{"id": "Promotion clicked", "type": "events"}]}, inputs_schema=[ { "key": "eventType", @@ -230,7 +230,7 @@ HogFunctionMappingTemplate( name="Promotion viewed", include_by_default=True, - filters={"events": [{"id": "Promotion Viewed", "type": "events"}]}, + filters={"events": [{"id": "Promotion viewed", "type": "events"}]}, inputs_schema=[ { "key": "eventType", @@ -252,7 +252,7 @@ HogFunctionMappingTemplate( name="Product added to wishlist", include_by_default=True, - filters={"events": [{"id": "Product Added To Wishlist", "type": "events"}]}, + filters={"events": [{"id": "Product added to wishlist", "type": "events"}]}, inputs_schema=[ { "key": "eventType", @@ -274,7 +274,7 @@ HogFunctionMappingTemplate( name="Product viewed", include_by_default=True, - filters={"events": [{"id": "Product Viewed", "type": "events"}]}, + filters={"events": [{"id": "Product viewed", "type": "events"}]}, inputs_schema=[ { "key": "eventType", @@ -296,7 +296,7 @@ HogFunctionMappingTemplate( name="Product list viewed", include_by_default=True, - filters={"events": [{"id": "Product List Viewed", "type": "events"}]}, + filters={"events": [{"id": "Product list viewed", "type": "events"}]}, inputs_schema=[ { "key": "eventType", @@ -318,7 +318,7 @@ HogFunctionMappingTemplate( name="Products searched", include_by_default=True, - filters={"events": [{"id": "Products Searched", "type": "events"}]}, + filters={"events": [{"id": "Products searched", "type": "events"}]}, inputs_schema=[ { "key": "eventType", From cf8543dd991b6d7a2cdac7ac26ae7a9c52cf620e Mon Sep 17 00:00:00 2001 From: MarconLP <13001502+MarconLP@users.noreply.github.com> Date: Sun, 15 Dec 2024 21:40:09 +0100 Subject: [PATCH 04/14] fix fallback values --- posthog/cdp/templates/snapchat_ads/template_pixel.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/posthog/cdp/templates/snapchat_ads/template_pixel.py b/posthog/cdp/templates/snapchat_ads/template_pixel.py index e11d6670b05ea..a76e8a4e0fd25 100644 --- a/posthog/cdp/templates/snapchat_ads/template_pixel.py +++ b/posthog/cdp/templates/snapchat_ads/template_pixel.py @@ -76,13 +76,13 @@ "description": "Map of Snapchat event attributes and their values. Check out this page for more details: https://businesshelp.snapchat.com/s/article/pixel-direct-implementation", "label": "Event parameters", "default": { - "price": "{toFloat(event.properties.price or event.properties.value or event.properties.revenue)}", + "price": "{toFloat(event.properties.price ?? event.properties.value ?? event.properties.revenue)}", "currency": "{event.properties.currency}", "item_ids": "{event.properties.item_ids}", "item_category": "{event.properties.category}", "description": "{event.properties.description}", "search_string": "{event.properties.search_string}", - "number_items": "{toInt(event.properties.number_items or event.properties.quantity)}", + "number_items": "{toInt(event.properties.number_items ?? event.properties.quantity)}", "payment_info_available": "{toInt(event.properties.payment_info_available)}", "sign_up_method": "{event.properties.sign_up_method}", "brands": "{event.properties.brands}", From 00961fe20c6d488b5cdf746b3ee8dc16c46e611d Mon Sep 17 00:00:00 2001 From: MarconLP <13001502+MarconLP@users.noreply.github.com> Date: Mon, 16 Dec 2024 10:14:34 +0100 Subject: [PATCH 05/14] remove console.log calls --- posthog/cdp/templates/snapchat_ads/template_pixel.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/posthog/cdp/templates/snapchat_ads/template_pixel.py b/posthog/cdp/templates/snapchat_ads/template_pixel.py index a76e8a4e0fd25..0b21915bd4704 100644 --- a/posthog/cdp/templates/snapchat_ads/template_pixel.py +++ b/posthog/cdp/templates/snapchat_ads/template_pixel.py @@ -11,7 +11,6 @@ hog=""" // Adds window.snaptr and lazily loads the Snapchat Pixel script function initSnippet() { - console.log('SNAP: initSnippet'); (function(e,t,n){if(e.snaptr)return;var a=e.snaptr=function() {a.handleRequest?a.handleRequest.apply(a,arguments):a.queue.push(arguments)}; a.queue=[];var s='script';r=t.createElement(s);r.async=!0; @@ -22,18 +21,15 @@ export function onLoad({ inputs }) { initSnippet(); - console.log('SNAP: onLoad'); let userProperties = {}; for (const [key, value] of Object.entries(inputs.userProperties)) { if (value) { userProperties[key] = value; } }; - console.log('SNAP: onLoad/end', userProperties); snaptr('init', inputs.pixelId, userProperties); } export function onEvent({ inputs }) { - console.log('SNAP: onEvent'); let eventProperties = {}; for (const [key, value] of Object.entries(inputs.eventProperties)) { if (value) { @@ -45,7 +41,6 @@ eventProperties[key] = value; } }; - console.log('SNAP: onEvent/end', eventProperties); snaptr('track', inputs.eventType, eventProperties); } """.strip(), From 34ae5b5ca2e1bd2de0b94232b415ebe57524d1bc Mon Sep 17 00:00:00 2001 From: MarconLP <13001502+MarconLP@users.noreply.github.com> Date: Mon, 16 Dec 2024 10:31:54 +0100 Subject: [PATCH 06/14] add server side snapchat conversions destination --- posthog/cdp/templates/__init__.py | 4 +- .../snapchat_ads/template_snapchat_ads.py | 139 ++++++++++++++++++ 2 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 posthog/cdp/templates/snapchat_ads/template_snapchat_ads.py diff --git a/posthog/cdp/templates/__init__.py b/posthog/cdp/templates/__init__.py index c29dc9e925814..fd8c9d03014a2 100644 --- a/posthog/cdp/templates/__init__.py +++ b/posthog/cdp/templates/__init__.py @@ -47,6 +47,7 @@ from ._siteapps.template_debug_posthog import template as debug_posthog from ._internal.template_broadcast import template_new_broadcast as _broadcast from ._internal.template_blank import blank_site_destination, blank_site_app +from .snapchat_ads.template_snapchat_ads import template as snapchat_ads from .snapchat_ads.template_pixel import template_snapchat_pixel as snapchat_pixel HOG_FUNCTION_TEMPLATES = [ @@ -92,6 +93,8 @@ salesforce_create, salesforce_update, sendgrid, + snapchat_ads, + snapchat_pixel, zapier, zendesk, early_access_features, @@ -99,7 +102,6 @@ notification_bar, pineapple_mode, debug_posthog, - snapchat_pixel, ] diff --git a/posthog/cdp/templates/snapchat_ads/template_snapchat_ads.py b/posthog/cdp/templates/snapchat_ads/template_snapchat_ads.py new file mode 100644 index 0000000000000..38b6cfe3ed45c --- /dev/null +++ b/posthog/cdp/templates/snapchat_ads/template_snapchat_ads.py @@ -0,0 +1,139 @@ +from posthog.cdp.templates.hog_function_template import HogFunctionTemplate + +template: HogFunctionTemplate = HogFunctionTemplate( + status="alpha", + type="destination", + id="template-snapchat-ads", + name="Snapchat Ads Conversions", + description="Send conversion events to Snapchat Ads", + icon_url="/static/services/snapchat.png", + category=["Advertisement"], + hog=""" +let body := { + 'data': [ + { + 'event_name': inputs.eventName, + 'action_source': inputs.actionSource, + 'event_time': inputs.eventTime, + 'user_data': {}, + 'custom_data': {} + } + ] +} + +if (not empty(event.properties.$current_url)) body.data.1.event_source_url := event.properties.$current_url + +for (let key, value in inputs.userData) { + if (not empty(value)) { + body.data.1.user_data[key] := value + } +} + +for (let key, value in inputs.customData) { + if (not empty(value)) { + body.data.1.custom_data[key] := value + } +} + +let res := fetch(f'https://tr.snapchat.com/v3/{inputs.pixelId}/events?access_token={inputs.accessToken}', { + 'method': 'POST', + 'headers': { + 'Content-Type': 'application/json', + }, + 'body': body +}) +if (res.status >= 400) { + throw Error(f'Error from tr.snapchat.com (status {res.status}): {res.body}') +} +""".strip(), + inputs_schema=[ + { + "key": "accessToken", + "type": "string", + "label": "Access token", + "description": "Check out this page on how to obtain such a token: https://developers.snap.com/api/marketing-api/Conversions-API/GetStarted#access-token", + "secret": True, + "required": True, + }, + { + "key": "pixelId", + "type": "string", + "label": "Pixel ID", + "description": "You must obtain a Pixel ID to use the Conversions API. If you’ve already set up a Pixel for your website, we recommend that you use the same Pixel ID for your browser and server events.", + "secret": False, + "required": True, + }, + { + "key": "eventName", + "type": "string", + "label": "Event name", + "description": "A standard event or custom event name.", + "default": "{event.event}", + "secret": False, + "required": True, + }, + { + "key": "eventTime", + "type": "string", + "label": "Event time", + "description": "A Unix timestamp in seconds indicating when the actual event occurred. You must send this date in GMT time zone.", + "default": "{toUnixTimestampMilli(event.timestamp)}", + "secret": False, + "required": True, + }, + { + "key": "actionSource", + "label": "Action source", + "type": "choice", + "choices": [ + { + "label": "WEB - Conversion was made on your website.", + "value": "WEB", + }, + { + "label": "MOBILE_APP - Conversion was made on your mobile app.", + "value": "MOBILE_APP", + }, + { + "label": "OFFLINE - Conversion happened in a way that is not listed.", + "value": "OFFLINE", + }, + ], + "description": "This field allows you to specify where your conversions occurred. Knowing where your events took place helps ensure your ads go to the right people.", + "default": "website", + "secret": False, + "required": True, + }, + { + "key": "userData", + "type": "dictionary", + "label": "User data", + "description": "A map that contains customer information data. See this page for options: https://developers.snap.com/api/marketing-api/Conversions-API/Parameters#user-data-parameters", + "default": { + "em": "{sha256Hex(person.properties.email ?? '')}", + "ph": "{sha256Hex(person.properties.phone ?? '')}", + "sc_click_id": "{person.properties.sccid ?? person.properties.$initial_sccid ?? ''}", + }, + "secret": False, + "required": True, + }, + { + "key": "customData", + "type": "dictionary", + "label": "Custom data", + "description": "A map that contains custom data. See this page for options: https://developers.snap.com/api/marketing-api/Conversions-API/Parameters#custom-data-parameters", + "default": { + "currency": "USD", + "value": "{event.properties.price}", + "event_id": "{event.uuid}", + }, + "secret": False, + "required": True, + }, + ], + filters={ + "events": [], + "actions": [], + "filter_test_accounts": True, + }, +) From ea5e60cd415efd427a7b660cfeb05db9a5237c4d Mon Sep 17 00:00:00 2001 From: MarconLP <13001502+MarconLP@users.noreply.github.com> Date: Tue, 17 Dec 2024 11:57:01 +0100 Subject: [PATCH 07/14] add snapchat oauth integration --- .run/PostHog.run.xml | 2 +- .../src/lib/integrations/integrationsLogic.ts | 2 + frontend/src/types.ts | 1 + .../templates/snapchat_ads/template_pixel.py | 143 ++------ .../snapchat_ads/template_snapchat_ads.py | 347 ++++++++++++++---- .../migrations/0489_alter_integration_kind.py | 1 + posthog/models/integration.py | 20 +- posthog/settings/integrations.py | 3 + 8 files changed, 348 insertions(+), 171 deletions(-) diff --git a/.run/PostHog.run.xml b/.run/PostHog.run.xml index 32624c2ec1c8f..4d02e04919841 100644 --- a/.run/PostHog.run.xml +++ b/.run/PostHog.run.xml @@ -1,7 +1,7 @@ -