Package: wagtail-tag-manager
Wagtail Tag ManagerWagtail Tag Manager (WTM for short) is aWagtailaddon
that allows for easier and GDPR compliant administration of scripts and tags.In this package the term "tag" is being used for code snippets being injected
into HTML. This is not to be confused with tags used to identify content in the
CMS, such as pictures and documents.‼️ Breaking changesAs of version 2.0, consent is stored differently in thewtmcookie. The reason for this change is
to prevent so-called "cache-busting" and only refresh the WTM cookie after a certain period of time
(specified inWTM_COOKIE_REFRESH).
The cookie will now contain abase64anduriencoded JSON string which stores both the consent state
and additional information. Old versions of the cookie
(e.g.necessary:true|preferences:unset|statistics:pending|marketing:false) will automatically be
upgraded when detected. Once decoded, it will look something like this:{"meta":{"id":"b402114a-352f-488f-8481-834cd91a1b2b","refresh_timestamp":1694520568.531865,"set_timestamp":1694520573.685324},"state":{"necessary":"true","preferences":"unset","statistics":"pending","marketing":"false"}}To easily parse the cookie using JavaScript, you can use this code snippet:const{meta,state}=JSON.parse(atob(decodeURIComponent(cookie_content_goes_here)));You can ready more on how to easily access this state from your front-endhere.FeaturesWagtail Tag Manager offers functionality similar to platforms likeAdobe Dynamic Tag Management,Google Tag ManagerandTealium iQwithout the need of a third party. It's fully integrated into Wagtail.This approach comes with a couple of advantages, most prominently the ability
to inject tags into a page before the response is send to a client.AdministratorsManage scripts and tags from within Wagtail, with powerful options to define load order.Store reusable content in constants and variables and easily add them to your tags.Create triggers to load tags based on events in the browser.Create cookie declarations to provide end-users with a full picture of the tracking taking place.DevelopersCreate custom variables to give administrators functionality specific to your use-cases.Table of contentDisclaimerRequirementsInstructionsTemplate tagswtm_instant_tagswtm_lazy_managerwtm_cookie_barwtm_includePreference managementContext processorsSettingsWTM_TAG_TYPESWTM_INJECT_TAGSWTM_MANAGE_VIEWWTM_COOKIE_EXPIREWTM_COOKIE_REFRESHWTM_CACHE_TIMEOUTWTM_PRESERVE_VARIABLESWTM_INJECT_STYLEWTM_INJECT_SCRIPTWTM_SUMMARY_PANELSWTM_ENABLE_SCANNERWTM_CHROMEDRIVER_URLCustom variablesPage tag mixinLazy triggersSandboxConceptWho's using itLicenseDisclaimerThis package attempts to ease the implementation of tags by the new ePrivacy
rules as defined by the European Union. I urge you to read about these new
rules and ensure you are properly configuring your tags. This package is free
and the author can not be held responsible for the correctness of your
implementation, or the assumptions made in this package to comply with the new
ePrivacy regulation.Read more about theePrivacy Regulation.Included in this package is a cookie bar which admittedly provides too little
information to end users regarding the purpose of the scripts you are placing
on the website. For compliance, please use thecookie_bar.htmltemplate to
change the text shown in the cookie bar.RequirementsPackageVersion(s)Django3.2, 4.0, 4.1, 4.2Wagtail4.1, 4.2, 5.0. 5.1Python3.8, 3.9, 3.10, 3.11InstructionsInstallation:pip install wagtail-tag-managerAdd the application to yourINSTALLED_APPS:INSTALLED_APPS=[# ...'wagtail_modeladmin','wagtail_tag_manager',# ...]If you wish to enable the cookie bar settings (allowing you to change to title
and text displayed in the cookie bar), also includewagtail.contrib.settingsin theINSTALLED_APPS.Include the middleware:MIDDLEWARE=[# ..."wagtail_tag_manager.middleware.CookieConsentMiddleware",'wagtail_tag_manager.middleware.TagManagerMiddleware',# optional# ...]WTM offers two ways to implement it's functionality. You can either choose to
use theTagManagerMiddleware(which will rewrite the html on each request)
or use the{% wtm_instant_tags %}and{% wtm_lazy_manager %}template
tags.If you prefer to use the template tags to inject tags into your templates,
set theWTM_INJECT_TAGSandWTM_INJECT_SCRIPTsettings toFalseand implement the template tags as follows:{%loadwtm_tags%}<head>{%wtm_instant_tags'top_head'%}...{%wtm_instant_tags'bottom_head'%}</head><body>{%wtm_instant_tags'top_body'%}...{%wtm_instant_tags'bottom_body'%}{%wtm_lazy_manager%}</body>Include the urls:fromdjango.urlsimportinclude,pathfromwagtail_tag_managerimporturlsaswtm_urlsurlpatterns=[# ...path('wtm/',include(wtm_urls)),# ...path('',include(wagtail_urls)),# ...]Template tagsAs an alternative to using the middleware you can use thewtm_instant_tagsandwtm_lazy_managertemplate tags. Please be sure to use theTagManagerMiddlewareOR the template tags, never both.wtm_instant_tagsTo load all instant tags at once:{%loadwtm_tags%}<head>...{%wtm_instant_tags%}</head>To load tags corresponding to a certain position:{%loadwtm_tags%}<head>{%wtm_instant_tags'top_head'%}...{%wtm_instant_tags'bottom_head'%}</head><body>{%wtm_instant_tags'top_body'%}...{%wtm_instant_tags'bottom_body'%}</body>wtm_lazy_manager{%loadwtm_tags%}<body>...{%wtm_lazy_manager%}</body>Optionally, you can disable either the script and/or the styling.{%loadwtm_tags%}<body>...{%wtm_lazy_managerinclude_style=Falseinclude_script=False%}</body>wtm_cookie_bar{%loadwtm_tags%}<body>{%wtm_cookie_bar%}...</body>wtm_includeWTM comes with thewtm_includetemplate tag to accommodate loading of
resources and markup based on the tag strategy and consent given. It can be
used as a way to load html, css or javascript files.{%loadwtm_tags%}<body>...{%wtm_include"necessary""css/style.css"%}{%wtm_include"necessary""js/style.js"%}{%wtm_include"necessary""content.html"%}...</body>Alternatively, you can use it as a block:{%loadwtm_tags%}<body>...{%wtm_include"statistics"%}<script>console.log("Included conditionally");</script>{%wtm_endinclude%}...</body>Preference managementYou can use the following provided template tags to render a tag status
overview, a table with cookie declarations or a consent form.{%wtm_tag_table%}{%wtm_declaration_table%}{%wtm_manage_form%}Context processorsTo enable the context processors, add the following to your settings:"context_processors":[# ..."wagtail_tag_manager.context_processors.consent_state",]You can now use the following value in your templates:{{wtm_consent_state.necessary}}{{wtm_consent_state.preferences}}{{wtm_consent_state.statistics}}{{wtm_consent_state.marketing}}These will return a boolean indicating wether or not tags specific to the
corresponding state should load.SettingsWTM_TAG_TYPESWTM_TAG_TYPES={# key, verbose name, setting"necessary":(_("Necessary"),"required"),"preferences":(_("Preferences"),"initial"),"statistics":(_("Statistics"),"initial"),"marketing":(_("Marketing"),""),}Allows you to define the tag types available. This can be helpful if you'd like
the change the terminology used, or when you'd prefer to split a type in
multiple sections. Notice the two keywords (requiredandinitial) used.Tags marked asrequiredcan not be disabled and will always be included on
every page.Tags marked asinitialwill be included as long as no explicit consent has
been given by the end user, provided the browser allows cookies. While no
consent has been given, these tags will be loaded lazily to honor the browser
settings (which we can only read using javascript).The third option is to mark a tag asdelayed. This will ensure the tag will
not load on the first page load, but only from the second load forward.WTM_INJECT_TAGSWTM_INJECT_TAGS=TrueInstructs the middleware to inject all tags marked "instant load" in the
document. Disable this if you would rather use the{% wtm_instant_tags %}template tags.WTM_MANAGE_VIEWWTM_MANAGE_VIEW=TrueAllows you to enable or disable the included "manage" view allowing users to
get insight in the tags running on your site and adjust their preferences.
The view is enabled by default.WTM_COOKIE_EXPIREWTM_COOKIE_EXPIRE=365Sets the expiration time in days of WTM's cookies. Notice that this is only
applicable to the consent cookies used by WTM, not any cookies placed by tags.WTM_COOKIE_REFRESHWTM_COOKIE_REFRESH=30Sets the refresh time in days of WTM's cookies. Notice that this is only
applicable to the consent cookies used by WTM, not any cookies placed by tags.WTM_CACHE_TIMEOUTWTM_CACHE_TIMEOUT=1800Sets the amount of seconds the cache will be preserved. At the moment,
caching is only applied to constants, which will refresh when a constant is
saved. Default is 30 minutes.WTM_PRESERVE_VARIABLESWTM_PRESERVE_VARIABLES=TrueConfigures whether the variables are preserved for each request, or refreshed
for each tag applied to a response. When set toFalse, a query will be done
for each single tag which will add up quickly.WTM_INJECT_STYLEWTM_INJECT_STYLE=TrueChange toFalseto prevent WTM's included styles from loading. This is useful
if you wish to style the cookiebar yourself.WTM_INJECT_SCRIPTWTM_INJECT_SCRIPT=TrueChange toFalseto prevent WTM's included scripts from loading. This is
useful if you don't want to use the inlcuded lazy loading and cookie bar
functionality. While enabled, the script will expose thewindow.wtm.consent()function. When called, the function will retrieve the current consent state
and information from thewtmcookie. This will like something like this:{"meta":{"id":"b402114a-352f-488f-8481-834cd91a1b2b","refresh_timestamp":1694520568.531865,"set_timestamp":1694520573.685324},"state":{"marketing":"false","necessary":"true","preferences":"true","statistics":"true"}}WTM_SUMMARY_PANELSWTM_SUMMARY_PANELS=FalseDisables or enables the summary panels visible on the Wagtail admin dashboard.WTM_ENABLE_SCANNERThis is an experimental feature.WTM_ENABLE_SCANNER=FalseWhen enabled, allows scanning of cookies placed on the website. Use this to
automatically generate cookie declarations. Will attempt to use Chrome Driver
when available, and will fall back to regular requests if not.WTM_CHROMEDRIVER_URLThis is an experimental feature.WTM_CHROMEDRIVER_URL="http://0.0.0.0:4444/wd/hub"Allows configuration of the docker container running an instance ofselenium/standalone-chrome.When developing, use the following command to run the docker container and
ensure that your site is configured be accessible over your computer's public
ip. Otherwise the docker container won't be able to access the website.https://hub.docker.com/r/selenium/standalone-chrome/Custom variablesIn addition to managing variables in the admin interface, variables can also be
created in your source code by registering aCustomVariable.fromwagtail_tag_manager.decoratorsimportregister_variablefromwagtail_tag_manager.optionsimportCustomVariable@register_variableclassVariable(CustomVariable):name="Custom variable"description="Returns a custom value."key="custom"defget_value(self,request):return"This is a custom variable."Page tag mixinIf you would like to include tags on a page, include theTagMixinmixin.
Under the "Settings" tab of the corresponding page type a list of tags will be
shown. By selecting these, these tags will be included when the page loads.Additionally, by selecting the "Include children" field, all descending pages
of the configured page will also load the chosen tags.Note that the consent state is being applied to these tags. If the selected tag
is marked as, for example, "marketing", the end-user still must allow this type
of tags before is is being injected.fromwagtail_tag_manager.mixinsimportTagMixinclassHomePage(TagMixin,Page):passLazy triggersTriggers allow you to monitor events on the frontend of your website and load a
tag after a specified event has occurred. By using conditions you are able to
harness (custom) variables to only trigger a tag once your event complies with
the conditions that you specified.SandboxTo experiment with the package you can use the sandbox provided in this
repository. To install this you will need to create and activate a
virtualenv and then runmake sandbox. This will start a fresh Wagtail
install, with the tag manager module enabled, onhttp://localhost:8000andhttp://localhost:8000/cms/. The superuser credentials aresuperuserwith the passwordtesting.Various types of tags, constants and variables are enabled out of the box.
Check out the console in your browser to see them in action.ConceptWTM comes with the following tag types pre-configured:NameSettingNecessaryRequiredPreferencesInitialStatisticsInitialMarketingDefaultThese types correspond to the segmentation made by the EUhere.StateRequiredInitialDelayedDefaultNo cookies accepted.yesnononoCookies implicitly accepted through browser settings.yesyesyes¹noCookies explicitly accepted, noting tracking functionality.²yesyesyes¹yes¹ From the second page load onward.² According to the ePrivacy regulation, mentioning that you are using tracking functionality is mandatory.Note that in the case of Statistics cookies or local storage, you are obliged
to still show a notification at least once, noting that you are using cookies
for analytical and performance measurement purposes.When implementing Marketing cookies, the user has to explicitly give permission
for you to enable them for their session. When asking for permission, you must
explicitly state the tracking functionality of the script you are using.To ease the implementation by this concept, Wagtail Tag Manager allows you to
define a tag as "Necessary", "Preferences", "Statistics" or "Marketing".
When properly configured, it'll take care of loading the correct tag at
the correct time, taking in account the following scenario's:The user has not accepted cookies.RequiredInitialDelayedDefaultInstantyesnononoLazyyesnononoThe user has accepted cookies through browser settings.RequiredInitialDelayedDefaultInstantyesyes¹yes²noLazyyesyesyes²no¹ Will be loaded lazily.² From the second page load onward.As the acceptance of "Initial" tags can only be verified client side, we'll
first load all the "Initial" tags lazy (whether they are instant or not).Please note that we still have to show a message stating that we are using
tags with analytical purposes.The user has explicitly accepted cookies for your site.RequiredInitialDelayedDefaultInstantyesyesyesyesLazyyesyesyesyesWho’s using it?I'd love to hear from sites and applications where WTM is being used. Please
contact me if you'd like your implementation to be listed here!LicenseTo make Wagtail Tag Manager accessible, it's is published under the BSD 3-Clause
"New" or "Revised" License. For more information, please refer to theLICENSEfile in this repository.