Visitor Front-End API

Puzzel Contact Centre Chat Visitor Front-End API

This document describes how to control the behavior of the Puzzel Contact Centre Chat Visitor application injected on customer web pages for more complex integrations.

This document covers the front-end API that is available in the browser when Puzzel’s script tag is injected, and our application is started.

Through the front-end API any external script running on the same web page can:

  • Get information about the current state in the Puzzel application (useful for testing, debugging and custom logic)

  • Perform actions through exposed functions that can be called by other scripts

  • Get notified and (optionally) transform data at specific lifecycle points in the Puzzel application by implementing hook-functions (some hooks like the “pzlOnBefore…”-hooks can act as middleware in more advanced scenarios)

Get information

Information about the current application state is exposed in the global browser context under:

window.pzl

(for debugging/testing you can view the content of this object by opening the browser dev tools and just type pzl in the console).

The pzl-object is created when Puzzel’s application “pzl_loader.js” has loaded and started (see the “Hooks”-section of this document for more information about how to determine when the API is ready to use).
During runtime, the pzl-object will be populated with various state information and API-functions.

These are the main properties exposed under window.pzl:

pzl.version = { ... } contains an object with versions and build time for all Puzzel modules currently loaded:

Example:

pzl.version
{
   "moduleLoader": "1.1.0.154195 (2024-11-13T10:26:51.619Z)",
   "renderModule": "1.0.0.153984 (2024-11-12T09:58:47.371Z)",
   "chatModule": "1.0.3.153708 (2024-11-07T12:25:59.194Z)"
}

pzl.info = { ... } contains various information about e.g. which site mapping is currently matching the URL, which configuration is used (id, name and version) and which modules are currently loaded.

pzl.info.loadedModules = { ... } contains similar info as pzl.version

pzl.info.activeChains = { ... } contains information about which interaction chains that are currently active on the page, and for each active chain, which interaction is currently loaded/displayed.

An interaction chain is usually identified by the ruleId of the rule that initially triggered it, i.e. usually chainId === ruleId. But if an interaction chain is started using the API (see “Perform actions” section below), the chainId can be set manually (or the default value will be “api” if not specified).

Example:

pzl.info
{
   "loadedModules": {
       "moduleLoader": { ... },
       "renderModule": { ... },
       "chatModule": { ... }
   },
   "siteMappingName": "Swedish site",
   "configId": "bf960cfa-0154-426a-b785-74f8c3a9725a",
   "configVersion": "34",
   "configName": "My test config",
   "activeChains": {
       "74b321a8-6ba2-4f7a-a4da-914e2bf49499": {
           "chainId": "74b321a8-6ba2-4f7a-a4da-914e2bf49499",
           "ruleId": "74b321a8-6ba2-4f7a-a4da-914e2bf49499",
           "ruleName": "Rule for all",
           "currentInteractionId": "6394745c-6ab7-40be-b176-1cef22f889d0"
       }
   }
}

Perform actions

To control the Puzzel visitor application and modules from custom scripts, the application exposes some API-functions under pzl.api = { ... }. Some types of sub-modules will add their own API-functions under pzl.api when launched (e.g. chat-module when a visitor starts a chat)

These are the API-functions always available (exposed by “pzl_loader.js”):

pzl.api.triggerRule({...})

Trigger a specific rule configured in the web engage admin portal, just as if its conditions matched. Its outcome configuration will be evaluated, so if e.g. different start-interactions are set for different timemodule-exits, the outcome will launch different interactions depending on the current time of day, etc.

The function takes an object as argument with the following properties:

{
   ruleId: <String>
   ruleName: <String>
   chainId: <String>, // default <ruleId>
   force: <Boolean>   // default false
   ...rest
}

Either ruleId or ruleName must be specified, and these properties determine which rule to trigger.

force (default false) will trigger the rule even if there is already an active chain started from this rule (default behaviour is that only be one chain started from the same rule, and only one chain leading to chat may be active at the same time. Setting force: true overrides that)

The property chainId can be set to a custom string to identify the chain launched by this rule (default chainId is the ruleId).

Any other properties in this object will be passed on as input-data to the first interaction (existing properties with the same key will be overridden).

Examples:

pzl.api.triggerRule({ ruleName: 'My rule' });
pzl.api.triggerRule({
   ruleId: 'rule-guid-abc123',
   queueKey: 'Q_CHAT_9',
   language: 'en',
   visitorClaims: {
      thisIsAVisitorClaim: 'hello claim'
   }
});
pzl.api.showInteraction({...})

Show a specific interaction configured in the web engage admin portal.

The function takes an object as argument with the following properties:

{
   interactionId: <String>,
   chainId: <String>   // default 'api'
   ...rest
} 

The property interactionId is required and determines which interaction to start.
If chainId is specified, this will be the id of the chain launched from this interaction (default “api”).

Any other properties in this object will be passed on as input-data to the interaction.

Examples:

pzl.api.showInteraction({ interactionId: 'some-guid' });
pzl.api.showInteraction({
   interactionId: 'chat_interaction_guid',
   queueKey: 'Q_CHAT_9'
});
pzl.api.showInteraction({
   interactionId: 'chat_interaction_guid',
   queueKey: 'Q_CHAT_9',
   visitorClaims: {
      some_custom_id: '123abc'
   }
});
pzl.api.showInteraction({
chainId: 'my-chain',
interactionId: 'identification_interaction_id',
queueKey: 'Q_CHAT_9',
email: 'some.one@company.com',
prevDimensions: {
height: '721px',
width: '360px'
}
});
pzl.api.nextInteraction({...})

This function will transition to the next interaction in an interaction chain. E.g. from “chat” -> “survey”, etc. If there is no next interaction in the chain (i.e. the currently loaded interaction is last in its chain), the chain will be closed.

Note: Some interactions may link to more than one next interaction (e.g. a panel with multiple buttons). In that case, next interaction will be the first one with a valid link found in its configuration.

The function takes an object as argument with the following properties:

{
   chainId: <String>,
   force: <Boolean>,  //default false
   ...rest
}

The property chainId determines in which chain to move forward one step. For interaction chains triggered/started by a rule in web engage, this is usually the ruleId. If the chain was started using the API, it can be a custom value (default “api”).

The property force is used in some interaction types, e.g. if the active interaction is a chat-interaction and force=== true, the chat will leave the chat and transition to next without showing the confirmation modal.

Any other properties in this object will be passed on as input-data to the next interaction if possible.

Note: For some transitions, e.g. from chat with force=== false (i.e. showing a modal before transitioning), any extra input data in this call will currently be ignored and not passed on to next.

The nextInteraction()-function will return a promise that resolves with the interactionId of the next interaction, or null if the chain was finished.

Examples:

// Transition chain "api" to its next interaction
pzl.api.nextInteraction();
// Transition chain "rule-guid" and also add/update the "queueKey"-property
pzl.api.nextInteraction({
chainId: 'rule-guid',
queueKey: 'Q_CHAT_9'
});
pzl.api.minimizeInteraction({...})

This function will set/toggle minimize state of the currently active interaction in chain with chainId.

Note: Interactions that are rendered injected in the page DOM (i.e. has its “Parent DOM element selector” set to anything else than “body”) will currently ignore this call.

The function takes an object as argument with the following properties:

{
chainId: <String>,  // default "api"
minimize: <Boolean> // default undefined
}

The property chainId determines which chain minimize.

The property minimize can be set true/false to enforce minimize/restore.

If minimize is undefined (default) the minimize state will toggle.

Examples:

// Toggle minimize state in chain "rule-guid1" 
pzl.api.minimizeInteraction({chainId: 'rule-guid1'})
// Set minimize state to false in chain "api" 
pzl.api.minimizeInteraction({minimize: false})
pzl.api.closeInteraction({...})

This function will close the currently active interaction and finish the interaction chain, even if linked interactions exist in the current interaction.

The function takes an object as argument with the following property:

{
chainId: <String> // default "api"
}

The property chainId determines which chain to finish.

Examples:

// Close interaction chainID: "rule-guid1" 
pzl.api.closeInteraction({chainId: 'rule-guid1'})
pzl.api.evaluateRules()This function triggers a re-evaluation of the configured engagement rules. A use case is if the customer’s webpage is a single-page-app that changes state without a page reload. Rules can be configured to trigger on content of the DOM, so if the DOM changes, this function can be used to notify the Puzzel application to re-evaluate rules.
pzl.api.trackCustomEvent(trackingObject)

This function can be used to send custom tracking events to Puzzel’s statistics service.

The function takes an object as property, and it will use it to populate the properties-object of a tracking event.

Example:

pzl.api.trackCustomEvent({hello: 'xyz'});

Will generate and POST a tracking event like this:

{
"type": "CustomEvent",
"properties": {
"siteMappingName": "default",
"configId": "config-123abc",
"configVersion": "222",
"configName": "Test config-123abc",
"hello": "xyz"
}
}
pzl.api.setLoginDetected(<Boolean>)

This function sets the “login detected”-state, just as if a “Detect login” or a “Detect logout”-interaction was triggered by a rule. This state can control how a “visitor identification”-interaction will behave, and this function can be used by an external script to create more complex/custom logic. E.g. when detecting login state is hard to do reliably with engagement rule conditions.

The function takes a boolean as parameter (default true).

Examples:

// Both these calls will set state to “loggedIn”
pzl.api.setLoginDetected();
pzl.api.setLoginDetected(true);
// This call will clear the “loggedIn”-state
pzl.api.setLoginDetected(false);
pzl.api.setClaims({...})

This function can be called to set visitor claims. The claims will be passed on to the next interaction when transitioning.

This function takes an object of keys and string values. If any claims has have already been set, this will overwrite them.

Example:

// If this is called before starting a chat...
pzl.api.setClaims({
"email": "someone@somewhere.com",
"someCustomId": "12345"
});

Will set the claims “email” and “someCustomId” in the conversation and be visible to the agent.

Note: The claims are not stored persistently until next interaction loads. So it may be necessary to call this function on every page load to ensure the claims will be set.

pzl.api.addClaims({...})

This function is the same add setClaims() above, but merges the claims in the input object with any existing claims.

Example:

// After running these two calls:
pzl.api.setClaims({
"claim1": "abc"
});
pzl.api.addClaims({
"claim2": "123"
});

Will make these visitor claims passed to next interaction:

{
"claim1": "abc",
"claim2": "123"
}
pzl.api.registerHooks(<obj>)

This function can be used to register an object containing hook functions (default is the browser’s global window-object).

All available hooks are listed in the next section “Hooks”

Examples:

pzl.api.registerHooks({
pzlOnBeforeInteractionTransition: (o) => {
console.log(o.interactionInputData);
},
pzlOnRuleMatch: ({ ruleItem }) => { ... }
});

pzl.api.registerHook(<String>, <function>)

 

This function registers a specific hook-function in the current hooks container (default is the global window-object)

Examples:

// Create an isolated hooks-object
pzl.api.registerHooks({});

// Register hook-functions in it
pzl.api.registerHook("pzlOnBeforeEvaluateRules",
   (o) => {
      console.log(o.ruleItems)
   }
);
pzl.api.registerHook("pzlOnBeforeInteractionTransition",
   (o) => {
      console.log(o.interactionInputData);
   }
);
// Deregister hook
pzl.api.registerHook("pzlOnRuleMatch", null);

 
The chat module adds these API-functions:

pzl.api.setChatLanguage(langCode)

Switch language of a loaded chat.

Use case primarily for testing. 

Example:

pzl.api.setChatLanguage('en') 

Hooks

To let external scripts be notified of specific events in the Puzzel application, a set of hook-functions can be implemented. The application will look for these functions and call them (if they exist) with data relevant to the specific hook. In many hook-functions, the data can be transformed and returned to the Puzzel application, thus acting like a middleware to add or modify the data and alter the flow of the application. A hook may also return a Promise that will be awaited to support asynchronous logic (e.g. a hook could fetch data from a REST-API and inject it as visitor claims into the data before the Puzzel application transitions to the next interaction)

A special hook is called when the Puzzel application is loaded and ready to use:

window.pzlOnStart({...})

The hook will be called with an object as argument:

{
status: "started",
configInfo: {
"siteMappingName": "default site",
"configId": "1234-abcd",
"configVersion": "15",
"configName": "Test configuration"
}
}

or

{
status: "error",
error: <error-obj>
}

Example:

Implement this function before the puzzel script tag is injected/loaded:

window.pzlOnStart(function (obj) {
if (obj.status === 'started') {
// Now it's possible to use the puzzel api.
pzl.api.showInteraction({...});
}
});

If the order of execution for different scripts on the page is not predictable, something like this could be used to detect when the Puzzel application is ready:

function puzzelIsReady(obj) => {
   if (obj.status === 'started') {
      // Now it's possible to use the puzzel api.
      pzl.api.showInteraction({...});
   }
}

if (window.pzl && window.pzl.info && window.pzl.info.status === 'started') {
   // Puzzel app is already started
   puzzelIsReady({ status: 'started' }); 
} else {
   // Puzzel app not yet started
   window.pzlOnStart = puzzelIsReady;
}

The above code should work when executed both before and after the Puzzel app is started.

The pzlOnStart()-hook needs to be implemented in the global window-object (because it must exist already when the Puzzel application starts).

Other hooks can also be implemented under window (which is the default context), and they are all prefixed with “pzl” to avoid naming conflicts. But they can also be implemented in an isolated object registered by using the API-function pzl.api.registerHooks({...}) described in the previous section of this document.

These are the hook-functions called by the Puzzel applications at various points of execution:

window.pzlOnStart({
status,
configInfo,
error
})

This hook is described above, and it’s normally the best hook to implement to know when the application is started and ready.

If the pzlOnStart()-hook returns the string "skipEvaluate", the application will not automatically evaluate engagement rules on startup. The use case for “skipEvaluate” could be when the page is loaded asychronously and the DOM may not be stable at the time the Puzzel app starts. By returning “skipEvaluate”, rule-evaluation is be deferred and can be done later (when the DOM is ready) by calling pzl.api.evaluateRules()

window.pzlOnLoad({ bootstrap })

This hook is called when the Puzzel application has loaded, but not yet started.

Like pzlOnStart(), it also needs to be implemented in the global window-object, but this hook is normally not very useful when the Puzzel application is injected with the standard script-tag.

But if the application has been configured to defer automatic bootstrap (see next section “Manual/deferred bootstrapping”), this hook is called when the application is loaded and ready to be started. In that case, the property bootstrap will exist in the argument-object, which is a function that can be called to manually start the PUzzel application.

The bootstrap-function takes an object as argument with the following (optional) properties:

{
hooks: <object>, // default window
visitorClaims: <object> // default {}
}

hooks can specify an object containing an isolated hooks-context.

visitorClaims can be an object containing key/value pairs of additional visitor claims that will be added to the interaction input data and used in e.g. a chat.

Examples:

window.pzlOnLoad = ({ bootstrap }) => {
bootstrap && bootstrap({
hooks: {
pzlOnStart: () => {
/* do something with the api */
}
},
visitorClaims: {
name: <String>,
some_other_claim: <String>
}
})
};

The bootstrap-function returns a promise that resolves when the application is started (at the same time as pzlOnStart() is called).

The pzl.api is is ready to use after awaiting bootstrap(), like this:

try {
await bootstrap();
/* do something with the api*/
} catch (error) {
/* bootstrap failed */
}
pzlOnRuleMatch({ ruleItem })

This hook is called every time a rule (defined in the web engage configuration) has matched.

In the argument-object, the property ruleItem contains the full configuration object of the matching rule. 

Note: This object is the internal data-object representing a rule, so there may be properties added or changed in this object in the future. Basic properties like id, name, etc. should be static though.

Example of a ruleItem:

{
"id": "rule-guid-1",
"name": "Always match",
"description": "One rule to rule them all!",
"alwaysEvaluate": true,
"outcome": {
"timeModuleId": "3780_time",
"language": "sv",
"exitList": [ ... ]
},
"ruleSetList": [ ... ]
}

After the rule has matched, its outcome-configuration will be evaluated (time modules are checked, language is set, queues are checked).

By implementing this hook, it is possible to alter the rule-item data before its outcome is evaluated.

Example:

window.pzlOnRuleMatch = ({ ruleItem }) => {
   if (ruleItem.id = '123') {
      return {
         ...ruleItem,
         outcome: {
            ...ruleItem.outcome,
            language: 'en'
         }
      }
   }
}

The above hook would change the language of the interaction chain started by ruleId: "123" to English.

Note: Transforming data in hooks should only be done for advanced setups and must be done with care! It is easy to break the interaction chain by fiddling with this data!

pzlOnBeforeEvaluateRules({ ruleItems })

This hook is called before the rules defined in the web engage admin portal are evaluated.

The hook can transform the array and return a new ruleItems-array that will be evaluated instead.

Note: Mutating the items in the array may cause unexpected behavior. If items should be modified, cloning them is preferred.

pzlOnAfterEvaluateRules({ ruleItems })

This hook is called after all rules have been evaluated and any triggered interactions are started.

This hook is for information only, and any return value is ignored.

pzlOnBeforeInteractionTransition({
interactionInputData,
interactionHistory
})

This hook is called before an interaction-chain transitions to the next interaction (or when the first interaction is triggered from a rule).

The argument is an object containing the interactionInputData (object) that is sent as input to next interaction, and the interactionHistory (array) of the chain with input data for all previous transitions in the chain.

The interactionInputData-object will contain different data depending on the type of interaction, but some properties should always be there, e.g. chainId, interactionId and interactionType.

This is an example of an interactionInputData-object:

{
    "chainId": "<rule-guid>",
    "interactionId": "<interaction-guid>",
    "formValues": {
        "queueKey": ""
    },
    "prevPosition": {
        "anchorPoint": "bottomRight",
        "parentSelector": "body",
        "usePreviousPosition": false,
        "xOffset": "20px",
        "yOffset": "40px",
        "zIndex": 1000
    },
    "prevDimensions": {
        "height": "680px",
        "width": "360px"
    },
    "visitorClaims": {}
}

The hook can return a transformed interactionInputData-object, or a promise that resolves with a new interactionInputData-object for asynchronous logic.

pzlOnAfterInteractionTransition(({
interactionInputData,
interactionHistory
})

This hook is called after an interaction transition is finished and the next interactions has started.

This hook is for information only, and any return value is ignored.

pzlOnBeforeChainFinished({
chainId,
reEvaluateRules
})

This hook is called when an interaction chain is about to be finished.

The argument is an object that contains the chainId (string) of the finishing chain, and reEvaluateRules (boolean) that indicates whether the engagement rules will be re-evaluated after finishing the chain.

The hook can control/override the behavior by returning either a string value or an object.

If it returns the string "abortFinishChain", the operation is aborted and the chain will not be finished.

If it returns the string "skipEvaluate", the chain will finish, but without automatically re-evaluating the engagement rules afterwards.

If it returns an object, the finish-operation will be aborted, and the chain will instead transition to a next interaction. The object will be interpreted as an interactionInputData-object (described in the pzlOnBeforeInteractionTransition()-description), and the object needs to contain at least an interactionId to use as “next”.

If there’s also a property force ===  true in the input argument-object when this hook is called, it is not possible to redirect to another interaction with an object (if force === true, the application is finishing the chain due to an unrecoverable error, and redirecting on finish could create infinite loops)

Manual/deferred bootstrapping

The default behavior of the Puzzel application is to automatically start and evaluate the engagement rules as soon as the Puzzel script-tag is loaded.

For advanced setups, it is possible to defer starting the application and bootstrap it manually. This makes it possible to decide exactly when the application should start, and also inject custom visitor claims and hook-functions from start.

To enable deferred bootstrapping, the attribute data-defer-bootstrap can be added to the script tag.

Example:

<script type="text/javascript">
(function (a, b) { 
var loader = a.createElement('script');
loader.type = 'text/javascript';
loader.src = 'https://app-cdn.puzzel.com/public/js/pzl_loader.js';
loader.setAttribute('id', 'pzlModuleLoader');
loader.setAttribute('data-customer-id', b);
loader.setAttribute('data-defer-bootstrap', true);
a.body.append(loader);
})(document, '12345');
</script>

 

 When the Puzzel script is loaded like this, it will load and immediately just call the hook:
window.pzlOnLoad({ bootstrap })

The argument to this hook is an object containing the function bootstrap({ ... }) that can be called to launch the application. See description of pzlOnLoad() in the “Hooks”-section above for details about which bootstrap-options are currently supported.

Published

Last updated

0
0