diff --git a/README.md b/README.md index e7d694a..91ca08d 100644 --- a/README.md +++ b/README.md @@ -186,16 +186,24 @@ googleAnalytics: googleAds: # Enable provider enabled: true + # Google Ads Conversion Tracking ID + conversionId: '' # Google Consent settings googleConsent: # Enable consent mode enabled: true # Consent mode name mode: ad_storage + # Google Ads Remarketing settings + remarketing: + # Enable Google Ads Remarketing + enabled: true + # Enable conversion linking + enableConversionLinker: true # Google Ads Conversion settings conversion: - # Google Ads Conversion Tracking ID - conversionId: '' + # Enable Google Ads Conversion + enabled: true # Google Ads Conversion Tracking Label conversionLabel: '' # Google Tag Manager server container settings @@ -312,7 +320,7 @@ cookiebot: # Enable URL passthrough urlPassthrough: false # Enable advertiser consent mode - AdvertiserConsentModeEnabled: false + advertiserConsentModeEnabled: false ``` ## Caveats diff --git a/pkg/config/googleads.go b/pkg/config/googleads.go index 486a8be..8d4966b 100644 --- a/pkg/config/googleads.go +++ b/pkg/config/googleads.go @@ -1,7 +1,9 @@ package config type GoogleAds struct { - Enabled bool `json:"enabled" yaml:"enabled"` - GoogleConsent GoogleConsent `json:"googleConsent" yaml:"googleConsent"` - Conversion GoogleAdsConversion `json:"conversion" yaml:"conversion"` + Enabled bool `json:"enabled" yaml:"enabled"` + GoogleConsent GoogleConsent `json:"googleConsent" yaml:"googleConsent"` + ConversionID string `json:"conversionId" yaml:"conversionId"` + Conversion GoogleAdsConversion `json:"conversion" yaml:"conversion"` + Remarketing GoogleAdsRemarketing `json:"remarketing" yaml:"remarketing"` } diff --git a/pkg/config/googleadsconversion.go b/pkg/config/googleadsconversion.go index 2adb9da..72e537e 100644 --- a/pkg/config/googleadsconversion.go +++ b/pkg/config/googleadsconversion.go @@ -6,7 +6,6 @@ import ( type GoogleAdsConversion struct { Enabled bool `json:"enabled" yaml:"enabled"` - ConversionID string `json:"conversionId" yaml:"conversionId"` ConversionLabel string `json:"conversionLabel" yaml:"conversionLabel"` ServerContainer contemplate.Config `json:"serverContainer" yaml:"serverContainer"` } diff --git a/pkg/config/googleadsremarketing.go b/pkg/config/googleadsremarketing.go new file mode 100644 index 0000000..401cb46 --- /dev/null +++ b/pkg/config/googleadsremarketing.go @@ -0,0 +1,6 @@ +package config + +type GoogleAdsRemarketing struct { + Enabled bool `json:"enabled" yaml:"enabled"` + EnableConversionLinker bool `json:"enableConversionLinker" yaml:"enableConversionLinker"` +} diff --git a/pkg/provider/googleads/constants.go b/pkg/provider/googleads/constants.go index dc35d66..d28b4ca 100644 --- a/pkg/provider/googleads/constants.go +++ b/pkg/provider/googleads/constants.go @@ -1,8 +1,9 @@ package googleads const ( - Tag = "gads" - Name = "Google Ads" - NameConversionIDConstant = "GAds Conversion ID" - NameConversionLabelConstant = "GAds Conversion Label" + Tag = "gads" + Name = "Google Ads" + NameConversionIDConstant = "GAds Conversion ID" + NameConversionLabelConstant = "GAds Conversion Label" + NameGoogleAdsRemarketingTrigger = "Google Ads Remarketing" ) diff --git a/pkg/provider/googleads/server.go b/pkg/provider/googleads/server.go index 0df078d..adf33e8 100644 --- a/pkg/provider/googleads/server.go +++ b/pkg/provider/googleads/server.go @@ -24,12 +24,13 @@ func Server(l *slog.Logger, tm *tagmanager.TagManager, cfg config.GoogleAds) err } } - { // conversion - conversionID, err := tm.UpsertVariable(commonvariable.NewConstant(NameConversionIDConstant, cfg.Conversion.ConversionID)) - if err != nil { - return err - } + conversionID, err := tm.UpsertVariable(commonvariable.NewConstant(NameConversionIDConstant, cfg.ConversionID)) + if err != nil { + return err + } + // conversion + if cfg.Conversion.Enabled { conversionLabel, err := tm.UpsertVariable(commonvariable.NewConstant(NameConversionLabelConstant, cfg.Conversion.ConversionLabel)) if err != nil { return err @@ -74,6 +75,30 @@ func Server(l *slog.Logger, tm *tagmanager.TagManager, cfg config.GoogleAds) err } } } + + // remarketing + if cfg.Remarketing.Enabled { + var eventTriggerOpts []trigger.GoogleAdsRemarketingEventOption + 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.GoogleAdsRemarketingEventWithConsentMode(consentVariable)) + } + + eventTrigger, err := tm.UpsertTrigger(trigger.NewGoogleAdsRemarketingEvent(NameGoogleAdsRemarketingTrigger, eventTriggerOpts...)) + if err != nil { + return errors.Wrap(err, "failed to upsert event trigger: "+NameGoogleAdsRemarketingTrigger) + } + + if _, err := tm.UpsertTag(servertagx.NewGoogleAdsRemarketing(Name, conversionID, cfg.Remarketing, eventTrigger)); err != nil { + return err + } + } } return nil diff --git a/pkg/provider/googleads/server/tag/googleadsremarketing.go b/pkg/provider/googleads/server/tag/googleadsremarketing.go new file mode 100644 index 0000000..20347b3 --- /dev/null +++ b/pkg/provider/googleads/server/tag/googleadsremarketing.go @@ -0,0 +1,50 @@ +package tag + +import ( + "strconv" + + "github.com/foomo/sesamy-cli/pkg/config" + "github.com/foomo/sesamy-cli/pkg/utils" + "google.golang.org/api/tagmanager/v2" +) + +func NewGoogleAdsRemarketing(name string, conversionID *tagmanager.Variable, cfg config.GoogleAdsRemarketing, triggers ...*tagmanager.Trigger) *tagmanager.Tag { + return &tagmanager.Tag{ + FiringTriggerId: utils.TriggerIDs(triggers), + Name: name, + TagFiringOption: "oncePerEvent", + Parameter: []*tagmanager.Parameter{ + { + Key: "enableConversionLinker", + Type: "boolean", + Value: strconv.FormatBool(cfg.EnableConversionLinker), + }, + { + Key: "enableDynamicRemarketing", + Type: "boolean", + Value: "false", + }, + { + Key: "enableCustomParams", + Type: "boolean", + Value: "false", + }, + { + Key: "enableUserId", + Type: "boolean", + Value: "false", + }, + { + Key: "conversionId", + Type: "template", + Value: "{{" + conversionID.Name + "}}", + }, + { + Key: "rdp", + Type: "boolean", + Value: "false", + }, + }, + Type: "sgtmadsremarket", + } +} diff --git a/pkg/provider/googleads/server/trigger/emarsysevent.go b/pkg/provider/googleads/server/trigger/googleadsevent.go similarity index 100% rename from pkg/provider/googleads/server/trigger/emarsysevent.go rename to pkg/provider/googleads/server/trigger/googleadsevent.go diff --git a/pkg/provider/googleads/server/trigger/googleadsremarketingevent.go b/pkg/provider/googleads/server/trigger/googleadsremarketingevent.go new file mode 100644 index 0000000..04cd084 --- /dev/null +++ b/pkg/provider/googleads/server/trigger/googleadsremarketingevent.go @@ -0,0 +1,54 @@ +package trigger + +import ( + "google.golang.org/api/tagmanager/v2" +) + +type ( + GoogleAdsRemarketingEventOptions struct { + consentMode *tagmanager.Variable + } + GoogleAdsRemarketingEventOption func(*GoogleAdsRemarketingEventOptions) +) + +func GoogleAdsRemarketingEventWithConsentMode(mode *tagmanager.Variable) GoogleAdsRemarketingEventOption { + return func(o *GoogleAdsRemarketingEventOptions) { + o.consentMode = mode + } +} + +func NewGoogleAdsRemarketingEvent(name string, opts ...GoogleAdsRemarketingEventOption) *tagmanager.Trigger { + o := &GoogleAdsRemarketingEventOptions{} + 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: "serverPageview", + Name: name, + Filter: filter, + } +} diff --git a/sesamy.schema.json b/sesamy.schema.json index c9f77a5..9c7138f 100644 --- a/sesamy.schema.json +++ b/sesamy.schema.json @@ -24,7 +24,7 @@ "cookiebot": { "type": "object", "properties": { - "AdvertiserConsentModeEnabled": { + "advertiserConsentModeEnabled": { "type": "boolean" }, "cdnRegion": { @@ -144,12 +144,12 @@ "conversion": { "type": "object", "properties": { - "conversionId": { - "type": "string" - }, "conversionLabel": { "type": "string" }, + "enabled": { + "type": "boolean" + }, "serverContainer": { "type": "object", "properties": { @@ -174,6 +174,9 @@ } } }, + "conversionId": { + "type": "string" + }, "enabled": { "type": "boolean" }, @@ -187,6 +190,17 @@ "type": "string" } } + }, + "remarketing": { + "type": "object", + "properties": { + "enableConversionLinker": { + "type": "boolean" + }, + "enabled": { + "type": "boolean" + } + } } } }, diff --git a/sesamy.yaml b/sesamy.yaml index 4842990..210ce0c 100644 --- a/sesamy.yaml +++ b/sesamy.yaml @@ -162,16 +162,24 @@ googleAnalytics: googleAds: # Enable provider enabled: true + # Google Ads Conversion Tracking ID + conversionId: '' # Google Consent settings googleConsent: # Enable consent mode enabled: true # Consent mode name mode: ad_storage + # Google Ads Remarketing settings + remarketing: + # Enable Google Ads Remarketing + enabled: true + # Enable conversion linking + enableConversionLinker: true # Google Ads Conversion settings conversion: - # Google Ads Conversion Tracking ID - conversionId: '' + # Enable Google Ads Conversion + enabled: true # Google Ads Conversion Tracking Label conversionLabel: '' # Google Tag Manager server container settings @@ -288,4 +296,4 @@ cookiebot: # Enable URL passthrough urlPassthrough: false # Enable advertiser consent mode - AdvertiserConsentModeEnabled: false + advertiserConsentModeEnabled: false