fix(provider/cookiebot): add cookiebot and integrate consent mode v2

This commit is contained in:
Kevin Franklin Kim 2024-08-27 16:17:10 +02:00
parent b014843991
commit 7aadfb2721
No known key found for this signature in database
39 changed files with 895 additions and 116 deletions

View File

@ -159,6 +159,12 @@ googleAnalytics:
priority: 10
# Patch ecommerce items
ecommerceItems: true
# Google Consent settings
googleConsent:
# Enable consent mode
enabled: true
# Consent mode name
mode: analytics_storage
# Google Tag Manager web container settings
webContainer:
# Contemplate package config for generated events
@ -180,6 +186,12 @@ googleAnalytics:
googleAds:
# Enable provider
enabled: true
# Google Consent settings
googleConsent:
# Enable consent mode
enabled: true
# Consent mode name
mode: ad_storage
# Google Ads Conversion settings
conversion:
# Google Ads Conversion Tracking ID
@ -210,6 +222,12 @@ umami:
websiteId: ''
# Endpoint url of the umami api
endpointUrl: https://umami.your-domain.com
# Google Consent settings
googleConsent:
# Enable consent mode
enabled: true
# Consent mode name
mode: analytics_storage
# Google Tag Manager server container settings
serverContainer:
# Contemplate package config for generated events
@ -230,6 +248,12 @@ facebook:
apiAccessToken: ''
# Code used to verify that your server events are received correctly by Conversions API
testEventToken: ''
# Google Consent settings
googleConsent:
# Enable consent mode
enabled: true
# Consent mode name
mode: ad_storage
# Google Tag Manager server container settings
serverContainer:
# Contemplate package config for generated events
@ -252,8 +276,12 @@ emarsys:
enabled: true
# Emarsys merchant id
merchantId: ''
# Name of the event to mark as new page view
newPageViewEvent: '''
# Google Consent settings
googleConsent:
# Enable consent mode
enabled: true
# Consent mode name
mode: analytics_storage
# Google Tag Manager server container settings
serverContainer:
# Contemplate package config for generated events
@ -263,6 +291,22 @@ emarsys:
- Purchase
- ViewItem
- ViewItemList
# --- Cookiebot CMP
cookiebot:
# Enable provider
enabled: true
# Name of the manually installed Cookiebot CMP tag template
# "https://tagmanager.google.com/gallery/#/owners/cybotcorp/templates/gtm-templates-cookiebot-cmp
templateName: "Cookiebot CMP"
# Cookiebot id
cookiebotId: ''
# CDN Region (eu, com)
cdnRegion: eu
# Enable URL passthrough
urlPassthrough: false
# Enable advertiser consent mode
AdvertiserConsentModeEnabled: false
```
## Caveats

View File

@ -7,7 +7,6 @@ import (
facebookprovider "github.com/foomo/sesamy-cli/pkg/provider/facebook"
googleadsprovider "github.com/foomo/sesamy-cli/pkg/provider/googleads"
googleanalyticsprovider "github.com/foomo/sesamy-cli/pkg/provider/googleanalytics"
googletagprovider "github.com/foomo/sesamy-cli/pkg/provider/googletag"
googletagmanagerprovider "github.com/foomo/sesamy-cli/pkg/provider/googletagmanager"
umamiprovider "github.com/foomo/sesamy-cli/pkg/provider/umami"
"github.com/foomo/sesamy-cli/pkg/tagmanager"
@ -46,12 +45,6 @@ func NewServer(root *cobra.Command) {
return err
}
if pkgcmd.Tag(googletagprovider.Tag, tags) {
if err := googletagprovider.Server(tm); err != nil {
return errors.Wrap(err, "failed to provision google tag")
}
}
if pkgcmd.Tag(googletagmanagerprovider.Tag, tags) {
if err := googletagmanagerprovider.Server(tm, cfg.GoogleTagManager); err != nil {
return errors.Wrap(err, "failed to provision google tag manager")

View File

@ -2,6 +2,7 @@ package tagmanager
import (
pkgcmd "github.com/foomo/sesamy-cli/pkg/cmd"
cookiebotprovider "github.com/foomo/sesamy-cli/pkg/provider/cookiebot"
emarsysprovider "github.com/foomo/sesamy-cli/pkg/provider/emarsys"
googleanaylticsprovider "github.com/foomo/sesamy-cli/pkg/provider/googleanalytics"
googletagprovider "github.com/foomo/sesamy-cli/pkg/provider/googletag"
@ -43,19 +44,25 @@ func NewWeb(root *cobra.Command) {
if pkgcmd.Tag(googletagprovider.Tag, tags) {
if err := googletagprovider.Web(tm, cfg.GoogleTag); err != nil {
return errors.Wrap(err, "failed to provision google tag")
return errors.Wrap(err, "failed to provision google provider")
}
}
if cfg.GoogleAnalytics.Enabled && pkgcmd.Tag(googleanaylticsprovider.Tag, tags) {
if err := googleanaylticsprovider.Web(tm, cfg.GoogleAnalytics); err != nil {
return errors.Wrap(err, "failed to provision google analytics tag")
return errors.Wrap(err, "failed to provision google analytics provider")
}
}
if cfg.Emarsys.Enabled && pkgcmd.Tag(emarsysprovider.Tag, tags) {
if err := emarsysprovider.Web(tm, cfg.Emarsys); err != nil {
return errors.Wrap(err, "failed to provision emarsys tag")
return errors.Wrap(err, "failed to provision emarsys provider")
}
}
if cfg.Cookiebot.Enabled && pkgcmd.Tag(cookiebotprovider.Tag, tags) {
if err := cookiebotprovider.Web(tm, cfg.Cookiebot); err != nil {
return errors.Wrap(err, "failed to provision cookiebot provider")
}
}

View File

@ -8,6 +8,7 @@ type Config struct {
GoogleTagManager GoogleTagManager `json:"googleTagManager" yaml:"googleTagManager"`
// Providers
GoogleAds GoogleAds `json:"googleAds" yaml:"googleAds"`
Cookiebot Cookiebot `json:"cookiebot" yaml:"cookiebot"`
GoogleAnalytics GoogleAnalytics `json:"googleAnalytics" yaml:"googleAnalytics"`
ConversionLinker ConversionLinker `json:"conversionLinker" yaml:"conversionLinker"`
Facebook Facebook `json:"facebook" yaml:"facebook"`

10
pkg/config/cookiebot.go Normal file
View File

@ -0,0 +1,10 @@
package config
type Cookiebot struct {
Enabled bool `json:"enabled" yaml:"enabled"`
TemplateName string `json:"templateName" yaml:"templateName"`
CookiebotID string `json:"cookiebotId" yaml:"cookiebotId"`
CDNRegion string `json:"cdnRegion" yaml:"cdnRegion"`
URLPassthrough bool `json:"urlPassthrough" yaml:"urlPassthrough"`
AdvertiserConsentModeEnabled bool `json:"advertiserConsentModeEnabled" yaml:"advertiserConsentModeEnabled"`
}

View File

@ -5,9 +5,9 @@ import (
)
type Emarsys struct {
Enabled bool `json:"enabled" yaml:"enabled"`
MerchantID string `json:"merchantId" yaml:"merchantId"`
NewPageViewEvent string `json:"newPageViewEvent" yaml:"newPageViewEvent"`
WebContainer contemplate.Config `json:"webContainer" yaml:"webContainer"`
ServerContainer contemplate.Config `json:"serverContainer" yaml:"serverContainer"`
Enabled bool `json:"enabled" yaml:"enabled"`
MerchantID string `json:"merchantId" yaml:"merchantId"`
GoogleConsent GoogleConsent `json:"googleConsent" yaml:"googleConsent"`
WebContainer contemplate.Config `json:"webContainer" yaml:"webContainer"`
ServerContainer contemplate.Config `json:"serverContainer" yaml:"serverContainer"`
}

View File

@ -9,5 +9,6 @@ type Facebook struct {
PixelID string `json:"pixelId" yaml:"pixelId"`
APIAccessToken string `json:"apiAccessToken" yaml:"apiAccessToken"`
TestEventToken string `json:"testEventToken" yaml:"testEventToken"`
GoogleConsent GoogleConsent `json:"googleConsent" yaml:"googleConsent"`
ServerContainer contemplate.Config `json:"serverContainer" yaml:"serverContainer"`
}

View File

@ -1,6 +1,7 @@
package config
type GoogleAds struct {
Enabled bool `json:"enabled" yaml:"enabled"`
Conversion GoogleAdsConversion `json:"conversion" yaml:"conversion"`
Enabled bool `json:"enabled" yaml:"enabled"`
GoogleConsent GoogleConsent `json:"googleConsent" yaml:"googleConsent"`
Conversion GoogleAdsConversion `json:"conversion" yaml:"conversion"`
}

View File

@ -7,6 +7,7 @@ import (
type GoogleAnalytics struct {
Enabled bool `json:"enabled" yaml:"enabled"`
GoogleGTag GoogleGTag `json:"googleGTag" yaml:"googleGTag"`
GoogleConsent GoogleConsent `json:"googleConsent" yaml:"googleConsent"`
WebContainer contemplate.Config `json:"webContainer" yaml:"webContainer"`
ServerContainer contemplate.Config `json:"serverContainer" yaml:"serverContainer"`
}

View File

@ -0,0 +1,6 @@
package config
type GoogleConsent struct {
Enabled bool `json:"enabled" yaml:"enabled"`
Mode string `json:"mode" yaml:"mode"`
}

View File

@ -9,5 +9,6 @@ type Umami struct {
Domain string `json:"domain" yaml:"domain"`
WebsiteID string `json:"websiteId" yaml:"websiteId"`
EndpointURL string `json:"endpointUrl" yaml:"endpointUrl"`
GoogleConsent GoogleConsent `json:"googleConsent" yaml:"googleConsent"`
ServerContainer contemplate.Config `json:"serverContainer" yaml:"serverContainer"`
}

View File

@ -0,0 +1,7 @@
package cookiebot
const (
Tag = "cookiebot"
Name = "Cookiebot"
NameCookiebotTag = "Cookiebot Initialization"
)

View File

@ -0,0 +1,31 @@
package cookiebot
import (
"github.com/foomo/sesamy-cli/pkg/config"
"github.com/foomo/sesamy-cli/pkg/provider/cookiebot/web/tag"
"github.com/foomo/sesamy-cli/pkg/tagmanager"
"github.com/pkg/errors"
)
func Web(tm *tagmanager.TagManager, cfg config.Cookiebot) error {
{ // create folder
if folder, err := tm.UpsertFolder("Sesamy - " + Name); err != nil {
return err
} else {
tm.SetFolderName(folder.Name)
}
}
{ // create event tags
temmplate, err := tm.LookupTemplate(cfg.TemplateName)
if err != nil {
return errors.Wrapf(err, "Failed to lookup `%s`, please install the `%s` gallery tag template first (%s)", cfg.TemplateName, "Cookiebot CMP", "https://tagmanager.google.com/gallery/#/owners/cybotcorp/templates/gtm-templates-cookiebot-cmp")
}
if _, err := tm.UpsertTag(tag.NewCookiebotInitialization(NameCookiebotTag, cfg, temmplate)); err != nil {
return err
}
}
return nil
}

View File

@ -0,0 +1,71 @@
package tag
import (
"strconv"
"github.com/foomo/sesamy-cli/pkg/config"
"github.com/foomo/sesamy-cli/pkg/tagmanager/web/trigger"
"github.com/foomo/sesamy-cli/pkg/utils"
"google.golang.org/api/tagmanager/v2"
)
func NewCookiebotInitialization(name string, cfg config.Cookiebot, template *tagmanager.CustomTemplate) *tagmanager.Tag {
return &tagmanager.Tag{
Name: name,
FiringTriggerId: []string{trigger.IDConsentInitializtion},
TagFiringOption: "oncePerEvent",
Parameter: []*tagmanager.Parameter{
{
Key: "adsDataRedaction",
Type: "template",
Value: "dynamic",
},
{
Key: "addGeoRegion",
Type: "boolean",
Value: "false",
},
{
Key: "serial",
Type: "template",
Value: cfg.CookiebotID,
},
{
Key: "iabFramework",
Type: "boolean",
Value: "false",
},
{
Key: "cdnRegion",
Type: "template",
Value: cfg.CDNRegion,
},
{
Key: "advertiserConsentModeEnabled",
Type: "boolean",
Value: "true",
},
{
Key: "language",
Type: "template",
Value: "auto",
},
{
Key: "urlPassthrough",
Type: "boolean",
Value: strconv.FormatBool(cfg.URLPassthrough),
},
{
Key: "consentModeEnabled",
Type: "boolean",
Value: "true",
},
{
Key: "waitForUpdate",
Type: "template",
Value: "2000",
},
},
Type: utils.TemplateType(template),
}
}

View File

@ -7,10 +7,12 @@ import (
serverclientx "github.com/foomo/sesamy-cli/pkg/provider/emarsys/server/client"
servertagx "github.com/foomo/sesamy-cli/pkg/provider/emarsys/server/tag"
"github.com/foomo/sesamy-cli/pkg/provider/emarsys/server/template"
"github.com/foomo/sesamy-cli/pkg/provider/googletag"
"github.com/foomo/sesamy-cli/pkg/provider/emarsys/server/trigger"
"github.com/foomo/sesamy-cli/pkg/provider/googleconsent"
googleconsentvariable "github.com/foomo/sesamy-cli/pkg/provider/googleconsent/server/variable"
"github.com/foomo/sesamy-cli/pkg/tagmanager"
commontrigger "github.com/foomo/sesamy-cli/pkg/tagmanager/common/trigger"
commonvariable "github.com/foomo/sesamy-cli/pkg/tagmanager/common/variable"
"github.com/foomo/sesamy-cli/pkg/utils"
"github.com/pkg/errors"
)
@ -45,18 +47,30 @@ func Server(l *slog.Logger, tm *tagmanager.TagManager, cfg config.Emarsys) error
}
{ // create tags
eventParameters, err := googletag.CreateServerEventTriggers(tm, cfg.ServerContainer)
eventParameters, err := utils.LoadEventParams(cfg.ServerContainer)
if err != nil {
return err
}
for event := range eventParameters {
eventTrigger, err := tm.LookupTrigger(commontrigger.EventName(event))
if err != nil {
return errors.Wrap(err, "failed to lookup event trigger: "+event)
var eventTriggerOpts []trigger.EmarsysEventOption
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.EmarsysEventWithConsentMode(consentVariable))
}
if _, err := tm.UpsertTag(servertagx.NewEmarsys(event, cfg.NewPageViewEvent == eventTrigger.Name, merchantID, tagTemplate, eventTrigger)); err != nil {
eventTrigger, err := tm.UpsertTrigger(trigger.NewEmarsysEvent(event, eventTriggerOpts...))
if err != nil {
return errors.Wrap(err, "failed to upsert event trigger: "+event)
}
if _, err := tm.UpsertTag(servertagx.NewEmarsys(event, merchantID, tagTemplate, eventTrigger)); err != nil {
return err
}
}

View File

@ -1,8 +1,6 @@
package tag
import (
"strconv"
"github.com/foomo/sesamy-cli/pkg/utils"
"google.golang.org/api/tagmanager/v2"
)
@ -11,7 +9,7 @@ func EmarsysName(v string) string {
return "Emarsys - " + v
}
func NewEmarsys(name string, isNewPageView bool, merchantID *tagmanager.Variable, template *tagmanager.CustomTemplate, triggers ...*tagmanager.Trigger) *tagmanager.Tag {
func NewEmarsys(name string, merchantID *tagmanager.Variable, template *tagmanager.CustomTemplate, triggers ...*tagmanager.Trigger) *tagmanager.Tag {
return &tagmanager.Tag{
FiringTriggerId: utils.TriggerIDs(triggers),
Name: EmarsysName(name),
@ -22,11 +20,6 @@ func NewEmarsys(name string, isNewPageView bool, merchantID *tagmanager.Variable
Type: "template",
Value: "optional",
},
{
Key: "isNewPageView",
Type: "boolean",
Value: strconv.FormatBool(isNewPageView),
},
{
Key: "merchantId",
Type: "template",

View File

@ -29,12 +29,6 @@ ___TEMPLATE_PARAMETERS___
"displayName": "Merchant ID",
"simpleValueType": true
},
{
"type": "CHECKBOX",
"name": "isNewPageView",
"checkboxText": "New Page View",
"simpleValueType": true
},
{
"type": "GROUP",
"name": "consentSettingsGroup",
@ -130,7 +124,7 @@ function mapEventData() {
customerId: eventData.user_id || null,
sessionId: getCookieValues('emarsys_s')[0] || eventData.ga_session_id,
pageViewId: eventData.page_view_id || generatePageViewId(),
isNewPageView: data.isNewPageView || !eventData.page_view_id,
isNewPageView: !eventData.page_view_id,
visitorId: getCookieValues('emarsys_cdv')[0] || eventData.client_id,
referrer: eventData.page_referrer || null,
orderId: null,

View File

@ -0,0 +1,75 @@
package trigger
import (
"google.golang.org/api/tagmanager/v2"
)
func EmarsysEventName(v string) string {
return "Emarsys - " + v
}
type (
EmarsysEventOptions struct {
consentMode *tagmanager.Variable
}
EmarsysEventOption func(*EmarsysEventOptions)
)
func EmarsysEventWithConsentMode(mode *tagmanager.Variable) EmarsysEventOption {
return func(o *EmarsysEventOptions) {
o.consentMode = mode
}
}
func NewEmarsysEvent(name string, opts ...EmarsysEventOption) *tagmanager.Trigger {
o := &EmarsysEventOptions{}
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: EmarsysEventName(name),
CustomEventFilter: []*tagmanager.Condition{
{
Parameter: []*tagmanager.Parameter{
{
Key: "arg0",
Type: "template",
Value: "{{_event}}",
},
{
Key: "arg1",
Type: "template",
Value: name,
},
},
Type: "equals",
},
},
Filter: filter,
}
}

View File

@ -54,7 +54,7 @@ func Web(tm *tagmanager.TagManager, cfg config.Emarsys) error {
return errors.Wrap(err, "failed to lookup google tag event setting: "+event)
}
if _, err := tm.UpsertTag(containertag.NewGoogleAnalyticsGA4Event(event, tagID, eventSettings, eventTrigger)); err != nil {
if _, err := tm.UpsertTag(containertag.NewGoogleAnalyticsEvent(event, tagID, eventSettings, eventTrigger)); err != nil {
return err
}
}

View File

@ -5,10 +5,12 @@ import (
"github.com/foomo/sesamy-cli/pkg/config"
servertagx "github.com/foomo/sesamy-cli/pkg/provider/facebook/server/tag"
"github.com/foomo/sesamy-cli/pkg/provider/googletag"
"github.com/foomo/sesamy-cli/pkg/provider/facebook/server/trigger"
"github.com/foomo/sesamy-cli/pkg/provider/googleconsent"
googleconsentvariable "github.com/foomo/sesamy-cli/pkg/provider/googleconsent/server/variable"
"github.com/foomo/sesamy-cli/pkg/tagmanager"
commontrigger "github.com/foomo/sesamy-cli/pkg/tagmanager/common/trigger"
commonvariable "github.com/foomo/sesamy-cli/pkg/tagmanager/common/variable"
"github.com/foomo/sesamy-cli/pkg/utils"
"github.com/pkg/errors"
)
@ -45,15 +47,27 @@ func Server(l *slog.Logger, tm *tagmanager.TagManager, cfg config.Facebook) erro
}
{ // create tags
eventParameters, err := googletag.CreateServerEventTriggers(tm, cfg.ServerContainer)
eventParameters, err := utils.LoadEventParams(cfg.ServerContainer)
if err != nil {
return err
}
for event := range eventParameters {
eventTrigger, err := tm.LookupTrigger(commontrigger.EventName(event))
var eventTriggerOpts []trigger.FacebookEventOption
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.FacebookEventWithConsentMode(consentVariable))
}
eventTrigger, err := tm.UpsertTrigger(trigger.NewFacebookEvent(event, eventTriggerOpts...))
if err != nil {
return errors.Wrap(err, "failed to lookup event trigger: "+event)
return errors.Wrap(err, "failed to upsert event trigger: "+event)
}
if _, err := tm.UpsertTag(servertagx.NewConversionsAPITag(event, pixelID, apiAccessToken, testEventToken, template, eventTrigger)); err != nil {

View File

@ -0,0 +1,75 @@
package trigger
import (
"google.golang.org/api/tagmanager/v2"
)
func FacebookEventName(v string) string {
return "FB Conversion - " + v
}
type (
FacebookEventOptions struct {
consentMode *tagmanager.Variable
}
FacebookEventOption func(*FacebookEventOptions)
)
func FacebookEventWithConsentMode(mode *tagmanager.Variable) FacebookEventOption {
return func(o *FacebookEventOptions) {
o.consentMode = mode
}
}
func NewFacebookEvent(name string, opts ...FacebookEventOption) *tagmanager.Trigger {
o := &FacebookEventOptions{}
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: FacebookEventName(name),
CustomEventFilter: []*tagmanager.Condition{
{
Parameter: []*tagmanager.Parameter{
{
Key: "arg0",
Type: "template",
Value: "{{_event}}",
},
{
Key: "arg1",
Type: "template",
Value: name,
},
},
Type: "equals",
},
},
Filter: filter,
}
}

View File

@ -5,11 +5,13 @@ import (
"github.com/foomo/sesamy-cli/pkg/config"
servertagx "github.com/foomo/sesamy-cli/pkg/provider/googleads/server/tag"
"github.com/foomo/sesamy-cli/pkg/provider/googletag"
"github.com/foomo/sesamy-cli/pkg/provider/googleads/server/trigger"
"github.com/foomo/sesamy-cli/pkg/provider/googleconsent"
googleconsentvariable "github.com/foomo/sesamy-cli/pkg/provider/googleconsent/server/variable"
"github.com/foomo/sesamy-cli/pkg/tagmanager"
commontrigger "github.com/foomo/sesamy-cli/pkg/tagmanager/common/trigger"
commonvariable "github.com/foomo/sesamy-cli/pkg/tagmanager/common/variable"
"github.com/foomo/sesamy-cli/pkg/tagmanager/server/variable"
"github.com/foomo/sesamy-cli/pkg/utils"
"github.com/pkg/errors"
)
@ -44,15 +46,27 @@ func Server(l *slog.Logger, tm *tagmanager.TagManager, cfg config.GoogleAds) err
}
{ // create tags
eventParameters, err := googletag.CreateServerEventTriggers(tm, cfg.Conversion.ServerContainer)
eventParameters, err := utils.LoadEventParams(cfg.Conversion.ServerContainer)
if err != nil {
return err
}
for event := range eventParameters {
eventTrigger, err := tm.LookupTrigger(commontrigger.EventName(event))
var eventTriggerOpts []trigger.GoogleAdsEventOption
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.GoogleAdsEventWithConsentMode(consentVariable))
}
eventTrigger, err := tm.UpsertTrigger(trigger.NewGoogleAdsEvent(event, eventTriggerOpts...))
if err != nil {
return errors.Wrap(err, "failed to lookup event trigger: "+event)
return errors.Wrap(err, "failed to upsert event trigger: "+event)
}
if _, err := tm.UpsertTag(servertagx.NewGoogleAdsConversionTracking(event, value, currency, conversionID, conversionLabel, eventTrigger)); err != nil {

View File

@ -0,0 +1,75 @@
package trigger
import (
"google.golang.org/api/tagmanager/v2"
)
func GoogleAdsEventName(v string) string {
return "GAds - " + v
}
type (
GoogleAdsEventOptions struct {
consentMode *tagmanager.Variable
}
GoogleAdsEventOption func(*GoogleAdsEventOptions)
)
func GoogleAdsEventWithConsentMode(mode *tagmanager.Variable) GoogleAdsEventOption {
return func(o *GoogleAdsEventOptions) {
o.consentMode = mode
}
}
func NewGoogleAdsEvent(name string, opts ...GoogleAdsEventOption) *tagmanager.Trigger {
o := &GoogleAdsEventOptions{}
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: GoogleAdsEventName(name),
CustomEventFilter: []*tagmanager.Condition{
{
Parameter: []*tagmanager.Parameter{
{
Key: "arg0",
Type: "template",
Value: "{{_event}}",
},
{
Key: "arg1",
Type: "template",
Value: name,
},
},
Type: "equals",
},
},
Filter: filter,
}
}

View File

@ -5,11 +5,13 @@ import (
client2 "github.com/foomo/sesamy-cli/pkg/provider/googleanalytics/server/client"
containertag "github.com/foomo/sesamy-cli/pkg/provider/googleanalytics/server/tag"
template2 "github.com/foomo/sesamy-cli/pkg/provider/googleanalytics/server/template"
"github.com/foomo/sesamy-cli/pkg/provider/googletag"
"github.com/foomo/sesamy-cli/pkg/provider/googleanalytics/server/trigger"
"github.com/foomo/sesamy-cli/pkg/provider/googleconsent"
googleconsentvariable "github.com/foomo/sesamy-cli/pkg/provider/googleconsent/server/variable"
"github.com/foomo/sesamy-cli/pkg/tagmanager"
commontrigger "github.com/foomo/sesamy-cli/pkg/tagmanager/common/trigger"
serverclient "github.com/foomo/sesamy-cli/pkg/tagmanager/server/client"
servertrigger "github.com/foomo/sesamy-cli/pkg/tagmanager/server/trigger"
"github.com/foomo/sesamy-cli/pkg/utils"
"github.com/pkg/errors"
)
@ -57,18 +59,30 @@ func Server(tm *tagmanager.TagManager, cfg config.GoogleAnalytics, redactVisitor
}
{ // create tags
eventParameters, err := googletag.CreateServerEventTriggers(tm, cfg.ServerContainer)
eventParameters, err := utils.LoadEventParams(cfg.ServerContainer)
if err != nil {
return err
}
for event := range eventParameters {
eventTrigger, err := tm.LookupTrigger(commontrigger.EventName(event))
if err != nil {
return errors.Wrap(err, "failed to lookup event trigger: "+event)
var eventTriggerOpts []trigger.GoogleAnalyticsEventOption
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.GoogleAnalyticsEventWithConsentMode(consentVariable))
}
if _, err := tm.UpsertTag(containertag.NewGoogleAnalyticsGA4(event, redactVisitorIP, eventTrigger)); err != nil {
eventTrigger, err := tm.UpsertTrigger(trigger.NewGoogleAnalyticsEvent(event, eventTriggerOpts...))
if err != nil {
return errors.Wrap(err, "failed to upsert event trigger: "+event)
}
if _, err := tm.UpsertTag(containertag.NewGoogleAnalytics(event, redactVisitorIP, eventTrigger)); err != nil {
return errors.Wrap(err, "failed to upsert google analytics ga4 tag: "+event)
}
}

View File

@ -7,14 +7,14 @@ import (
"google.golang.org/api/tagmanager/v2"
)
func GoogleAnalyticsGA4Name(v string) string {
func GoogleAnalyticsName(v string) string {
return "GA4 - " + v
}
func NewGoogleAnalyticsGA4(name string, redactVisitorIP bool, triggers ...*tagmanager.Trigger) *tagmanager.Tag {
func NewGoogleAnalytics(name string, redactVisitorIP bool, triggers ...*tagmanager.Trigger) *tagmanager.Tag {
return &tagmanager.Tag{
FiringTriggerId: utils.TriggerIDs(triggers),
Name: GoogleAnalyticsGA4Name(name),
Name: GoogleAnalyticsName(name),
Parameter: []*tagmanager.Parameter{
{
Key: "redactVisitorIp",

View File

@ -0,0 +1,75 @@
package trigger
import (
"google.golang.org/api/tagmanager/v2"
)
func GoogleAnalyticsEventName(v string) string {
return "GA4 - " + v
}
type (
GoogleAnalyticsEventOptions struct {
consentMode *tagmanager.Variable
}
GoogleAnalyticsEventOption func(*GoogleAnalyticsEventOptions)
)
func GoogleAnalyticsEventWithConsentMode(mode *tagmanager.Variable) GoogleAnalyticsEventOption {
return func(o *GoogleAnalyticsEventOptions) {
o.consentMode = mode
}
}
func NewGoogleAnalyticsEvent(name string, opts ...GoogleAnalyticsEventOption) *tagmanager.Trigger {
o := &GoogleAnalyticsEventOptions{}
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: GoogleAnalyticsEventName(name),
CustomEventFilter: []*tagmanager.Condition{
{
Parameter: []*tagmanager.Parameter{
{
Key: "arg0",
Type: "template",
Value: "{{_event}}",
},
{
Key: "arg1",
Type: "template",
Value: name,
},
},
Type: "equals",
},
},
Filter: filter,
}
}

View File

@ -41,7 +41,7 @@ func Web(tm *tagmanager.TagManager, cfg config.GoogleAnalytics) error {
return errors.Wrap(err, "failed to lookup google tag event setting: "+event)
}
if _, err := tm.UpsertTag(containertag.NewGoogleAnalyticsGA4Event(event, tagID, eventSettings, eventTrigger)); err != nil {
if _, err := tm.UpsertTag(containertag.NewGoogleAnalyticsEvent(event, tagID, eventSettings, eventTrigger)); err != nil {
return err
}
}

View File

@ -4,14 +4,14 @@ import (
"google.golang.org/api/tagmanager/v2"
)
func GoogleAnalyticsGA4EventName(v string) string {
func GoogleAnalyticsEventName(v string) string {
return "GA4 Event - " + v
}
func NewGoogleAnalyticsGA4Event(name string, tagID, settings *tagmanager.Variable, trigger *tagmanager.Trigger) *tagmanager.Tag {
func NewGoogleAnalyticsEvent(name string, tagID, settings *tagmanager.Variable, trigger *tagmanager.Trigger) *tagmanager.Tag {
return &tagmanager.Tag{
FiringTriggerId: []string{trigger.TriggerId},
Name: GoogleAnalyticsGA4EventName(name),
Name: GoogleAnalyticsEventName(name),
Parameter: []*tagmanager.Parameter{
{
Type: "boolean",

View File

@ -0,0 +1,7 @@
package googleconsent
const (
Tag = "consent"
Name = "Google Consent"
NameGoogleConsentModeCheckVariableTemplate = "Google Consent Mode Check"
)

View File

@ -0,0 +1,35 @@
package googleconsent
import (
"github.com/foomo/sesamy-cli/pkg/provider/googleconsent/server/template"
"github.com/foomo/sesamy-cli/pkg/provider/googleconsent/server/variable"
"github.com/foomo/sesamy-cli/pkg/tagmanager"
)
func ServerEnsure(tm *tagmanager.TagManager) error {
folderName := tm.FolderName()
defer tm.SetFolderName(folderName)
{ // create folder
if folder, err := tm.UpsertFolder("Sesamy - " + Name); err != nil {
return err
} else {
tm.SetFolderName(folder.Name)
}
}
{ // create clients
consentTemplate, err := tm.UpsertCustomTemplate(template.NewGoogleConsentModeCheck(NameGoogleConsentModeCheckVariableTemplate))
if err != nil {
return err
}
if _, err = tm.UpsertVariable(variable.NewGoogleConsentModeAdStorage(consentTemplate)); err != nil {
return err
}
if _, err = tm.UpsertVariable(variable.NewGoogleConsentModeAnalyticsStorage(consentTemplate)); err != nil {
return err
}
}
return nil
}

View File

@ -0,0 +1,22 @@
package template
import (
"fmt"
"google.golang.org/api/tagmanager/v2"
)
func NewGoogleConsentModeCheck(name string) *tagmanager.CustomTemplate {
return &tagmanager.CustomTemplate{
Name: name,
TemplateData: fmt.Sprintf(GoogleConsentModeCheckData, name),
// oogleapi: Error 400: galleryReference: This field is invalid (or unsupported).
// GalleryReference: &tagmanager.GalleryReference{
// Host: "github.com",
// Owner: "analytics-engineers",
// Repository: "gtm-server-variable-google-consent-mode-check",
// Signature: "8905ba41f72b510484a3ff9dc27dabaf09c029eb1228e2d1435b5cc2e837cc8d",
// Version: "a31230ca43cdadea1b97ef7dcf76b8e9f8c04725",
// },
}
}

View File

@ -0,0 +1,101 @@
package template
const GoogleConsentModeCheckData = `___INFO___
{
"type": "MACRO",
"id": "cvt_temp_public_id",
"version": 1,
"securityGroups": [],
"displayName": "%s",
"categories": [
"UTILITY"
],
"description": "Managed by Sesamy. DO NOT EDIT.\nReads the \u0027gcs\u0027 parameter from UA/GA4 hits and returns \"granted\" or \"denied\" for the selected consent type.",
"containerContexts": [
"SERVER"
],
"brand": {
"displayName": "analytics-engineers",
"id": "github.com_analytics-engineers"
}
}
___TEMPLATE_PARAMETERS___
[
{
"type": "SELECT",
"name": "consentType",
"displayName": "Consent type",
"selectItems": [
{
"value": "ad_storage",
"displayValue": "ad_storage"
},
{
"value": "analytics_storage",
"displayValue": "analytics_storage"
}
],
"simpleValueType": true
}
]
___SANDBOXED_JS_FOR_SERVER___
const getEventData = require('getEventData');
let consentType = data.consentType;
let consentParamValue = getEventData('x-ga-gcs');
let consentValue = "0";
if (consentParamValue !== undefined) {
if (consentType === "ad_storage") {
consentValue = consentParamValue.substring(2, 3);
} else if (consentType === "analytics_storage") {
consentValue = consentParamValue.substring(3, 4);
}
}
return consentValue === "1" ? "granted" : "denied";
___SERVER_PERMISSIONS___
[
{
"instance": {
"key": {
"publicId": "read_event_data",
"versionId": "1"
},
"param": [
{
"key": "eventDataAccess",
"value": {
"type": 1,
"string": "any"
}
}
]
},
"clientAnnotations": {
"isEditedByUser": true
},
"isRequired": true
}
]
___TESTS___
scenarios: []
___NOTES___
Code generated by sesamy. DO NOT EDIT.
`

View File

@ -0,0 +1,5 @@
package variable
func GoogleConsentModeName(name string) string {
return "Google Consent Mode - " + name
}

View File

@ -0,0 +1,20 @@
package variable
import (
"github.com/foomo/sesamy-cli/pkg/utils"
"google.golang.org/api/tagmanager/v2"
)
func NewGoogleConsentModeAdStorage(template *tagmanager.CustomTemplate) *tagmanager.Variable {
return &tagmanager.Variable{
Name: GoogleConsentModeName("ad_storage"),
Parameter: []*tagmanager.Parameter{
{
Key: "consentType",
Type: "template",
Value: "ad_storage",
},
},
Type: utils.TemplateType(template),
}
}

View File

@ -0,0 +1,20 @@
package variable
import (
"github.com/foomo/sesamy-cli/pkg/utils"
"google.golang.org/api/tagmanager/v2"
)
func NewGoogleConsentModeAnalyticsStorage(template *tagmanager.CustomTemplate) *tagmanager.Variable {
return &tagmanager.Variable{
Name: GoogleConsentModeName("analytics_storage"),
Parameter: []*tagmanager.Parameter{
{
Key: "consentType",
Type: "template",
Value: "analytics_storage",
},
},
Type: utils.TemplateType(template),
}
}

View File

@ -1,38 +0,0 @@
package googletag
import (
"github.com/foomo/gocontemplate/pkg/contemplate"
"github.com/foomo/sesamy-cli/pkg/tagmanager"
commontrigger "github.com/foomo/sesamy-cli/pkg/tagmanager/common/trigger"
"github.com/foomo/sesamy-cli/pkg/utils"
)
func Server(tm *tagmanager.TagManager) error {
{ // create folder
if folder, err := tm.UpsertFolder("Sesamy - " + Name); err != nil {
return err
} else {
tm.SetFolderName(folder.Name)
}
}
return nil
}
func CreateServerEventTriggers(tm *tagmanager.TagManager, cfg contemplate.Config) (map[string]map[string]string, error) {
previousFolderName := tm.FolderName()
tm.SetFolderName("Sesamy - " + Name)
defer tm.SetFolderName(previousFolderName)
eventParameters, err := utils.LoadEventParams(cfg)
if err != nil {
return nil, err
}
for event := range eventParameters {
if _, err = tm.UpsertTrigger(commontrigger.NewEvent(event)); err != nil {
return nil, err
}
}
return eventParameters, nil
}

View File

@ -2,11 +2,13 @@ package umami
import (
"github.com/foomo/sesamy-cli/pkg/config"
"github.com/foomo/sesamy-cli/pkg/provider/googletag"
"github.com/foomo/sesamy-cli/pkg/provider/googleconsent"
googleconsentvariable "github.com/foomo/sesamy-cli/pkg/provider/googleconsent/server/variable"
containertag "github.com/foomo/sesamy-cli/pkg/provider/umami/server/tag"
containertemplate "github.com/foomo/sesamy-cli/pkg/provider/umami/server/template"
"github.com/foomo/sesamy-cli/pkg/provider/umami/server/trigger"
"github.com/foomo/sesamy-cli/pkg/tagmanager"
commontrigger "github.com/foomo/sesamy-cli/pkg/tagmanager/common/trigger"
"github.com/foomo/sesamy-cli/pkg/utils"
"github.com/pkg/errors"
)
@ -25,15 +27,27 @@ func Server(tm *tagmanager.TagManager, cfg config.Umami) error {
}
{ // create tags
eventParameters, err := googletag.CreateServerEventTriggers(tm, cfg.ServerContainer)
eventParameters, err := utils.LoadEventParams(cfg.ServerContainer)
if err != nil {
return err
}
for event := range eventParameters {
eventTrigger, err := tm.LookupTrigger(commontrigger.EventName(event))
var eventTriggerOpts []trigger.UmamiEventOption
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.UmamiEventWithConsentMode(consentVariable))
}
eventTrigger, err := tm.UpsertTrigger(trigger.NewUmamiEvent(event, eventTriggerOpts...))
if err != nil {
return errors.Wrap(err, "failed to lookup event trigger: "+event)
return errors.Wrap(err, "failed to upsert event trigger: "+event)
}
if _, err := tm.UpsertTag(containertag.NewUmami(event, cfg, template, eventTrigger)); err != nil {

View File

@ -0,0 +1,75 @@
package trigger
import (
"google.golang.org/api/tagmanager/v2"
)
func UmamiEventName(v string) string {
return "Umami - " + v
}
type (
UmamiEventOptions struct {
consentMode *tagmanager.Variable
}
UmamiEventOption func(*UmamiEventOptions)
)
func UmamiEventWithConsentMode(mode *tagmanager.Variable) UmamiEventOption {
return func(o *UmamiEventOptions) {
o.consentMode = mode
}
}
func NewUmamiEvent(name string, opts ...UmamiEventOption) *tagmanager.Trigger {
o := &UmamiEventOptions{}
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: UmamiEventName(name),
CustomEventFilter: []*tagmanager.Condition{
{
Parameter: []*tagmanager.Parameter{
{
Key: "arg0",
Type: "template",
Value: "{{_event}}",
},
{
Key: "arg1",
Type: "template",
Value: name,
},
},
Type: "equals",
},
},
Filter: filter,
}
}

View File

@ -12,6 +12,7 @@ import (
testingx "github.com/foomo/go/testing"
tagx "github.com/foomo/go/testing/tag"
"github.com/foomo/sesamy-cli/pkg/config"
"github.com/foomo/sesamy-cli/pkg/provider/googleconsent/server/template"
"github.com/foomo/sesamy-cli/pkg/tagmanager"
"github.com/foomo/sesamy-cli/pkg/tagmanager/common/trigger"
"github.com/stretchr/testify/assert"
@ -105,16 +106,16 @@ func TestNewClient_Server(t *testing.T) {
}
{ // --- Templates ---
// t.Run("upsert template", func(t *testing.T) {
// obj, err := c.UpsertCustomTemplate(template2.NewConversionsAPITag("Facebook"))
// require.NoError(t, err)
// dump(t, obj)
// })
t.Run("upsert template", func(t *testing.T) {
obj, err := c.UpsertCustomTemplate(template.NewGoogleConsentModeCheck("TESTOMAT"))
require.NoError(t, err)
dump(t, obj)
})
t.Run("list templates", func(t *testing.T) {
cmd := c.Service().Accounts.Containers.Workspaces.Templates.List(c.WorkspacePath())
if r, err := cmd.Do(); assert.NoError(t, err) {
// dump(t, r)
fmt.Println(r.Template[4].TemplateData)
dump(t, r)
fmt.Println(r.Template[3].TemplateData)
}
})
}