Digioh Development Framework/API v2.5

Introduction for Developers        1

Custom JS Types        2

Custom JS SDLC        3

Page JS        5

Box JS execution pipeline        6

Form Submission Data Object: x        10

Interactive Helper Functions        11

Asynchronous Capabilities        13

Function Reference: api        14

Cookie Functions        14

URL and Domain Functions        15

Geo-Location Functions        16

Technology and Device Type Functions        17

Visitor Information Functions        18

Digioh Client Functions        19

Global Box Functions        20

DataLayer Manipulation Functions        21

Miscellaneous Functions        23

Function Reference: boxapi namespace        24

Box Metadata Functions        24

Box Page Functions        26

Form Submit Pipeline Functions        27

Dynamic Form Manipulation Functions        29

Box Behavioral Functions        32

Box HTML Structure        32

Introduction for Developers

Digioh allows the dynamic display of popups, forms, and general “calls to action” on your website, and is deployed via a JavaScript tag to your website(s). In technical terms, think of Digioh as a “post-processor” for your website user interface. Typically, the tag activates on each pageview after DOM ready, and then manipulates the HTML to power a variety of marketing use cases. The Digioh portal allows authorized users to control what the Digioh tag does on your site. The main Digioh concepts are:

Boxes: visual objects to display on your site. These can be lightbox, sidebar, or banner “overlays”, or “inlines” that embed into the page. Often but not necessarily, boxes contain forms that when submitted send data to your ESP or CRM via Digioh Integrations. Usually, boxes without forms are intended to redirect users somewhere else on your site.

Integrations: boxes with forms can have one or more configured Integrations that are called on form submission. Typically, this is to add an email address and any other form data to a list in your email platform, but Digioh supports a wide variety of integrations. Form submission data is sent from the browser to the Digioh server using a standard protocol, and the Integration transforms the data and relays it to the configured API endpoint. This also protects any sensitive API credentials since they are stored and used only on the Digioh server.

Box Conditions: these are the logical conditions under which specific boxes are displayed. In simple terms, after each page is loaded Digioh evaluates the conditions for each box and displays it if true. Box Conditions are part of a powerful rules engine used for targeting and personalization.

Custom JS: this is the Digioh development framework and focus of this document. With Digioh, much is possible with just Boxes, Integrations, Conditions, and existing Custom JS Apps, but Custom JS allows developers to customize even further and implement the “last mile” for advanced use-cases. With Custom JS, Digioh can interoperate with existing first or third party JavaScript and data on your site. This can be directly via JavaScript variables and functions, or anything in the DOM, cookies, local storage, or dataLayer, and even the results of API calls.

Additional Documentation is available here: https://help.digioh.com/section/custom-html-js/. Before starting on Custom JS implementation, we recommend you first look for an existing Custom JS App that either solves for your use case or can be modified to do so. View the list of apps from within Digioh, the the profile menu top right, then Custom JS (Apps).

Custom JS Types

Accessible through the Profile menu in the Digioh portal, there are different types of Custom JS:

Global JS: if you have multiple websites each with a separate Digioh account, Global JS is the common code that runs across all of your site on every pageview. Since your sites likely have a common CMS and code base, Global JS is ideal for implementing custom business logic common to all of your sites.

Page JS: this is a JavaScript snippet that runs once on every pageview. Page JS is ideal for processing data on your page to make it available to Box Conditions. For example, if Boxes should display only to logged in users, Page JS can do the work of detecting this and making a true/false flag available to Box Conditions.

Box JS: this is JavaScript that runs for specific boxes at different points in the box “lifecycle”, such as On Display, On Submit, On Close, etc. Common Box JS use case examples are: custom validation of form input data, tracking to analytics databases, and read/write of cookies, local storage, or JS variables to dynamically interoperate with your page.

In the Box JS editor, you can create an unlimited number of JS snippets for specific boxes.

You can configure the specific event trigger, and a comma separated list of box IDs to include or exclude. The box ID is from the ID column in the main box list page, see below.

An important difference between Page and Box JS is that Page JS runs in the context of the main window object, whereas Box JS runs in an iFrame. This means that if you want to access the main DOM from Box JS, you must reference via the window.parent object as follows:

window.parent.$

window.parent.location

window.parent.document

window.parent.xyz

In Box JS, the window object is the iFrame so if, for example, you want to use jQuery in the box, you can call $ directly, whereas if you want to use jQuery on the main window from Box JS, you use window.parent.$.

Custom JS SDLC

Digioh provides features to facilitate safe development and testing on live sites. In traditional software development, there are completely different stage or qa environments running separate software instances from top to bottom. However, with Digioh it is actually more complicated to work with different Digioh accounts for test and production because custom JS and boxes would have to be manually copied between accounts to “deploy” the changes to production, a process which itself can be prone to error.

Instead, for new custom JavaScript development, Digioh supports Box QA Mode. This allows you to use a single Digioh account for QA and production, deploying test code to your production site, but without actually exposing it to real users. You can go through the develop, deploy, test cycle of software development without the risk of breaking your live site. Simply make the changes to Custom JS and then hit “Publish QA”. To activate the QA version when visiting the client site, put ?boxqamode on any URL (or &boxqamode if it already has a query string). QA mode is not just for JS, you can also use it to test new boxes and rules:

Note that when you hit Publish (to production) or Publish QA, you are really publishing everything in the account: any and all changes to boxes, conditions, and Custom JS. If you have a work-in-progress Custom JS sitting in QA mode and you (or anyone else with access to the Digioh account) hit Publish, all of your JS immediately is pushed to production. This means that a routine cosmetic change and publishing of a box, say, could inadvertently cause the release of broken JS to a live site. For this reason, Digioh has a “Lock Publishing” feature that prevents publishing to production/live:

Before making any significant JS changes, first lock the account for publishing, then test your changes in QA mode, then unlock the account to publish live. This prevents someone else or even yourself accidentally publishing broken JS to a live site. If you find an account already in locked mode and need to make production changes, check the account history by clicking the “vcard” icon next to the account name top right, as shown below. While the lock action itself isn’t shown, whoever locked it will likely be the last person with activity in the log, and you can ask them if they are done before unlocking.

In general, do not leave Custom JS in a broken or experimental state for longer than absolutely necessary. Always try to leave the account in a safe state: boxes, rules, and JS.

Page JS

Digioh Custom JS runs in its own namespace, but you have access to the full DOM via provided variables. Page JS has access to the following:

  • window, document: this is the outermost context in which the main website is functioning. Unlike a directly deployed JS tag, you cannot directly access global window variables by name without using the window prefix.
  • jQuery, $: this is Digioh’s private jQuery context, which is distinct from the parent window’s jQuery context. It is attached to the main DOM, but we use our own private jQuery context to ensure cross-site consistency of jQuery versioning in our platform. It also prevents jQuery conflicts with the parent website. If you need to hook into the main window’s jQuery context for any particular reason (ie. event listeners), you can do so as follows: window.jQuery (or $).
  • api: use this to pass data back and forth between Page JS and Box Custom JS. You can use this object to define custom functions and/or variables to use account-wide, as you see fit. For example, if you define “api.myCustomVar = true;” in Page JS, then you will be able to use the value of that variable simply by referencing it the same way in Box JS. The api object also contains reference to our native functions SDK functionality, documented later.

Box JS execution pipeline

Box JS executes according to a sequential pipeline of events for which you can implement handlers.

The table below shows customizable events in sequence. Loosely speaking, boxes initialize their iFrame DOM and then display. After this, they can submit, redirect, or change pages any number of times. Finally, the close event is a terminator. We show the submission pipeline separately below, because it is more involved.

Box Event

Context

Special Variables

Return Options

Before DOM Ready

Box has just started initializing. You can prepare data here.

false: abort box display, cannot display again on same pageview

After DOM Ready

Box HTML created, ready for display

 

None (ignored)

Before Display

Immediately prior to display

 

false: abort box display, can display again on same pageview

After Display

Immediately after display

None (ignored)

Before Redirect

After button click and before processing redirect URL. See below for details of x.

x.element.text

x.element.url

x.element.action=url

false: abort redirect

or...

x: modify x.element.url and return x to dynamically alter the redirect.

After Redirect

After processing redirect URL, immediately before browser page change

x.element.text

x.element.url

x.element.action=url

None (ignored)

Before Download

After button click

x.element.text

x.element.file

x.element.action=file

None (ignored)

After Download

Immediately before issuing browser download

x.element.text

x.element.file

x.element.action=file

None (ignored)

Before Open Another Box

Immediately after button click

x.target_lightbox_guid

None (ignored). Note that this also triggers any Redirect and Close event JS.

After Open Another Box

Immediately before page change

x.target_lightbox_guid

None (ignored)

Before Change Pages

old_page still visible

x.old_page

x.new_page

x.name

false: abort page change

After Change Pages

new_page now visible

x.old_page

x.new_page

x.name

None (ignored)

Before Close

Immediately before close

None (ignored)

After Close

Immediately after close

None (ignored)

The box submission pipeline is shown below in strict sequence, including “native” events that occur behind the scenes and cannot be overridden. This process is invoked when any box form is submitted.


Box Event

Context

Variables in Scope

Return Options

Native: prepare form data

Populate x object from form data

n/a

n/a

Before Form Validation

Prior to default form data validation.

x.email

x.name

x.phone

x.custom_1

...

false: abort submission.

string: abort and show string as error message.

x: modified form data, bypasses validation in next step. Field list detailed below.

Native: validate form

Validation of form fields as configured in the Box Editor, e.g. required fields, email/phone syntax.

n/a

Skipped if Before Form Validation returned form data object x.

After Form Validation

After default form validation

x.email

x.name

x.phone

x.custom_1

...

false: abort submission.

string: abort and show string as error message.

x: modified form data. Field list detailed below.

Native: show loading

Display the loading “spinner”

n/a

n/a

Before Submit

Immediately before submission

x.email

x.phone

x.custom_1

...

false: abort submission

string: abort and show string as error message. Field list detailed below.

Native: send data

Inject a submission “pixel” into the DOM

n/a

n/a

After Submit

400 msecs after pixel inject

x.email

x.phone

x.custom_1

...

false: do not perform box “after submit” action. Field list detailed below.

Native: after submit action

Action configured at form level can be: close box, redirect to url, open another box, show thank you, show extra page.

n/a

This action is performed unless false is returned from prior step

If your goal is to modify form data before submission, use the form data object x, modify it, then return it. You can do this in either Before or After Form Validation event handlers, the difference being that returning x from Before Form Validation will prevent the default configured validation from occurring. So for example, any fields configured as required in the Box Editor will not actually be required. Best practice is to use After Form Validation, unless you have a specific reason to disable the default validation for email and phone fields, which cannot otherwise be disabled.

Before and After Submit events are well suited for doing your own custom tracking calls, or sending data to other systems. There may be situations where you want to disable and replace the default after submit action (which is usually to show the thank you page), you can do this by returning false from the After Submit handler, after calling changePages, for example.

Note about race conditions: if the box after submit action is configured as a redirect, you need to be careful of race conditions. Digioh form submissions are fast, but rely on the browser to request a “pixel” that carries the submission data. The same is true of any asynchronous operations you perform in Before or After Submit handlers, they could potentially be aborted by the browser redirecting away from the page. If this is a problem for you, change the after form submission action configured on the Box to “Do Nothing”, and perform the redirect from Box JS After Submit with a longer delay. For example:

//After Box Submit - custom redirect

your custom code ...

setTimeout(function() {

window.location.href = "http://www.yoursite.com/foo";

}, 2000);        //Extended wait

Form Submission Data Object: x

The data object x is essentially a parameter object for Custom JS snippets, and it takes different forms depending on where you are in the Box JS Execution Pipeline. Details below.

Before/After Redirect: x

  • x.element.text : the text of the button clicked to initiate the redirect
  • x.element.url : redirect URL, can be modified before redirect (then return x)

Before/After Download: x

  • x.element.text : the text of the button clicked to initiate the download
  • x.element.file : the URL path of the file (hosted on a Digioh server)

Before/After Change Pages: x

  • x.old_page : the name of the original page before change
  • x.new_page : the name of the transition to page after change
  • x.name : the name of the control (button) that caused the change

Supported page names are:

  • "main" : the main default page
  • "thx" : the thank you page
  • "ep1", "ep2", "ep3", "ep4" : extra pages 1 thru 4

Form Submission Pipeline: x

The x object can be modified and returned in Before/After Form Validation to dynamically alter the form data before submission.

  • x.first_name : string, as entered or parsed from full_name
  • x.last_name : string, as entered or parsed from full_name
  • x.full_name : string, as entered or concatenated first_name + ' ' + last_name
  • x.email : string, default validation for syntax, must have text @ domain
  • x.phone : string, default validation requires digits and optional dash (-) or space
  • x.opt_in: true or false checkbox field
  • x.custom_1 thru x.custom_50 : type and format depends on configured field type


Custom Field types and formats in x:

  • Text Box: string
  • Text Area: string
  • Dropdown: string that is the configured “Submitted Value” (vs. the “Display Value”)
  • Checkbox: boolean true or false
  • Radio: string that is configured “Submitted Value”
  • Hidden field: string
  • Date Picker: string, with date formatted as configured “Output Format”, default MM/dd/yyyy

Interactive Helper Functions

These are functions in the Digioh core designed to help with interactive debugging from the browser console.

DIGIOH_API.print()

Prints the output from your calls to console.log in Custom JS.

DIGIOH_API.printAll()

Print detailed logs from Digioh core and your Custom JS.

DIGIOH_API.printErrors()

Prints only errors generated from Custom JS or the Digioh core (e.g. exceptions).

DIGIOH_API.printConditionsOutput(boxShortId)

This prints the result of evaluated box conditions, which is helpful in diagnosing common “why is this box (not) showing” situations. Output is in JSON format, with the important property being rule_result true/false.

DIGIOH_API.get$()

This is the jQuery ($) object used by Digioh. If your site does not have jQuery natively deployed, you can use this for troubleshooting. Digioh uses a private namespace to avoid conflict with any existing jQuery installations. Note that this jQuery instance operates on the window/DOM in which Digioh is installed. $ is available from within Page JS, and also as the jQuery variable.

DIGIOH_API.reset()

Resets Digioh by clearing the Digioh dataLayer, Digioh specific cookies, localStorage, and sessionStorage. This is useful for testing when you need a “clean” session with respect to Digioh.

DIGIOH_API.resetAll()

This resets Digioh as above with reset(), and also clears all other cookies, localStorage, and sessionStorage.

Asynchronous Capabilities

By default, Digioh activates on the page DOM Ready event, and assumes that the DOM is stable and contains everything needed to evaluate box conditions and box JS. If your page has asynchronous JavaScript that may not be completed at DOM Ready, and you have Box JS or Box conditions that depend on the output, you will need to use the Digioh async callback feature. This is the Digioh activation sequence in order:

  1. On DOM Ready event, run Digioh Page JS
  2. Evaluate all box conditions and determine what to display, including any conditions that look for the presence or attributes of DOM elements. The results of this is what you see with the DIGIOH_API.printConditionsOutput(XXXXX) call.
  3. For all boxes to be displayed, preload/inject them into the DOM with display:none.
  4. For inline boxes attaching next to a specific element with jQuery (for example div#article_newsletter_inject) the target element must be present now or the box will not display.
  5. Flip preloaded boxes to display, potentially based on "dynamic" box conditions such as timer or onClick rules that might delay it.

Digioh supports asynchronous callbacks via Page JS. The most common use for this feature is to coordinate the activation of Digioh on your site with your own JavaScript, or another technology. So, for example, you may wish to delay Digioh activation until your advertising code has fully initialized, so that Custom JS can reliably interoperate with it. To do this, in Page JS you check if the external code has been initialized and if not, use one of the callback options below to tell Digioh to wait and then try again. Both options simply require you to return a special string.

//At top of Page JS

if(!window.adnetwork.isReady) return “async_retry”;

//Do something with window.adnetwork

When returning “async_retry”, Digioh will automatically try running Page JS repeatedly at 300 millisecond intervals. It will continue doing so until a value other than “async_retry” is returned (or nothing is returned). Alternatively:

//At top of Page JS

if(!window.adnetwork.isReady) return “async_callback”;

//Do something with window.adnetwork

Returning “async_callback” allows you to explicitly determine when to re-run the Page JS. When you are ready for Page JS to resume, call the following function from anywhere in your own (non-Digioh) JS:

window.DIGIOH_API.LIGHTBOX.customJsOnDocumentReadyCallback();

The above retry/callback methods will completely halt execution of the Digioh javascript code.  Therefore, until you tell custom JS to proceed, no conditions will be evaluated and no boxes will be displayed (including inline boxes). This is by design, so you have time to finalize your website state before Digioh proceeds.

In addition, if you have JS code on your site that uses Digioh output (e.g. custom rules or JS variables set by Page JS), you can call this function to check if Digioh has finished initializing:

window.DIGIOH_API.LIGHTBOX.isReady();

Function Reference: api

Digioh Custom JS has two namespaces with helper functions.

  1. api : the “global” namespace, containing functions callable from Page and Box JS
  2. boxapi : the box namespace, functions for Box JS only

This section documents the api namespace. All global api functions can be called from the Console in Browser Dev Tools, where DIGIOH_API is synonymous. For example:

DIGIOH_API.getCookie(‘myCookie’);

Cookie Functions

Digioh provides several helper functions for cookies, supporting Base64 and LZString encoding.

api.setCookie(name, value, {expirationDays}) → undefined

  • name: cookie name
  • value: string value of cookie, just the data, not in cookie “format”
  • {expirationDays}: optional expirationDays property, can use fractional days, default 1

api.setCookie('my_cookie', 'test', {expirationDays:30.4});  //Sets for *.domain.com

api.setCookie('my_cookie', 'test');        //Expires in 1 day

api.getCookie(name) → String

  • name: cookie name
  • returns: the cookie value or undefined if doesn’t exist

api.getCookie('my_cookie');

api.setCookieBase64(name, value, {expirationDays}) → undefined

  • name: cookie name
  • value: string value of cookie, to be encoded Base64

api.getCookieBase64(name) → String

  • name: cookie name
  • returns: string cookie data after Base64 decoding

api.setCookieLZString(name, value, {expirationDays}) → undefined

  • name: cookie name
  • value: string value of cookie, to be encoded with LZString
  • {expirationDays}: optional expirationDays property, can use fractional days, default 1

api.getCookieLZString(name) → String

  • name: cookie name
  • returns: string cookie data after LZString decoding

api.deleteCookie(name) → undefined

  • name: cookie to be deleted
  • action: deletes the cookie by setting expiration to date in the past

URL and Domain Functions

Using these helper functions guarantees consistency with the Digioh rules engine.

api.getUrlParameter(key) → String

  • key: name of parameter in the query string
  • returns: the value of the query string parameter, URLDecoded

var src = api.getUrlParameter('utm_source');

api.hideUrlParameter(key) → undefined

  • key: name of parameter in the query string
  • action: removes the named parameter from the query string without reloading the page. This is good practice for IDs and anything that might be considered “tracking” data by an observant user. While we do not recommend passing email addresses in the query string, if you must do this then we recommend removing it in this way.

api.getCurrentUrl() → String

  • returns: the current page URL, not URLDecoded

api.getHostname() → String

  • returns: the current page hostname/domain name

api.getPagePath() → String

  • returns: the current page path, including leading /, not URLDecoded

api.getQueryString() → String

  • returns: the current page query string, including leading ?, not URLDecoded

api.getUrlHash() → String

  • returns: the anchor portion of the URL, including leading #, not URLDecoded

api.getLandingPageUrl() → String

  • returns: the URL of the first pageview in this session

api.getReferrer() → String

  • returns: the referrer for this pageview (not original session referrer)

api.getLandingPageReferrer() → String

  • returns: the original referrer for this session

api.getClientIpAddress() → String

  • returns: IP address of the client (Internet facing, as determined by our server)

api.getClientId() → String

  • returns: Unique ID assigned to this client (aka. device)

Geo-Location Functions

Digioh performs real-time geo-location, these functions return data consistent with the Digioh rules engine and form submissions. That is, this same data is used for targeting conditions and sent to Integrations.

api.getClientContinentCode() → String

  • returns: two letter continent code, NA, EU, AF, AS, SA.

api.getClientContinentName() → String

  • returns: full continent name

api.isClientInEU() → Boolean

  • returns: true if client is in European Union country (e.g. for GDPR)

api.getClientCountryCode() → String

api.getClientCountryName() → String

  • returns: full country name

api.getClientRegionOrStateName() → String

  • returns: full state name, e.g. “Texas”

api.getClientRegionOrStateCode() → String

  • returns: state abbreviation, e.g. “TX”

api.getClientCity() → String

  • returns: full city name, e.g. “Austin”

api.getClientPostalCode() → String

  • returns: postal or zip code, e.g. 78759

api.getClientTimeZone() → String

  • returns: client time zone

api.getLongitude() → String

  • returns: estimated longitude

api.getLatitude() → String

  • returns: estimated latitude

Technology and Device Type Functions

These functions are consistent with box conditions and form submission data.

api.getOperatingSystem() → String

  • returns: “Apple”, “Windows”, “Android”

api.getBrowserType() → String

  • returns: “Chrome”, “Safari”, “Edge”, “Firefox”

api.getBrowserVersion() → Number

  • returns: browser version as a number

api.getDeviceType() → String

  • returns: “Desktop”, “Tablet”, “Mobile”

api.isMobile() → Boolean

  • returns: true if the device is a phone

api.isTablet() → Boolean

  • returns: true if the device is a tablet

api.isDesktop() → Boolean

  • returns: true if the device is desktop or laptop PC

api.isAndroid() → Boolean

  • returns: true if the device is Android OS

api.isIOS() → Boolean

  • returns: true if the device is Apple iOS

Visitor Information Functions

api.isNewSession() → Boolean

  • returns: true if this pageview is the first of this session (visit)

api.isNewVisitor() → Boolean

  • returns: true if this session is the first visit by user (i.e. Google Analytics New User)

api.getPagesNavigatedAllTime() → [Array of String]

  • returns: all URLs visited by this user, in sequence

api.getDaysSinceLastPageview() → Number

  • returns: if isNewSession(), this is the number of days since last visit

api.getTrafficSource() → String

  • returns: the high level source for this visit, e.g. “Direct”, “Organic Search”

api.getSearchEngineSource() → String

  • returns: the referring search engine, e.g. “Google”, empty string if unknown

api.getTotalPageViews() → Number

  • returns: the number of pageviews for this user across all sessions

api.getTotalSessions() → Number

  • returns: number of sessions for this user

api.getMVTestGroups() → [String]

  • returns: array of unique multivariate test bucket IDs of the form testId-boxId. Use this if you need to track which test bucket a user was assigned to if you are analyzing Digioh test results in another analytics platform.

Digioh Client Functions

These functions may be useful in Global JS, if you need custom logic specific to certain accounts. These correspond to the “User ID” and “GUID” visible at the bottom of the Profile Menu, top right, in the Digioh UI. They can also be called from the browser console, as an easy way to determine which Digioh account instance is running on a website.

api.getAccountId() → String

  • returns: the Digioh account (“user”) ID, guaranteed unique within your linked accounts. Corresponds to [VENDOR_ID] merge tag.

DIGIOH_API.getAccountID();        //Alternative call from browser console

api.getAccountGuid() → String

  • returns: the “GUID”, guaranteed unique across all Digioh accounts

Global Box Functions

These functions relate to boxes but exist in the “global” context and so can be called from both Page JS and Box JS.

api.getBoxGUID(boxIDorGUID) → String

  • returns: Digioh globally unique ID for this box. In some cases, such as interacting with Digioh Box HTML, you need the Box GUID. This is a 36 character string containing 5 groups of digits and lowercase letters separated by hyphens, e.g 6f90fcbb-1399-4c86-b88b-0a7b6ac78e27.

api.getBoxId(boxIDorGUID) → String

  • returns: “short” box ID unique within your account(s). Many functions support both the short numeric ID and GUID form of ID, but this and getBoxGUID allow you to switch between them.

api.closeBox(boxId) → undefined

  • boxId: the short id or GUID of the box to close
  • action: immediately closes the box, if open. Unlike closeAllBoxes, this will close inlines.

api.openBox(boxId, {evalConditions:boolean}) → undefined

  • boxId: the short id or GUID of the box to display
  • evalConditions: set to true to open the box only if conditions and master rules pass (default false)
  • action: immediately force open the box. Note that inline boxes must be able to successfully attach according to configured Widget > Position Using method.

api.closeAllBoxes() → undefined

  • action: immediately closes all open boxes on the page, honoring their configured close animation. Note that this does not affect inline boxes.

api.getBoxType(boxId) → String

  • returns: “lightbox”, “sidebar”, “inline”, or “banner”

api.addBoxIntegration(boxId, integrationId) → undefined

  • boxId: the short id or GUID of the box to augment
  • integrationId: the integration ID, from the Integrations page in the Digioh UI
  • action: dynamically add the Integration to this box. On submission, form data will be sent to this Integration, instead of any Integrations already configured via the UI (overrides).

if(!api.isClientInEU()) {

        api.addBoxIntegration(52361, 72384);        //Store PII if not in EU

}

api.removeBoxIntegration(boxId, integrationId) → undefined

  • boxId: the short id or GUID of the box to alter
  • integrationId: the integration ID, from the Integrations page in the Digioh UI
  • action: dynamically remove the integration, if present. Cannot be used to remove Integrations already configured via the UI, only those previously added dynamically.

api.resetBoxIntegrations(boxId) → undefined

  • boxId: the short id or GUID of the box to augment
  • action: remove all dynamically added integrations. Retains UI configured integrations.

api.getFormData(boxId) → Object

  • returns: object with all dataLayer properties, but populated for only the current box-page-form submission context for boxId. This function will return an object only when called from After Form Validation, Before Form Submission, and After Form Submission, and will return null otherwise. This function is useful if you want to process only incremental data input being added to the dataLayer.

DataLayer Manipulation Functions

The Digioh dataLayer is an object stored in browser local storage that contains all previous form submission data for that user (actually, device/browser combination). When submitting a form, all dataLayer data is sent to Digioh and then on to any configured Integrations. We provide functions that allow you to directly read, write, and delete data from the dataLayer. The dataLayer object is structured as follows:

{

  "email": "test@digioh.com",                //"Top level" data layer

  "first_name": "sdfsd",

  "last_name": "sdfsdf",

  "name": "sdfsd sdfsdf",

  "phone

  "opt_in": "true",

  "custom_6": "false",

  "custom_3": "1",

  "165909": {                                //Box level dataLayer, key is boxapi.getId()

    "custom_1": "aaa",

    "main_custom_1": "aaa",                //Page specific data fields

    "ep2_custom_22": "hello from ep2_custom_22!",

    "ep39_email": "sldfjs@zzzzzxxxx.com",

    "ep39_custom_1": "ep39cust1",

    "ep39_custom_17": "ep39cust17"

  }

}

Essentially, there is a top level dataLayer, which is written to by all boxes, and each box also retains its own version of the dataLayer. In addition, page specific field data is written at the box level. When a box page form submits, it will write data for all enabled fields to the top level, the box level, and to the box-page specific dataLayer properties. Generally, we recommend using the top level dataLayer where possible, and box and box-page level dataLayer only when you need to partition the dataLayer by box. You have 50 custom fields available, to avoid unnecessary complexity we recommend “assigning” a unique purpose to each custom field, and use custom fields for only that purpose across all boxes. For example, if you can decide that custom_2 is always the date of birth, it will make Custom JS and Integrations much easier to create and maintain.

For the functions below, if the optional boxId param is provided, it will only operate on the dataLayer for that boxId, and not the top-level or for other boxes. Typically, you should omit the boxId and operate at the top level unless you have special data requirements unique to a particular box.

api.getDataLayerValue(key, boxId) → String

  • key: lookup key, e.g. “custom_1”, “name”, etc
  • boxId: optional, if provided will fetch key from box-specific dataLayer
  • returns: value of key in the dataLayer

api.setDataLayerValue(key, val, boxId) → undefined

  • key: lookup key, e.g. “custom_1”, “name”, etc
  • boxId: optional, if provided will set key for box-specific dataLayer only
  • action: sets the value of key to val in the dataLayer

api.removeDataLayerValue(key, boxId) → undefined

  • key: lookup key, e.g. “custom_1”, “name”, etc
  • boxId: optional, if provided will remove key for box-specific dataLayer only
  • action: removes the key from dataLayer

api.getDataLayer(boxId) → Object

  • boxId: optional, return either the entire dataLayer, or box specific dataLayer
  • returns: the dataLayer object. Note that modifications to this object will not be written back to localStorage. Use setDataLayer to write the object.

api.setDataLayer(obj, boxId) → undefined

  • obj: an object in dataLayer format, as shown in the example above
  • boxId: optional, set only a box specific dataLayer
  • action: merges obj into the dataLayer, traversing property by property. Note that this will overwrite dataLayer values with the same key but not remove existing keys that are missing in the new dataLayer object.

api.clearDataLayer(boxId) → undefined

  • boxId: optional, if provided will delete only the dataLayer for a specific box.
  • action: deletes entire dataLayer from localStorage. Use this to entirely reset the dataLayer for a user, as if they had never submitted a form.

Miscellaneous Functions

api.isPreview() → Boolean

  • returns: true if this is a box Preview, useful for suppressing functionality, such as tracking to analytics systems, for example.

api.debugger(optionalPurpose) → undefined

  • optionalPurpose: string, if provided will show a confirmation modal to debug or not.
  • action: activate JavaScript debugger if in preview or boxqamode. Use of “debugger;” directly in Custom JS is strongly discouraged. When entering debug, simply step out of this function and you will be at the intended breakpoint.

api.writeCustomFlag(flagId) → undefined

  • flagId: the name of the flag, must be an allowed HTML element id (- _ is OK, no spaces)
  • action: writes invisible div to DOM with id=flagId, for targeting with HTML Exists in box conditions. Note that writeCustomFlag only makes sense in Page JS, because this is the only JS that is guaranteed to run before the Digioh rules engine.

api.isValidEmail(email) → Boolean

  • email: email address to be validated
  • returns: true if email is syntactically valid. This uses the same validator as the Digioh default validation for forms, so is ideal when you want to replace default validation in Box JS Before Form Validation, but still validate the email.

api.reload({ … flags …} ) → undefined

  • flags: optional object with optional boolean properties to control tracking:
  • sendPvEvent: default true, send a pageview event to Digioh Analytics
  • updatePvVars: default true, increment browser pageview count for conditions
  • action: close all boxes and reinitialize the Digioh rules engine. Since this is designed for use with Single Page Apps, by default Digioh will treat this reload as if it were a new page view, incrementing internal counts for the user.

api.enableReloadOnUrlChange() → undefined

  • action: dynamically configure Digioh to automatically call reloadDigioh on URL changes. This is useful for Single Page Applications and infinite scroll. Typically you would call this once in Page JS.

api.isReady() → Boolean

  • returns: true if Digioh has completely initialized (started and box conditions evaluated)

api.logEvent({ … data … }, {exp, group}) → undefined

  • data: arbitrary object with properties to log, e.g. { step: 2, error: "error detail" }
  • {exp:'02/13/2021'}: optional expiration date for the data, MM/DD/YYYY format. Defaults to 72 hours in the future.
  • {group:'gname'}: optional name for the data set, roughly analogous to GA category. Defaults to 'default'.  Expiration date is based on the group.
  • action: this logs an event to the Digioh database, where data can be retrieved from Analytics > Export Logs, organized by data group. Data stored here will eventually expire, so this is not suitable for long term analytics purposes. It is intended primarily for collecting debugging information from a live environment with real users. If called from a Box JS context, most box metadata will automatically be logged by default.

var data = {event_type : 'display'};

var options = {group : 'test1', exp : '01/31/2021'};

api.logEvent(data, options);

Function Reference: boxapi namespace

This section documents the boxapi namespace, functions that are specific only to boxes and not available in Page JS. You can access boxapi from browser Dev Tools if you are in the Digioh Box’s iFrame context (i.e. Right Click > Inspect the Digioh box).

Box Metadata Functions

boxapi.getName() → String

  • return: the name of the box as shown on the Box list in Digioh

boxapi.getId() → String

  • return: the box “short” ID as shown on the Box list in Digioh

boxapi.getBoxType() → undefined

  • returns: "lightbox", "sidebar", "inline", or "banner"

boxapi.getBoxFrameWrapper() → object (jQuery Element)

  • returns: a jQuery object containing the box element, in the context of the main (parent) window. This is ideal for interacting with the box via jQuery, e.g. moving or hiding it, or scrolling relative to the box.

boxapi.getBoxJQuery() → object (jQuery)

  • returns: jQuery for interacting with box internals. While you can access $ directly from Box JS, this is helpful if you are implementing reusable utility functions in Page JS where you are passing boxapi for context.

api.getAccountMetadata(key) → String or [{k:..., v:...}, …]

  • key: account-level metadata key, as configured in Admin > Account Metadata
  • returns: the configured metadata value for key. Account level metadata is ideal for global configuration parameters that apply to all boxes.

api.getWidgetMetadata(boxId, key) → String

  • boxId: short id or GUID
  • key: box level metadata key, as configured in Box Editor > Widget
  • returns: the configured metadata value for key. Box level metadata is ideal for allowing box level configuration of Custom JS behavior.

boxapi.getPageMetadata(pageName, key) → String

  • pageName: "main", "thx", "ep1", "ep2", "ep3", "ep4", ...
  • key: box page level metadata key, as configured in Box Editor > Page > Layout
  • returns: the configured metadata value for key. Page level metadata is useful for configuring page level behavior of Custom JS, e.g. for Before/After Change Pages.

boxapi.getFieldMetadata(pageName, fieldName, key) → String

  • pageName: "main", "thx", "ep1", "ep2", "ep3", "ep4", …
  • fieldName: "email", "phone", "opt_in", "custom7", …
  • key: form field-level metadata key, as configured in Box Editor > Page > Form > Field.
  • returns: the configured metadata value for key. This metadata is useful for configuring property names when building JSON for dynamic integrations, or field specific Custom JS behavior.

boxapi.getElementMetadata(pageName, elementName, key) → String

  • pageName: "main", "thx", "ep1", "ep2", "ep3", "ep4", …
  • elementName: "button1", "text7", "html2", "image4", …
  • key: page element-level metadata key, as configured in Box Editor > Page > Element
  • returns: the configured metadata value for key.

//Find all metdata with key mdKey, optionalLevel = undefined, account, box, page, element, field

api.findMetadata(mdKey, optionalLevel) -> [Object]

[{

    mdLevel : 'field',

    mdKey : 'state_auto',

    mdVal : 'name',

    elementType : null,                 //null except for elements (text, button, image, html)

    fieldType : 'select',               //null except for fields

    xName : 'custom_1',                 //null except for fields

    xNameSpecific : 'ep1custom_1',      //null except for fields

    dlName : 'custom_1',                //null except for fields

    dlNameSpecific : 'ep1_custom_1',    //null except for fields

    boxSettings : {...},                //undocumented, null for account-level metadata

    pageName : 'ep1',                   //null for account-level, box-level

    domId : '#ep1_form_input_custom_1'  //null for account-level

}]

Box Page Functions

Transitions between box pages occur automatically based on the box configuration, e.g. after form submit, or button actions. You can also manage page transitions in Box JS.

boxapi.showPage(pageName) → undefined

  • pageName: "main", "thx", "ep1", "ep2", "ep3", "ep4", ...
  • action: immediately transition from the current page. A common use case would be to dynamically change the page After Submit, based on form input data in x or client data. This will also run the Custom JS (Boxes) events for “Before Change Pages” and “After Change Pages”.

//In Box JS After Submit

if(api.isIOS()) { boxapi.showPage("ep1"); } //page with apple store download link

else { boxapi.showPage("ep2"); } //android store download link

return false;        //prevent default action (best practice is configure “Do Nothing”)

boxapi.showMainPage() → undefined

  • action: same as boxapi.showPage("main")

boxapi.showThankYouPage() → undefined

  • action: same as boxapi.showPage("thx")

boxapi.showExtraPage(pageNumber) → undefined

  • action: same as boxapi.showPage("ep" + pageNumber)

boxapi.isMainPage() -> Boolean

  • returns: true if page = "main"

boxapi.isThankYouPage() -> Boolean

  • returns: true if page = "thx"

boxapi.isExtraPage(pageNumber) -> Boolean

  • returns: true if page = "ep"+pageNumber

boxapi.getPageName() -> String

  • returns: the current page; “main”, “thx”, “ep1”, “ep2”, ...

boxapi.getPageTitle() -> String

  • returns: the free form page title if configured, verbose default if not e.g. “Main Page”

boxapi.getPageJQuery() -> Object (jQuery)

  • returns: jQuery object for current page, useful for calling find

Form Submit Pipeline Functions

These functions support common use cases for customizing the form validation and submission process.

boxapi.processSubmit({...}) → undefined

  • {pageName:"main"}: optional parameter overriding default of form on current page
  • {hideLoadingSpinner: false}: optional, by default will call showLoading()
  • {useSubmitLock: true}: optional, but we recommend you set this to false for programmatic submissions since submission in rapid sequence may be blocked otherwise. Submit lock is designed to prevent “double click” submissions.
  • action: dynamically start the form submission pipeline. Common use cases for this are when you want to automatically submit or resubmit forms after a certain amount of time, or if you need to check an external API to validate data, in which case you would abort submission (return false) and call processSubmit as an asynchronous callback. Best practice is to define a function in Page JS, in the api object, and call that from Box JS.

//Example submission after asynchronous external API call, in After Form Validation

var callback = function(status) {

if(status=='ok') {

        //Put a flag in api object

        api.doneAPI = true;

        //Restart pipeline for final submit

boxapi.processSubmit({useSubmitLock: false});

} else { boxapi.showError("API said no"); }

};

if(!api.doneAPI) {

        //First time through pipeline, start async API call

api.checkDuplicateEmail(x.email, callback);        //Your custom API code

return false;                                                //Don’t submit until callback

}

boxapi.getFormData() → Object

  • returns: object with all dataLayer properties, but populated for only the current form submission context. This function will return an object only when called from After Form Validation, Before Form Submission, and After Form Submission, and will return null otherwise. This function is useful if you want to process only incremental data input being added to the dataLayer.

boxapi.showLoading() → undefined

  • action: show the loading spinner. Most common use for this is to show it while waiting for an asynchronous API callback.

boxapi.hideLoading() → undefined

  • action: hide the loading spinner. Typically for an asynchronous callback.

boxapi.showError(errorMsg) → undefined

  • errorMsg: text of the error message
  • action: shows the error message in the Digioh standard error format (pink box). Typically you would use this associated with your own custom form data validation in Box JS After Form Validation.

boxapi.showInlineError(errorMsg, fieldName, {pageName}) → undefined

  • errorMsg: text of the error message
  • fieldName: "email", "phone", "custom1", "custom2", etc (full list below).
  • {pageName:"main"}: defaults to the current page, you can override with "main", "thx", "ep1", "ep2", "ep3", "ep4"
  • action: shows an inline error message next to the field. If your form is configured (Form > Inputs > Error Message Position) to show errors inline, you should use this function for consistency in displaying error messages. The showError function displays errors in the standard format (pink box).

boxapi.addBoxIntegration(integrationId) → undefined

  • integrationId: integration “short” ID
  • action: this is the box level equivalent of api.addBoxIntegration(boxId, integrationId), typically you would use this in After Form Validation or Before Submit to change how or where data is sent based on form input data in x.

boxapi.removeBoxIntegration(integrationId) → undefined

  • integrationId: integration “short” ID
  • action: this is the box level equivalent of api.removeBoxIntegration(boxId, integrationId), typically you would use this in After Form Validation or Before Submit to change how or where data is sent based on form input data in x.

boxapi.resetBoxIntegrations() → undefined

boxapi.trackManualRedirect() → undefined

  • action: track a redirect conversion in Digioh analytics, use this if you are programmatically redirecting to another page. This is important for reporting, and determining A/B test winners.

Dynamic Form Manipulation Functions

These functions allow you to read and write form data dynamically, outside of the form submission pipeline, e.g. to populate data before the box is displayed, or change forms based on user interactions. All of these functions accept a fieldName parameters with valid values as follows:

  • "first_name"
  • "last_name"
  • "full_name"
  • "name" - this is a smart field that maps to fields based on how name is configured
  • "email"
  • "phone"
  • "opt_in"
  • "custom1" thru "custom50" (note these have underscore in x: x.custom_1)

boxapi.setFormFieldValue(fieldName, value, {pageName}) → undefined

  • fieldName: valid fieldName values defined above, they are similar to property names on the x object (without underscores) and in the Box HTML structure.
  • value: for text fields this is a string, for date fields this is a string in MM/dd/yyyy format (regardless of the Box configured format), Boolean true or false for checkboxes. For radio buttons, set the option-to-be-selected by the using “Submitted Value” key for value.
  • action: dynamically set a field value. A common use case is to prepopulate a form (via Box JS After DOM Ready) based on custom logic or data from cookies or local storage.

//Dynamically change radio button (custom_3 here) from Option 1 to Option 2

boxapi.setFormFieldValue('custom_3', 'opt2');

//Dynamically check standard opt in checkbox field

boxapi.setFormFieldValue('opt_in', true);

//Dynamically set a date field

boxapi.setFormFieldValue('custom_2', '01/10/2020');

boxapi.getFormFieldValue(fieldName, {pageName}) → String

  • fieldName: valid fieldName values defined above.
  • {pageName:"main"}: defaults to current page, can be overridden here.
  • returns: current value from the form html, can be used outside of the submit pipeline where the x object is unavailable. See setFormFieldValue above for formats.

boxapi.addDropdownOption(fieldName, submitVal, displayVal, {pageName}) → undefined

  • fieldName: valid fieldName values defined above, the field must be of type dropdown.
  • submitVal: the new dropdown data value that gets submitted (if selected)
  • displayVal: the new dropdown user visible value, paired with submitValue
  • {pageName:"main"}: optionally specify the page, defaults to CURRENT_PAGE
  • action: dynamically add to the list

boxapi.removeDropdownOption(fieldName, submitVal, {pageName}) → undefined

  • fieldName: valid fieldName values defined above, the field must be of type dropdown.
  • submitVal: the new dropdown data value that gets submitted (if selected)
  • {pageName:"main"}: optional, defaults to CURRENT_PAGE, can be overridden here.
  • action: this is the inverse of addDropdownOption

boxapi.removeAllDropdownOptions(fieldName, {pageName}) → undefined

  • fieldName: valid fieldName values defined above, the field must be of type dropdown.
  • {pageName:"main"}: optional, defaults to current page, can be overridden here.
  • action: clears all options if you want to rebuild the entire dropdown

boxapi.hideFormField(fieldName, {pageName}) → undefined

  • fieldName: valid fieldName values defined above
  • {pageName:"main"}: defaults to current page, can be overridden here.
  • action: dynamically hide a form field. A typical use case would be to hide a field determined to be inapplicable based on cookies or local storage, or based on other form field input (e.g. hiding a “State” field if the selected country is not USA). If a form field is hidden dynamically, and it is configured as “required” in the Box Editor, this will no longer be enforced.

boxapi.showFormField(fieldName, {pageName}) → undefined

  • fieldName: valid fieldName values defined above
  • {pageName:"main"}: defaults to current page, can be overridden here.
  • action: this is the inverse of hideFormField. All enabled form fields are shown by default. Note that it is not valid to show a field that is configured as Display Mode OFF in the Digioh UI. If your intent is to show fields only under certain conditions, set all possible fields to Display Mode ON in the Digioh UI, then dynamically hide the fields that are not applicable.

Box Behavioral Functions

boxapi.closeBox() → undefined

  • action: immediately close the box. Unlike closeAllBoxes, this will close inlines. A typical use case for this would be to close the box prior to calling api.openBox(otherBoxId)

boxapi.hideElement(elementName, {pageName}) → undefined

  • elementName: button1, text1, etc
  • {pageName}: optional page override, defaults to current page.   "main", "thx", "ep1", "ep2", "ep3", "ep4", …
  • action: hide the box element from view; can call at any point, but if you call from After DOM Ready, users will never see the element.

boxapi.showElement(elementName, {pageName}) → undefined

  • elementName: button1, text1, etc
  • {pageName}: optional page override, defaults to current page.   "main", "thx", "ep1", "ep2", "ep3", "ep4", …
  • action: show a previously hidden box element

boxapi.reloadWebPage({delayMsecs}) → undefined

  • {delayMsecs:Number}: optional delay before reload. It’s important to add a delay if you are calling this from After Submit, to allow time for the browser to process the submission data, best practice is 500 msecs.

boxapi.disableScroll() → undefined

  • action: disables scrolling of the main window (behind the box). Use this with caution, your web page will be unresponsive until calling boxapi.enableScroll(), even if the box is closed.

boxapi.enableScroll() → undefined

  • action: enable scrolling, pairs with disableScroll above.

boxapi.resetBox() → undefined

  • action: remove all data from interactions with this box. Use this to completely reset a box, e.g. dataLayer and selected buttons.

boxapi.resetPage(pageName) → undefined

  • action: remove all data from interactions with the given page, e.g. dataLayer and selected buttons set by that page.

Box HTML Structure

Digioh boxes are deployed inside an iFrame, and all boxes have the same standard HTML structure that corresponds to box visual elements in the Editor: form, text blocks, buttons, images, and custom HTML.

Each box page has its own layout div, that groups the visual elements for each page, with standard naming. Every element in the box has a unique id, making it easy to use jQuery from within Box Custom JS to manipulate the HTML and CSS. Common use cases are to hide and show box elements, customize styles, and preset checkboxes or radio buttons dynamically:

//In Box JS After DOM Ready

$("#button1").hide();

$("#button2").css("background-color", "yellow");

$("#thxbutton1").css("font-size": "200%");

$("#ep1_form_input_custom1").prop("checked", true);

All box HTML is available at time of After DOM Ready, with the main page (layout) visible. Box pages are transitioned by hiding the current page layout div, and showing the new page. This means you can customize any page, even if it is not currently showing.

Another common use case is when you want to add custom logic for box interactions not supported by the box event model. Digioh provides built in hooks for box actions: display, redirects, submissions, page changes, download, open another box, and close. Digioh does not directly support custom handlers for button clicks, but you can easily implement your own handler as follows:

//In Box JS After DOM Ready

$("#button1").click(function() {

        //Do something before the configured button action takes place

});

When working to manipulate the Box HTML, you can easily test and prototype using browser Dev Tools Console. This saves time by avoiding a full edit, save, publish, display, test cycle while you tune your CSS. Just select the lightbox-iframe as the JavaScript context: