diff --git a/cmd/tagmanager/server.go b/cmd/tagmanager/server.go index 463fbfb..229c5e0 100644 --- a/cmd/tagmanager/server.go +++ b/cmd/tagmanager/server.go @@ -9,6 +9,7 @@ import ( googleadsprovider "github.com/foomo/sesamy-cli/pkg/provider/googleads" googleanalyticsprovider "github.com/foomo/sesamy-cli/pkg/provider/googleanalytics" googletagmanagerprovider "github.com/foomo/sesamy-cli/pkg/provider/googletagmanager" + microsoftadsprovider "github.com/foomo/sesamy-cli/pkg/provider/microsoftads" tracifyprovider "github.com/foomo/sesamy-cli/pkg/provider/tracify" umamiprovider "github.com/foomo/sesamy-cli/pkg/provider/umami" "github.com/foomo/sesamy-cli/pkg/tagmanager" @@ -109,6 +110,13 @@ func NewServer(root *cobra.Command) { } } + if cfg.MicrosoftAds.Enabled && pkgcmd.Tag(microsoftadsprovider.Tag, tags) { + l.Info("🅿️ Running provider", "name", microsoftadsprovider.Name, "tag", microsoftadsprovider.Tag) + if err := microsoftadsprovider.Server(l, tm, cfg.MicrosoftAds); err != nil { + return errors.Wrap(err, "failed to provision microsoftads") + } + } + return nil }, } diff --git a/pkg/config/config.go b/pkg/config/config.go index 01b7912..5352827 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -21,6 +21,8 @@ type Config struct { ConversionLinker ConversionLinker `json:"conversionLinker" yaml:"conversionLinker"` // Facebook provider settings Facebook Facebook `json:"facebook" yaml:"facebook"` + // MicrosoftAds provider settings + MicrosoftAds MicrosoftAds `json:"microsoftAds" yaml:"microsoftAds"` // Emarsys provider settings Emarsys Emarsys `json:"emarsys" yaml:"emarsys"` // Hotjar provider settings diff --git a/pkg/config/microsoftads.go b/pkg/config/microsoftads.go new file mode 100644 index 0000000..ade76de --- /dev/null +++ b/pkg/config/microsoftads.go @@ -0,0 +1,12 @@ +package config + +type MicrosoftAds struct { + // Enable provider + Enabled bool `json:"enabled" yaml:"enabled"` + // Google Consent settings + GoogleConsent GoogleConsent `json:"googleConsent" yaml:"googleConsent"` + // Microsoft Ads UET Tag ID + TagID string `json:"tagId" yaml:"tagId"` + // Microsoft Ads Conversion settings + Conversion MicrosoftAdsConversion `json:"conversion" yaml:"conversion"` +} diff --git a/pkg/config/microsoftadsconversion.go b/pkg/config/microsoftadsconversion.go new file mode 100644 index 0000000..c3acef4 --- /dev/null +++ b/pkg/config/microsoftadsconversion.go @@ -0,0 +1,29 @@ +package config + +import ( + "github.com/foomo/gocontemplate/pkg/contemplate" +) + +type MicrosoftAdsConversion struct { + // Enable provider + Enabled bool `json:"enabled" yaml:"enabled"` + // Google Tag Manager server container settings + ServerContainer MicrosoftAdsServerContainer `json:"serverContainer" yaml:"serverContainer"` +} + +type MicrosoftAdsServerContainer struct { + contemplate.Config `json:",inline" yaml:",squash"` + Settings map[string]MicrosoftAdsConversionTag `json:"settings" yaml:"settings"` +} + +type MicrosoftAdsConversionTag struct { + PageType string `json:"pageType" yaml:"pageType"` + EventType string `json:"eventType" yaml:"eventType"` +} + +func (s *MicrosoftAdsServerContainer) Setting(eventName string) MicrosoftAdsConversionTag { + if value, ok := s.Settings[eventName]; ok { + return value + } + return MicrosoftAdsConversionTag{} +} diff --git a/pkg/provider/microsoft/server/template/data/conversion/code.js b/pkg/provider/microsoft/server/template/data/conversion/code.js deleted file mode 100644 index 34f0a28..0000000 --- a/pkg/provider/microsoft/server/template/data/conversion/code.js +++ /dev/null @@ -1,200 +0,0 @@ -const sendHttpGet = require('sendHttpGet'); -const getEventData = require('getEventData'); -const generateRandom = require('generateRandom'); -const logToConsole = require('logToConsole'); -const Math = require('Math'); -const encodeUriComponent = require('encodeUriComponent'); -const JSON = require('JSON'); -const getCookieValues = require('getCookieValues'); -const setCookie = require('setCookie'); -const parseUrl = require('parseUrl'); - - -let clickid; -function isNotEmpty(obj) { - if (obj === undefined || obj === null || obj.toString() === "" ) { - return false; - } else { - return obj; - } -} - -let msquery = () => { - const url = parseUrl(getEventData('page_location')); - if (url && url.searchParams.msclkid) { - return url.searchParams.msclkid; - } else { - return false; - } -}; - -function setUETCookie(clickid) { - setCookie('_uetmsclkid', "_uet"+clickid, {"expires":7776000000, httpOnly: false}); - logToConsole("Cookie set: " + clickid); -} - -if(data.first_click) { - if (isNotEmpty(data.msclkidCookie) || isNotEmpty(getCookieValues('_uetmsclkid'))) { - let clickid_cookie = getCookieValues('_uetmsclkid')[0]; - clickid = (isNotEmpty(data.msclkidCookie) || (clickid_cookie.substring(4))); - clickid += "-0"; - } else { //cookie not present - if (isNotEmpty(data.msclkidQuery) || msquery()) { - clickid = (isNotEmpty(data.msclkidQuery) || msquery()); - setUETCookie(clickid); - clickid += "-1"; - } else { - clickid = "N"; - } - } -} else { - if (isNotEmpty(data.msclkidQuery) || msquery()) { - clickid = (isNotEmpty(data.msclkidQuery) || msquery()); - setUETCookie(clickid); - clickid += "-1"; - } else { - if(isNotEmpty(data.msclkidCookie) || isNotEmpty(getCookieValues('_uetmsclkid'))){ - let clickid_cookie = getCookieValues('_uetmsclkid')[0]; - clickid = (isNotEmpty(data.msclkidCookie) || (clickid_cookie.substring(4))); - clickid += "-0"; - } else { - clickid = "N"; - } - } -} - - -const screen = data.screen || getEventData('screen_resolution'); - -let width, height = ""; -if (isNotEmpty(screen)){ - width = screen.split('x')[0]; - height = screen.split('x')[1]; - -} -let rn = generateRandom(100000, 999999); -function s4() { - return Math.floor(((1 + (generateRandom(1, 9999999)/10000000))) * 65536) - .toString(16) - .substring(1); -} - -let mid = (s4() + s4() + "-" + s4() + "-" + s4() + "-" + s4() + "-" + s4() + s4() + s4()); -let items_data; -if(isNotEmpty(getEventData('items'))){ - items_data = getEventData('items'); -} - -let items = () => { - let result = ""; - if(isNotEmpty(data.prodid)){ - items_data = data.prodid; - } - if (data.itemsGa) { - if(items_data) { - items_data.forEach(function(item, i) { - result += "id=" + item.item_id + 'quantity=' + item.quantity + 'price=' + item.price; - if (i < items_data.length - 1) { - result += ','; - } - }); - } - } else { - result = items_data; - } - return result; -}; - - -let items_id = () => { - let result = ""; - if(isNotEmpty(data.items)){ - items_data = data.items; - } - if(data.prodidGa) { - if (items_data) { - items_data.forEach(function(item, i) { - result += item.item_id; - if (i < items_data.length - 1) { - result += ','; - } - }); - } - } - return result; -}; - -let spa = () => { - if(data.spa) { - return "Y"; - } else { - return "N"; - } -}; - -let params = { - rn: rn, - ti: data.ti, - ver: '2.3', - mid: mid, - uid: isNotEmpty(data.userId) || getEventData('user_id'), - evt: data.evt, - p: getEventData('page_location'), - r: getEventData('page_referrer'), - tl: isNotEmpty(data.pageTitle) || getEventData('page_title'), - pagetype: data.pagetype, - items: items(), - prodid: items_id(), - search_term: isNotEmpty(data.searchTerm) || getEventData('search_term'), - transaction_id: isNotEmpty(data.transactionId) || getEventData('transaction_id'), - lg: isNotEmpty(data.lg) || getEventData('language'), - sw: width, - sh: height, - sc: data.sc || getEventData('screen_color_depth'), - spa: spa(), - msclkid: clickid, - sid: isNotEmpty(data.sid) || getEventData('uet_session_id'), - vid: isNotEmpty(data.vid) || getEventData('vid'), - page_path: isNotEmpty(data.pagePath) || getEventData('page_path'), - gc: getEventData('currency'), - gv: getEventData('value'), - ec: isNotEmpty(data.ec) || getEventData('event_category'), - ea: isNotEmpty(data.ea) || getEventData('event_action'), - el: isNotEmpty(data.el) || getEventData('event_label'), - ev: isNotEmpty(data.ev) || getEventData('event_value'), -}; - - -if (data.activateLogs) { - logToConsole("Params: " + JSON.stringify(params)); -} - - -let url = 'https://bat.bing.com/action/0?'; -let all_params = ""; -if(isNotEmpty(params)){ - for (var key in params){ - if (params[key] == undefined || params[key] == null) { - continue; - } - all_params += key + "=" + encodeUriComponent(params[key]) + "&"; - } - url += all_params; -} -if (data.activateLogs) { - logToConsole('URL: ' + url); -} - - -return sendHttpGet(url, { - headers: {key: 'value'}, - timeout: 500, -}).then((result) => { - if (result.statusCode >= 200 && result.statusCode < 300) { - logToConsole('Result: ' + data.gtmOnSuccess()); - data.gtmOnSuccess(); - } else { - logToConsole('Error: ' + result.statusCode); - data.gtmOnFailure(); - } -}); diff --git a/pkg/provider/microsoftads/constants.go b/pkg/provider/microsoftads/constants.go new file mode 100644 index 0000000..2326e2e --- /dev/null +++ b/pkg/provider/microsoftads/constants.go @@ -0,0 +1,8 @@ +package facebook + +const ( + Tag = "mads" + Name = "Microsoft Ads" + NameTagIDConstant = "Microsoft UET Tag ID" + NameConversionsTagTemplate = "Microsoft Ads Conversions" +) diff --git a/pkg/provider/microsoftads/server.go b/pkg/provider/microsoftads/server.go new file mode 100644 index 0000000..f5b9ba0 --- /dev/null +++ b/pkg/provider/microsoftads/server.go @@ -0,0 +1,70 @@ +package facebook + +import ( + "log/slog" + + "github.com/foomo/sesamy-cli/pkg/config" + "github.com/foomo/sesamy-cli/pkg/provider/googleconsent" + googleconsentvariable "github.com/foomo/sesamy-cli/pkg/provider/googleconsent/server/variable" + servertagx "github.com/foomo/sesamy-cli/pkg/provider/microsoftads/server/tag" + "github.com/foomo/sesamy-cli/pkg/provider/microsoftads/server/template" + "github.com/foomo/sesamy-cli/pkg/provider/microsoftads/server/trigger" + "github.com/foomo/sesamy-cli/pkg/tagmanager" + commonvariable "github.com/foomo/sesamy-cli/pkg/tagmanager/common/variable" + "github.com/foomo/sesamy-cli/pkg/utils" + "github.com/pkg/errors" +) + +func Server(l *slog.Logger, tm *tagmanager.TagManager, cfg config.MicrosoftAds) error { + { // create folder + if folder, err := tm.UpsertFolder("Sesamy - " + Name); err != nil { + return err + } else { + tm.SetFolderName(folder.Name) + } + } + + tagID, err := tm.UpsertVariable(commonvariable.NewConstant(NameTagIDConstant, cfg.TagID)) + if err != nil { + return err + } + + if cfg.Conversion.Enabled { + tagTemplate, err := tm.UpsertCustomTemplate(template.NewConversionTag(NameConversionsTagTemplate)) + if err != nil { + return err + } + + { // create tags + eventParameters, err := utils.LoadEventParams(cfg.Conversion.ServerContainer.Config) + if err != nil { + return err + } + + for event := range eventParameters { + var eventTriggerOpts []trigger.ConversionEventOption + if cfg.GoogleConsent.Enabled { + if err := googleconsent.ServerEnsure(tm); err != nil { + return err + } + consentVariable, err := tm.LookupVariable(googleconsentvariable.GoogleConsentModeName(cfg.GoogleConsent.Mode)) + if err != nil { + return err + } + eventTriggerOpts = append(eventTriggerOpts, trigger.ConversionEventWithConsentMode(consentVariable)) + } + + eventTrigger, err := tm.UpsertTrigger(trigger.NewConversionEvent(event, eventTriggerOpts...)) + if err != nil { + return errors.Wrap(err, "failed to upsert event trigger: "+event) + } + + if _, err := tm.UpsertTag(servertagx.NewConversion(event, tagID, tagTemplate, cfg.Conversion.ServerContainer.Setting(event), eventTrigger)); err != nil { + return err + } + } + } + } + + return nil +} diff --git a/pkg/provider/microsoftads/server/tag/conversion.go b/pkg/provider/microsoftads/server/tag/conversion.go new file mode 100644 index 0000000..9ee0171 --- /dev/null +++ b/pkg/provider/microsoftads/server/tag/conversion.go @@ -0,0 +1,145 @@ +package tag + +import ( + "github.com/foomo/sesamy-cli/pkg/config" + "github.com/foomo/sesamy-cli/pkg/utils" + "google.golang.org/api/tagmanager/v2" +) + +func ConversionName(v string) string { + return "MAds Conversion - " + v +} + +func NewConversion(name string, tagID *tagmanager.Variable, template *tagmanager.CustomTemplate, settings config.MicrosoftAdsConversionTag, triggers ...*tagmanager.Trigger) *tagmanager.Tag { + return &tagmanager.Tag{ + FiringTriggerId: utils.TriggerIDs(triggers), + Name: ConversionName(name), + TagFiringOption: "oncePerEvent", + Parameter: []*tagmanager.Parameter{ + { + Key: "pagetype", + Type: "template", + Value: settings.PageType, + }, + { + Key: "activateLogs", + Type: "boolean", + Value: "false", + }, + { + Key: "pageTitle", + Type: "template", + }, + { + Key: "prodidGa", + Type: "boolean", + Value: "true", + }, + { + Key: "vid", + Type: "template", + }, + { + Key: "searchTerm", + Type: "template", + }, + { + Key: "msclkidCookie", + Type: "template", + }, + { + Key: "msclkidCookie", + Type: "template", + }, + { + Key: "itemsGa", + Type: "boolean", + Value: "true", + }, + { + Key: "ea", + Type: "template", + Value: name, + }, + { + Key: "ea", + Type: "template", + Value: name, + }, + { + Key: "ecommCategory", + Type: "template", + }, + { + Key: "gc", + Type: "template", + }, + { + Key: "ec", + Type: "template", + }, + { + Key: "evt", + Type: "template", + Value: settings.EventType, + }, + { + Key: "firstClick", + Type: "boolean", + Value: "false", + }, + { + Key: "spa", + Type: "boolean", + Value: "false", + }, + { + Key: "el", + Type: "template", + }, + { + Key: "prodid", + Type: "template", + }, + { + Key: "pagePath", + Type: "template", + }, + { + Key: "gv", + Type: "template", + }, + { + Key: "ev", + Type: "template", + }, + { + Key: "pageLocation", + Type: "template", + }, + { + Key: "msclkidQuery", + Type: "template", + }, + { + Key: "createCookie", + Type: "boolean", + Value: "false", + }, + { + Key: "ti", + Type: "template", + Value: "{{" + tagID.Name + "}}", + }, + { + Key: "user_id", + Type: "template", + }, + { + Key: "pageReferrer", + Type: "template", + }, + }, + Type: utils.TemplateType(template), + } +} diff --git a/pkg/provider/microsoftads/server/template/conversiontag.go b/pkg/provider/microsoftads/server/template/conversiontag.go new file mode 100644 index 0000000..cd85fda --- /dev/null +++ b/pkg/provider/microsoftads/server/template/conversiontag.go @@ -0,0 +1,14 @@ +package template + +import ( + "fmt" + + "google.golang.org/api/tagmanager/v2" +) + +func NewConversionTag(name string) *tagmanager.CustomTemplate { + return &tagmanager.CustomTemplate{ + Name: name, + TemplateData: fmt.Sprintf(ConversionTagData, name), + } +} diff --git a/pkg/provider/microsoftads/server/template/conversiontagdata.go b/pkg/provider/microsoftads/server/template/conversiontagdata.go new file mode 100644 index 0000000..3e288e7 --- /dev/null +++ b/pkg/provider/microsoftads/server/template/conversiontagdata.go @@ -0,0 +1,737 @@ +package template + +const ConversionTagData = `___TERMS_OF_SERVICE___ + +By creating or modifying this file you agree to Google Tag Manager's Community +Template Gallery Developer Terms of Service available at +https://developers.google.com/tag-manager/gallery-tos (or such other URL as +Google may provide), as modified from time to time. + + +___INFO___ + +{ + "type": "TAG", + "id": "cvt_temp_public_id", + "version": 1, + "securityGroups": [], + "displayName": "%s", + "categories": [ + "ADVERTISING", "CONVERSIONS", "ANALYTICS", "REMARKETING" + ], + "brand": { + "id": "brand_dummy", + "displayName": "", + "thumbnail": "data:image/png;base64,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\u003d\u003d" + }, + "description": "Tag for sending conversions of Event type back to Bing/Microsoft Ads.\nInfo: https://github.com/rodfchaves/bing-microsoft-conversion-tag", + "containerContexts": [ + "SERVER" + ] +} + + +___TEMPLATE_PARAMETERS___ + +[ + { + "type": "LABEL", + "name": "label1", + "displayName": "All fields with star (*) are required." + }, + { + "type": "TEXT", + "name": "ti", + "displayName": "UET Tag ID*", + "simpleValueType": true, + "canBeEmptyString": false + }, + { + "type": "SELECT", + "name": "evt", + "displayName": "Event Type*", + "macrosInSelect": false, + "selectItems": [ + { + "value": "pageLoad", + "displayValue": "Page Load" + }, + { + "value": "custom", + "displayValue": "Custom" + } + ], + "simpleValueType": true, + "defaultValue": "pageLoad" + }, + { + "type": "LABEL", + "name": "customEvents", + "displayName": "Custom Event Data", + "enablingConditions": [ + { + "paramName": "evt", + "paramValue": "custom", + "type": "EQUALS" + } + ] + }, + { + "type": "TEXT", + "name": "ea", + "displayName": "Event Action", + "simpleValueType": true, + "canBeEmptyString": true, + "enablingConditions": [ + { + "paramName": "evt", + "paramValue": "custom", + "type": "EQUALS" + } + ], + "help": "Defaults to: event_action" + }, + { + "type": "TEXT", + "name": "ec", + "displayName": "Event Category", + "simpleValueType": true, + "canBeEmptyString": true, + "enablingConditions": [ + { + "paramName": "evt", + "paramValue": "custom", + "type": "EQUALS" + } + ], + "help": "Defaults to: event_category" + }, + { + "type": "TEXT", + "name": "el", + "displayName": "Event Label", + "simpleValueType": true, + "canBeEmptyString": true, + "enablingConditions": [ + { + "paramName": "evt", + "paramValue": "custom", + "type": "EQUALS" + } + ], + "help": "Defaults to: event_label" + }, + { + "type": "TEXT", + "name": "ev", + "displayName": "Event Value", + "simpleValueType": true, + "canBeEmptyString": true, + "enablingConditions": [ + { + "paramName": "evt", + "paramValue": "custom", + "type": "EQUALS" + } + ], + "help": "Defaults to: event_value" + }, + { + "type": "TEXT", + "name": "msclkidCookie", + "displayName": "Microsoft Click ID (from the cookie)", + "simpleValueType": true, + "canBeEmptyString": true, + "help": "msclkid from the cookie. Defaults to: _uetmsclkid cookie." + }, + { + "type": "TEXT", + "name": "msclkidQuery", + "displayName": "Microsoft Click ID (from the URL)", + "simpleValueType": true, + "canBeEmptyString": true, + "help": "msclkid from the URL. Defaults to: msclkid param from the page_location." + }, + { + "type": "TEXT", + "name": "user_id", + "displayName": "User ID", + "simpleValueType": true, + "canBeEmptyString": true, + "help": "ID from a logged user. Defaults to: user_id" + }, + { + "type": "TEXT", + "name": "vid", + "displayName": "Client ID", + "simpleValueType": true, + "canBeEmptyString": true, + "help": "ID from a non-logged user. Defaults to: client_id" + }, + { + "type": "TEXT", + "name": "pageLocation", + "displayName": "Page URL", + "simpleValueType": true, + "canBeEmptyString": true, + "help": "Defaults to: page_location" + }, + { + "type": "TEXT", + "name": "pageReferrer", + "displayName": "Referrer URL", + "simpleValueType": true, + "canBeEmptyString": true, + "help": "Defaults to: page_referrer" + }, + { + "type": "TEXT", + "name": "pageTitle", + "displayName": "Page title", + "simpleValueType": true, + "canBeEmptyString": true, + "help": "Defaults to: page_title" + }, + { + "type": "TEXT", + "name": "pagePath", + "displayName": "Page Path", + "simpleValueType": true, + "canBeEmptyString": true, + "help": "Defaults to: page_path" + }, + { + "type": "TEXT", + "name": "searchTerm", + "displayName": "Search Term", + "simpleValueType": true, + "canBeEmptyString": true, + "help": "The search query the user entered prior to arriving at the search results page.\nDefaults to: search_term" + }, + { + "type": "SELECT", + "name": "pagetype", + "displayName": "Page Type", + "macrosInSelect": true, + "selectItems": [ + { + "value": "category", + "displayValue": "Category" + }, + { + "value": "searchresults", + "displayValue": "Search Results" + }, + { + "value": "product", + "displayValue": "Product" + }, + { + "value": "cart", + "displayValue": "Cart" + }, + { + "value": "purchase", + "displayValue": "Purchase" + }, + { + "value": "home", + "displayValue": "Home" + }, + { + "value": "other", + "displayValue": "Other" + } + ], + "simpleValueType": true, + "defaultValue": "home" + }, + { + "type": "LABEL", + "name": "ecommerce", + "displayName": "Ecommerce Data" + }, + { + "type": "TEXT", + "name": "transactionId", + "displayName": "Transaction ID", + "simpleValueType": true + }, + { + "type": "TEXT", + "name": "ecommCategory", + "displayName": "Ecommerce Category", + "simpleValueType": true, + "canBeEmptyString": true, + "help": "The ID of the category for the category browse page." + }, + { + "type": "TEXT", + "name": "items", + "displayName": "Ecommerce Items", + "simpleValueType": true, + "help": "An array that includes details of products, such as product ID and price. This array should be captured on pages and events involving multiple products, such as an add-to-cart event, visiting the cart page, or visiting the purchase confirmation page.\n\nYou can also mark the checkbox below and send the standard Google Analytics datalayer ecommerce.items\n\nExample: id\u003dprodABCD\u0026quantity\u003d2\u0026price\u003d53.4,id\u003dprodABC\u0026quantity\u003d1\u0026price\u003d121.1\n\nDefaults to: items" + }, + { + "type": "CHECKBOX", + "name": "itemsGa", + "checkboxText": "Use the structure from Google Analytics ecommerce items", + "simpleValueType": true + }, + { + "type": "TEXT", + "name": "prodid", + "displayName": "Product IDs", + "simpleValueType": true, + "canBeEmptyString": true, + "help": "This parameter captures a comma-separated list of product IDs that the user has viewed. It supports multiple product IDs when the page displays more than one product. Each product ID is unique for each item and must match either the ID or item_group_id attribute in the product feed submitted through.\n\nExample: pid1,pid2,pid3,pid4,pid5,pid6,pid7,pid8,pid9,pid10" + }, + { + "type": "CHECKBOX", + "name": "prodidGa", + "checkboxText": "Use the structure from Google Analytics ecommerce items", + "simpleValueType": true + }, + { + "type": "TEXT", + "name": "gc", + "displayName": "Currency", + "simpleValueType": true, + "help": "The currency being used in the transaction.\n\nExample: usd\n\nDefaults to: currency", + "canBeEmptyString": true + }, + { + "type": "TEXT", + "name": "gv", + "displayName": "Value", + "simpleValueType": true, + "help": "For use in conversion tracking to report variable revenue.\n\nDefaults to: value", + "canBeEmptyString": true + }, + { + "type": "CHECKBOX", + "name": "spa", + "checkboxText": "Single-page application", + "simpleValueType": true + }, + { + "type": "CHECKBOX", + "name": "createCookie", + "checkboxText": "Automatically create the _uetmsclkid cookie", + "simpleValueType": true + }, + { + "type": "CHECKBOX", + "name": "firstClick", + "checkboxText": "First Click mode (check this if you want to track the first click ID)", + "simpleValueType": true + }, + { + "type": "CHECKBOX", + "name": "activateLogs", + "checkboxText": "Activate Logs", + "simpleValueType": true + } +] + + +___SANDBOXED_JS_FOR_SERVER___ + +const sendHttpGet = require('sendHttpGet'); +const getEventData = require('getEventData'); +const generateRandom = require('generateRandom'); +const logToConsole = require('logToConsole'); +const Math = require('Math'); +const encodeUriComponent = require('encodeUriComponent'); +const JSON = require('JSON'); +const getCookieValues = require('getCookieValues'); +const setCookie = require('setCookie'); +const parseUrl = require('parseUrl'); + + +let clickid; +function isNotEmpty(obj) { + if(obj == undefined || obj == null || obj.toString() == "" ) { + return false; + } else { + return obj; + } +} + +let msquery = () => { + if(parseUrl(getEventData('page_location'))) { + if (parseUrl(getEventData('page_location')).searchParams.msclkid) { + return parseUrl(getEventData('page_location')).searchParams.msclkid; + } else { + return false; + } + } else { + return false; + } +}; + +function setUETCookie(clickid) { + setCookie('_uetmsclkid', "_uet"+clickid, {"expires":7776000000, httpOnly: true, secure: true, path: '/', sameSite: 'strict'}); + if (data.activateLogs) { + logToConsole("Cookie set: " + clickid); + } +} + +if(data.first_click) { + if (isNotEmpty(data.msclkidCookie) || isNotEmpty(getCookieValues('_uetmsclkid'))) { + let clickid_cookie = getCookieValues('_uetmsclkid')[0]; + clickid = (isNotEmpty(data.msclkidCookie) || (clickid_cookie.substring(4))); + clickid += "-0"; + } else { //cookie not present + if (isNotEmpty(data.msclkidQuery) || msquery()) { + clickid = (isNotEmpty(data.msclkidQuery) || msquery()); + setUETCookie(clickid); + clickid += "-1"; + } else { + clickid = "N"; + } + } +} else { + if (isNotEmpty(data.msclkidQuery) || msquery()) { + clickid = (isNotEmpty(data.msclkidQuery) || msquery()); + setUETCookie(clickid); + clickid += "-1"; + } else { + if(isNotEmpty(data.msclkidCookie) || isNotEmpty(getCookieValues('_uetmsclkid'))){ + let clickid_cookie = getCookieValues('_uetmsclkid')[0]; + clickid = (isNotEmpty(data.msclkidCookie) || (clickid_cookie.substring(4))); + clickid += "-0"; + } else { + clickid = "N"; + } + } +} + + +const screen = data.screen || getEventData('screen_resolution'); + +let width, height = ""; +if (isNotEmpty(screen)){ + width = screen.split('x')[0]; + height = screen.split('x')[1]; + +} +let rn = generateRandom(100000, 999999); +function s4() { + return Math.floor(((1 + (generateRandom(1, 9999999)/10000000))) * 65536) + .toString(16) + .substring(1); +} + +let mid = (s4() + s4() + "-" + s4() + "-" + s4() + "-" + s4() + "-" + s4() + s4() + s4()); +let items_data; +if(isNotEmpty(getEventData('items'))){ + items_data = getEventData('items'); +} + +let items = () => { + let result = ""; + if(isNotEmpty(data.prodid)){ + items_data = data.prodid; + } + if (data.itemsGa) { + if(items_data) { + items_data.forEach(function(item, i) { + result += "id=" + item.item_id + 'quantity=' + item.quantity + 'price=' + item.price; + if (i < items_data.length - 1) { + result += ','; + } + }); + } + } else { + result = items_data; + } + return result; +}; + + +let items_id = () => { + let result = ""; + if(isNotEmpty(data.items)){ + items_data = data.items; + } + if(data.prodidGa) { + if (items_data) { + items_data.forEach(function(item, i) { + result += item.item_id; + if (i < items_data.length - 1) { + result += ','; + } + }); + } + } + return result; +}; + +let spa = () => { + if(data.spa) { + return "Y"; + } else { + return "N"; + } +}; + +let params = {}; + +params.rn = rn; +params.ti = data.ti; +params.ver = '2.3'; +params.mid = mid; +params.uid = isNotEmpty(data.userId) || getEventData('user_id'); +params.evt = data.evt; +params.p = isNotEmpty(data.pageLocation) || getEventData('page_location'); +params.r = isNotEmpty(data.pageReferrer) || getEventData('page_referrer'); +params.tl = isNotEmpty(data.pageTitle) || getEventData('page_title'); +params.pagetype = data.pagetype; +params.items = items(); +params.prodid = items_id(); +params.search_term = isNotEmpty(data.searchTerm) || getEventData('search_term'); +params.transaction_id = isNotEmpty(data.transactionId) || getEventData('transaction_id'); +params.lg = isNotEmpty(data.lg) || getEventData('language'); +params.sw = width; +params.sh = height; +params.sc = data.sc || getEventData('screen_color_depth'); +params.spa = spa(); +params.msclkid = clickid; +params.sid = isNotEmpty(data.sid) || getEventData('uet_session_id'); +params.vid = isNotEmpty(data.vid) || getEventData('vid'); +params.page_path = isNotEmpty(data.pagePath) || getEventData('page_path'); +params.gc = isNotEmpty(data.gc) || getEventData('currency'); +params.gv = isNotEmpty(data.gv) || getEventData('value'); +params.ec = isNotEmpty(data.ec) || getEventData('event_category'); +params.ea = isNotEmpty(data.ea) || getEventData('event_action'); +params.el = isNotEmpty(data.el) || getEventData('event_label'); +params.ev = isNotEmpty(data.ev) || getEventData('event_value'); + +if (data.activateLogs) { + logToConsole("Params: " + JSON.stringify(params)); +} + + +let url = 'https://bat.bing.com/action/0?'; +let all_params = ""; +if(isNotEmpty(params)){ + for (var key in params){ + if (params[key] == undefined || params[key] == null) { + continue; + } + all_params += key + "=" + encodeUriComponent(params[key]) + "&"; + } + url += all_params; +} +if (data.activateLogs) { + logToConsole('URL: ' + url); +} + + +return sendHttpGet(url, { + headers: {key: 'value'}, + timeout: 500, +}).then((result) => { + if (result.statusCode >= 200 && result.statusCode < 300) { + data.gtmOnSuccess(); + } else { + logToConsole('Error: ' + result.statusCode); + data.gtmOnFailure(); + } +}); + + +___SERVER_PERMISSIONS___ + +[ + { + "instance": { + "key": { + "publicId": "send_http", + "versionId": "1" + }, + "param": [ + { + "key": "allowedUrls", + "value": { + "type": 1, + "string": "specific" + } + }, + { + "key": "urls", + "value": { + "type": 2, + "listItem": [ + { + "type": 1, + "string": "https://bat.bing.com/*" + } + ] + } + } + ] + }, + "clientAnnotations": { + "isEditedByUser": true + }, + "isRequired": true + }, + { + "instance": { + "key": { + "publicId": "read_event_data", + "versionId": "1" + }, + "param": [ + { + "key": "eventDataAccess", + "value": { + "type": 1, + "string": "any" + } + } + ] + }, + "clientAnnotations": { + "isEditedByUser": true + }, + "isRequired": true + }, + { + "instance": { + "key": { + "publicId": "logging", + "versionId": "1" + }, + "param": [ + { + "key": "environments", + "value": { + "type": 1, + "string": "all" + } + } + ] + }, + "clientAnnotations": { + "isEditedByUser": true + }, + "isRequired": true + }, + { + "instance": { + "key": { + "publicId": "get_cookies", + "versionId": "1" + }, + "param": [ + { + "key": "cookieAccess", + "value": { + "type": 1, + "string": "specific" + } + }, + { + "key": "cookieNames", + "value": { + "type": 2, + "listItem": [ + { + "type": 1, + "string": "_uetmsclkid" + } + ] + } + } + ] + }, + "clientAnnotations": { + "isEditedByUser": true + }, + "isRequired": true + }, + { + "instance": { + "key": { + "publicId": "set_cookies", + "versionId": "1" + }, + "param": [ + { + "key": "allowedCookies", + "value": { + "type": 2, + "listItem": [ + { + "type": 3, + "mapKey": [ + { + "type": 1, + "string": "name" + }, + { + "type": 1, + "string": "domain" + }, + { + "type": 1, + "string": "path" + }, + { + "type": 1, + "string": "secure" + }, + { + "type": 1, + "string": "session" + } + ], + "mapValue": [ + { + "type": 1, + "string": "_uetmsclkid" + }, + { + "type": 1, + "string": "*" + }, + { + "type": 1, + "string": "*" + }, + { + "type": 1, + "string": "any" + }, + { + "type": 1, + "string": "any" + } + ] + } + ] + } + } + ] + }, + "clientAnnotations": { + "isEditedByUser": true + }, + "isRequired": true + } +] + + +___TESTS___ + +scenarios: [] + + +___NOTES___ + +Created on 4/27/2024, 12:10:56 PM +Code generated by sesamy. DO NOT EDIT. +` diff --git a/pkg/provider/microsoftads/server/trigger/conversionevent.go b/pkg/provider/microsoftads/server/trigger/conversionevent.go new file mode 100644 index 0000000..5da3298 --- /dev/null +++ b/pkg/provider/microsoftads/server/trigger/conversionevent.go @@ -0,0 +1,75 @@ +package trigger + +import ( + "google.golang.org/api/tagmanager/v2" +) + +func ConversionEventName(v string) string { + return "MAds Conversion - " + v +} + +type ( + ConversionEventOptions struct { + consentMode *tagmanager.Variable + } + ConversionEventOption func(*ConversionEventOptions) +) + +func ConversionEventWithConsentMode(mode *tagmanager.Variable) ConversionEventOption { + return func(o *ConversionEventOptions) { + o.consentMode = mode + } +} + +func NewConversionEvent(name string, opts ...ConversionEventOption) *tagmanager.Trigger { + o := &ConversionEventOptions{} + for _, opt := range opts { + if opt != nil { + opt(o) + } + } + + var filter []*tagmanager.Condition + if o.consentMode != nil { + filter = append(filter, + &tagmanager.Condition{ + Parameter: []*tagmanager.Parameter{ + { + Key: "arg0", + Type: "template", + Value: "{{" + o.consentMode.Name + "}}", + }, + { + Key: "arg1", + Type: "template", + Value: "granted", + }, + }, + Type: "equals", + }, + ) + } + + return &tagmanager.Trigger{ + Type: "customEvent", + Name: ConversionEventName(name), + CustomEventFilter: []*tagmanager.Condition{ + { + Parameter: []*tagmanager.Parameter{ + { + Key: "arg0", + Type: "template", + Value: "{{_event}}", + }, + { + Key: "arg1", + Type: "template", + Value: name, + }, + }, + Type: "equals", + }, + }, + Filter: filter, + } +} diff --git a/sesamy.schema.json b/sesamy.schema.json index 3f0660a..421f568 100644 --- a/sesamy.schema.json +++ b/sesamy.schema.json @@ -78,6 +78,10 @@ "$ref": "#/$defs/github.com.foomo.sesamy-cli.pkg.config.Facebook", "description": "Facebook provider settings" }, + "microsoftAds": { + "$ref": "#/$defs/github.com.foomo.sesamy-cli.pkg.config.MicrosoftAds", + "description": "MicrosoftAds provider settings" + }, "emarsys": { "$ref": "#/$defs/github.com.foomo.sesamy-cli.pkg.config.Emarsys", "description": "Emarsys provider settings" @@ -419,6 +423,66 @@ "additionalProperties": false, "type": "object" }, + "github.com.foomo.sesamy-cli.pkg.config.MicrosoftAds": { + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable provider" + }, + "googleConsent": { + "$ref": "#/$defs/github.com.foomo.sesamy-cli.pkg.config.GoogleConsent", + "description": "Google Consent settings" + }, + "tagId": { + "type": "string", + "description": "Microsoft Ads UET Tag ID" + }, + "conversion": { + "$ref": "#/$defs/github.com.foomo.sesamy-cli.pkg.config.MicrosoftAdsConversion", + "description": "Microsoft Ads Conversion settings" + } + }, + "additionalProperties": false, + "type": "object" + }, + "github.com.foomo.sesamy-cli.pkg.config.MicrosoftAdsConversion": { + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable provider" + }, + "serverContainer": { + "$ref": "#/$defs/github.com.foomo.sesamy-cli.pkg.config.MicrosoftAdsServerContainer", + "description": "Google Tag Manager server container settings" + } + }, + "additionalProperties": false, + "type": "object" + }, + "github.com.foomo.sesamy-cli.pkg.config.MicrosoftAdsConversionTag": { + "properties": { + "pageType": { + "type": "string" + }, + "eventType": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object" + }, + "github.com.foomo.sesamy-cli.pkg.config.MicrosoftAdsServerContainer": { + "properties": { + "packages": { + "$ref": "#/$defs/[]*contemplate.PackageConfig" + }, + "settings": { + "$ref": "#/$defs/map[string]config.MicrosoftAdsConversionTag" + } + }, + "additionalProperties": false, + "type": "object" + }, "github.com.foomo.sesamy-cli.pkg.config.ServerContainer": { "properties": { "packages": { @@ -501,6 +565,12 @@ "$ref": "#/$defs/github.com.foomo.sesamy-cli.pkg.config.GoogleAdsConversionTracking" }, "type": "object" + }, + "map[string]config.MicrosoftAdsConversionTag": { + "additionalProperties": { + "$ref": "#/$defs/github.com.foomo.sesamy-cli.pkg.config.MicrosoftAdsConversionTag" + }, + "type": "object" } } } \ No newline at end of file diff --git a/sesamy.yaml b/sesamy.yaml index 9e9fb47..ac40a92 100644 --- a/sesamy.yaml +++ b/sesamy.yaml @@ -164,10 +164,14 @@ googleAds: conversion: # Enable Google Ads Conversion enabled: true - # Google Ads Conversion Tracking Label - conversionLabel: '' # Google Tag Manager server container settings serverContainer: + # Conversion labels map + settings: + add_to_cart: + label: '' + purchase: + label: '' # Contemplate package config for generated events packages: - path: github.com/foomo/sesamy-go/pkg/event @@ -291,6 +295,38 @@ tracify: - ViewItem - Purchase + +# --- Microsoft Ads +microsoftAds: + # Enable provider + enabled: true + # Microsoft UET Tag ID + tagId: '123456789' + # Microsoft Ads Conversion + conversion: + # Enable conversion + enabled: true + # Google Tag Manager server container settings + serverContainer: + # Conversion labels map + settings: + add_to_cart: + pageType: other + eventType: custom + page_view: + pageType: other + eventType: pageLoad + purchase: + pageType: purchase + eventType: custom + # Contemplate package config for generated events + packages: + - path: github.com/foomo/sesamy-go/pkg/event + types: + - AddToCart + - PageView + - Purchase + # --- Hotjar hotjar: # Enable provider