Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ There are several ways to support Mautic other than contributing with code.
:hidden:

mauticjs_api/tracking_script
mauticjs_api/focus_scripts

.. toctree::
:maxdepth: 2
Expand Down
107 changes: 107 additions & 0 deletions docs/mauticjs_api/focus_scripts.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
Focus Item scripts
##################

Focus Items can be embedded on external sites. Mautic splits the embed JavaScript into consent-aware parts so a site can render a Focus Item before consent and add tracking only after consent.

Check warning on line 4 in docs/mauticjs_api/focus_scripts.rst

View workflow job for this annotation

GitHub Actions / prose

[vale] reported by reviewdog 🐶 [Google.Passive] In general, use active voice instead of passive voice ('be embedded'). Raw Output: {"message":"[Google.Passive] In general, use active voice instead of passive voice ('be embedded').","location":{"path":"docs/mauticjs_api/focus_scripts.rst","range":{"start":{"line":4,"column":17},"end":{"line":4,"column":28}}},"severity":"INFO","code":{"value":"Google.Passive","url":"https://developers.google.com/style/voice"}}

.. note::

For guidance on creating and configuring Focus Items in the Mautic UI, see the :xref:`Mautic User Documentation<Mautic End User Docs>`. This page documents only the developer-facing split scripts.

Check warning on line 8 in docs/mauticjs_api/focus_scripts.rst

View workflow job for this annotation

GitHub Actions / prose

[vale] reported by reviewdog 🐶 [Mautic.FeatureList] Is this referring to a Mautic feature? If so, use 'Landing Page' instead of 'page'. Raw Output: {"message":"[Mautic.FeatureList] Is this referring to a Mautic feature? If so, use 'Landing Page' instead of 'page'.","location":{"path":"docs/mauticjs_api/focus_scripts.rst","range":{"start":{"line":8,"column":145},"end":{"line":8,"column":149}}},"severity":"INFO","code":{"value":"Mautic.FeatureList"}}

The Focus split scripts follow an analogous but entirely separate scope model to the one described in :ref:`Script scopes and split scripts<mauticjs_api/tracking_script:Script scopes and split scripts>`. The scopes below apply that analogous but separate model to Focus Items.

.. vale off

Split Focus scripts and scope model
***********************************

.. vale on

Focus embedding is split into three scopes:

Check warning on line 19 in docs/mauticjs_api/focus_scripts.rst

View workflow job for this annotation

GitHub Actions / prose

[vale] reported by reviewdog 🐶 [Google.Passive] In general, use active voice instead of passive voice ('is split'). Raw Output: {"message":"[Google.Passive] In general, use active voice instead of passive voice ('is split').","location":{"path":"docs/mauticjs_api/focus_scripts.rst","range":{"start":{"line":19,"column":17},"end":{"line":19,"column":25}}},"severity":"INFO","code":{"value":"Google.Passive","url":"https://developers.google.com/style/voice"}}

* ``RUNTIME`` - the anonymous bootstrap that the other scopes depend on. It performs no tracking.
* ``DISPLAY`` - loads and renders the Focus Item. It adds no tracking pixel, no Contact tokens, and no ``mauticform[focusId]`` marker.
* ``TRACKING`` - resolves the tracked Contact, generates the trackable redirect, and installs the view pixel and the Form focus-id marker.

These are Focus-specific scope labels. They mirror the ``BuildJsScope`` model documented on the tracking script page, but they aren't the same ``enum`` and share no code path: ``BuildJsScope`` pairs ``RUNTIME`` and ``TRACKING`` with ``ESSENTIAL`` (not ``DISPLAY``) and gates the ``mtc.js`` / ``mautic-tracking.js`` / ``mautic-essential.js`` script family, whereas these Focus scopes gate only the Focus scripts. Don't gate Focus code on ``BuildJsScope`` cases or vice versa.

Check warning on line 25 in docs/mauticjs_api/focus_scripts.rst

View workflow job for this annotation

GitHub Actions / prose

[vale] reported by reviewdog 🐶 [Mautic.FeatureList] Is this referring to a Mautic feature? If so, use 'Landing Page' instead of 'page'. Raw Output: {"message":"[Mautic.FeatureList] Is this referring to a Mautic feature? If so, use 'Landing Page' instead of 'page'.","location":{"path":"docs/mauticjs_api/focus_scripts.rst","range":{"start":{"line":25,"column":113},"end":{"line":25,"column":117}}},"severity":"INFO","code":{"value":"Mautic.FeatureList"}}

Check warning on line 25 in docs/mauticjs_api/focus_scripts.rst

View workflow job for this annotation

GitHub Actions / prose

[vale] reported by reviewdog 🐶 [Google.Parens] Use parentheses judiciously. Raw Output: {"message":"[Google.Parens] Use parentheses judiciously.","location":{"path":"docs/mauticjs_api/focus_scripts.rst","range":{"start":{"line":25,"column":1},"end":{"line":25,"column":475}}},"severity":"INFO","code":{"value":"Google.Parens","url":"https://developers.google.com/style/parentheses"}}

.. vale off

Generated scripts and endpoints
*******************************

.. vale on

Mautic serves the scopes through separate endpoints so a site can load only what it needs before consent, then add tracking later. Each endpoint path resolves against your Mautic instance's base URL.

.. list-table::
:header-rows: 1

* - Endpoint
- Included scopes
- Purpose
* - ``/focus/{id}/display.js``
- ``RUNTIME`` and ``DISPLAY``
- Renders the Focus Item with no tracking.
* - ``/focus/{id}/tracking.js``
- ``TRACKING``
- Adds the tracking layer for a Focus Item that's already displayed.
* - ``/focus/{id}.js``
- ``RUNTIME``, ``DISPLAY``, and ``TRACKING``
- The legacy aggregate script. Unchanged and backward compatible; still returns the full combined script.

All three endpoints send the ``Cache-Control: private, no-store`` response header.

.. vale off

Client-side runtime globals
***************************

.. vale on

The split scripts expose a small set of client-side global variables, a public method, and an event so a site can control when tracking activates:

* ``window.MauticFocus.enableTracking(<id>)`` - the public API for activating tracking on a displayed Focus Item after consent. If the Focus Item is registered in ``window.MauticFocusItems[id]``, it calls that item's ``loadTracking()``; otherwise it sets ``window.MauticFocusTrackingQueue[id] = true``, which the display script consumes once it registers the item.
* ``window.MauticFocusItems`` - a registry keyed by Focus Item ID. Each entry is the runtime for that Focus Item and exposes methods to load and activate the tracking layer. The display script uses it to lazily inject and activate tracking.
* ``window.MauticFocusTrackingQueue`` - a queue that bridges consent. Activation requests made before the tracking layer is ready are queued and flushed once it loads.

Check warning on line 65 in docs/mauticjs_api/focus_scripts.rst

View workflow job for this annotation

GitHub Actions / prose

[vale] reported by reviewdog 🐶 [Google.Passive] In general, use active voice instead of passive voice ('are queued'). Raw Output: {"message":"[Google.Passive] In general, use active voice instead of passive voice ('are queued').","location":{"path":"docs/mauticjs_api/focus_scripts.rst","range":{"start":{"line":65,"column":131},"end":{"line":65,"column":141}}},"severity":"INFO","code":{"value":"Google.Passive","url":"https://developers.google.com/style/voice"}}
* ``window.MauticFocusUseMauticTrackingConsent`` - when set to ``true``, the Focus display script auto-activates tracking as soon as Mautic website tracking becomes enabled, instead of waiting for a manual or CMP activation. The copied website-tracking snippet sets it to ``true`` when an administrator turns on the 'Use Mautic consent for Focus tracking' option.

Check warning on line 66 in docs/mauticjs_api/focus_scripts.rst

View workflow job for this annotation

GitHub Actions / prose

[vale] reported by reviewdog 🐶 [Google.Acronyms] Spell out 'CMP', if it's unfamiliar to the audience. Raw Output: {"message":"[Google.Acronyms] Spell out 'CMP', if it's unfamiliar to the audience.","location":{"path":"docs/mauticjs_api/focus_scripts.rst","range":{"start":{"line":66,"column":210},"end":{"line":66,"column":213}}},"severity":"INFO","code":{"value":"Google.Acronyms","url":"https://developers.google.com/style/abbreviations"}}
* ``mautic:tracking-enabled`` - a document event the tracking layer dispatches once tracking initializes. The Focus runtime listens for it to bridge consent, mirroring the tracking layer's own dispatch of this event, documented in the ``mautic:tracking-enabled`` bullet under :ref:`Client-side runtime globals<mauticjs_api/tracking_script:Client-side runtime globals>`. This is the event-dispatch signal, not the ``mauticEssentialReady`` / ``MauticJS.runtimeReady`` readiness-guard pattern.

.. code-block:: js

// check whether a Focus Item's runtime has registered yet
if (window.MauticFocusItems && window.MauticFocusItems[123]) {
window.MauticFocus.enableTracking(123);
} else {
// not ready yet — queue activation for when the display script loads
window.MauticFocusTrackingQueue = window.MauticFocusTrackingQueue || {};
window.MauticFocusTrackingQueue[123] = true;
}

.. vale off

Activating tracking after consent
*********************************

.. vale on

Call the public ``window.MauticFocus.enableTracking(<id>)`` API from your CMP's consent event. Use native JavaScript, since ``jQuery`` and other libraries aren't guaranteed to be available on third party sites:

.. code-block:: js

// called by your consent-management platform once the visitor consents
window.MauticFocus.enableTracking(123);

The copied 'Consent-managed' snippet calls this same public API inline: it invokes ``window.MauticFocus.enableTracking(<id>)`` when available, and otherwise queues the request in ``window.MauticFocusTrackingQueue`` for the display script to flush once it loads.

If the tracking layer hasn't loaded yet, the activation request is queued in ``window.MauticFocusTrackingQueue`` and flushed once the layer loads.

Check warning on line 96 in docs/mauticjs_api/focus_scripts.rst

View workflow job for this annotation

GitHub Actions / prose

[vale] reported by reviewdog 🐶 [Google.Passive] In general, use active voice instead of passive voice ('is queued'). Raw Output: {"message":"[Google.Passive] In general, use active voice instead of passive voice ('is queued').","location":{"path":"docs/mauticjs_api/focus_scripts.rst","range":{"start":{"line":96,"column":65},"end":{"line":96,"column":74}}},"severity":"INFO","code":{"value":"Google.Passive","url":"https://developers.google.com/style/voice"}}

Alternatively, set ``window.MauticFocusUseMauticTrackingConsent`` to ``true`` to let the Focus display script auto-activate tracking as soon as Mautic website tracking becomes enabled. On that path the Focus runtime activates in response to the ``mautic:tracking-enabled`` document event rather than waiting for a manual or CMP call.

.. vale off

Dynamic Web Content injection behavior
**************************************

.. vale on

The Dynamic Web Content build-JS subscriber now parses Dynamic Web Content through the DOM rather than treating it as opaque markup. It injects only same-origin Focus scripts through two independent allow-rules. It always allows ``/focus/{id}/display.js`` so a Focus Item renders regardless of consent state. When ``MauticJS.trackingEnabled`` is ``true``, it additionally allows the legacy ``/focus/{id}.js`` — this injection is added on top of the always-allowed display script, not in place of it — so the combined tracking-capable script loads through Dynamic Web Content only once tracking is active.
1 change: 1 addition & 0 deletions docs/mauticjs_api/tracking_script.rst
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ The split scripts expose a small set of client-side global variables and an even
* ``MauticJS.runtimeReady`` - set to ``true`` once the runtime bootstrap has loaded. Tracking code guards on it before running.
* ``MauticJS.trackingEnabled`` - ``false`` in the essential or runtime build and ``true`` once the tracking layer loads.
* ``MauticJS.requestWithCredentials`` - ``false`` by default in the essential or runtime build and ``true`` once tracking loads.
* ``mautic:tracking-enabled`` - a document event the tracking layer dispatches once tracking initializes. See :doc:`/mauticjs_api/focus_scripts` for how the Focus runtime consumes it to bridge consent.
* ``mauticEssentialReady`` - a convention event, not something the generated runtime emits on its own. The authoritative readiness flag is ``MauticJS.runtimeReady``; the consent-managed essential loader snippet - the copy-paste snippet that loads ``/mautic-essential.js`` - dispatches ``mauticEssentialReady`` once ``MauticJS.runtimeReady === true`` by calling ``MauticJS.dispatchEvent('mauticEssentialReady')``. That helper builds a native ``CustomEvent`` and dispatches it on ``document``, so browser-side code following the split-script loader pattern can rely on it as a readiness hook and listen with ``document.addEventListener('mauticEssentialReady', ...)``.

Because the essential script may have finished loading before your code runs - in which case the event has already fired and a late listener would never run - guard on ``MauticJS.runtimeReady`` first and run immediately when it's already ``true``, falling back to the listener only when the runtime isn't ready yet. The shipped tracking add-on snippet follows this same dual path. This handles both cases safely:
Expand Down
Loading