Using the Embed API

First learn to use the Embed API, then see the various arguments and calls that can customize how the configurator looks and behaves.

Embedding Options

  • We suggest JavaScript.
    The Embed API can be written in both HTML and JavaScript.  You can choose to use either, since they offer identical features. The JavaScript version is especially useful for fully integrating another software application with Epicor CPQ in a reusable manner. Most webmasters prefer the flexibility of the JavaScript version, so examples on this page are in JavaScript, instead of HTML.
  • We suggest the configurator.
    You can embed a configurator along with its viewer's 3D scene, or you can embed a scene all by itself.  Since most scenes rely on a configurator to work, embedding a scene independently is an edge case.  The examples here will show how to embed a configurator.

Quick Start

The easiest way to get started is to use the embed generator in the configurator admin.  

  1. In the admin tool, click Products > Configurators and open the configurator you wish to embed. 
  2. Click the Embed button in the toolbar to launch the embed helper.
  3. In the embed helper pop-up that appears, select the options you want for your embed, and copy/paste the generated HTML code into your web page.  That's it!  

Here is an example of a simple JavaScript embed:

Basic Javascript Embed

<script src="https://subdomain.kbmax.com/embed.min.js"></script>

<script>
     document.addEventListener("DOMContentLoaded", function() {
     //start the embed
        var config = new kbmax.ConfiguratorEmbed({
            elementId: "theViewer",
            configuratorId: 317,
            showHeader: false,
            showDrawer: true,
            showMove: false,
            bindToFormSelector: "",
            loadStyle: "none",
        });
     });
</script>

<div id="theViewer" style="height: 800px;"></div>

The embed code consists of two scripts and a div. 

  • Line 1: The first script is a reference to the embed library.  Replace the word 'subdomain' with your company subdomain, including the environment.  This script should be added at the end of the body tag of your page. The script reference also needs to be added after any HTML inputs you have on your web page that you would like to bind to the configurator.
  • Lines 3-16: The second script initializes the configurator you would like to embed, and defines how it will behave.  This script you can either insert into your page directly in a script tag, or refer to in a referenced script file.
  • Line 18: The div which will contain the configurator.  This can be placed where appropriate on the web page.

Instatiating the Embedded Configurator

The embed helper pop-up gives you working code to start your embed, but you will probably adjust that code by adding arguments to the embed code and, optionally, adding JavaScript to your web page to add more sophisticated behaviors as you need them.

Most of your configuration work is in the second script.  Here is a full example, showing parameters explained below:

Setting Embed Parameters

//wait until the document loads before using the epicor cpq embed api
document.addEventListener("DOMContentLoaded", function() {

    //start the embed
    var config = new kbmax.ConfiguratorEmbed({
        elementId: "theViewer",
        configuratorId: 4004,
        showFields: true,
        showHeader: false,
        showConfigHeader: true,
        showMove: false,
        bindToFormSelector: ""    });

    //to interact with the configurator, you primarily just set field values. 
    //The rules take over, using those values in the configurator as though 
    //a user selected them.
    //To set field values, you can use the setFields command, 
    //which takes a JavaScript object where each
    //property is a field name, and the property value is the 
    //value you want to set for the field
    config.setFields({ "Field1": "Hello 3D!", "Field2": 15 });

    //you can run an action using the following...
    config.runAction("actionName");

    //see the ConfiguratorEmbed calls listed in our Help for more.
});


Let's break down the script above to understand it.  First, you need to create a new instance of the ConfiguratorEmbed class. The constructor of the ConfiguratorEmbed class accepts an arguments object built from any of the embed arguments shown below.

a) New web page embed, displaying a new configured product (most common use)
You can add as many arguments as you need to instantiate the configurator, and define how it is embedded in the page. Here's a simple example.

var config = new kbmax.ConfiguratorEmbed({
	elementId: "theViewer",
	configuratorId: 4004,
	showFields: true,
	showHeader: false,
	showConfigHeader: true,
	showMove: false,
	bindToFormSelector: ""});


b) Re-using an existing embed
If you want to get a reference to an already existing embed, that was created either by the HTML version or earlier in the JavaScript, you only need to provide the elementSelector (or elementId) argument.

var existingEmbed = new kbmax.ConfiguratorEmbed({elementId: "theViewer"});

c) New embed, displaying an existing configured product

Sometimes you may want the embed to use an existing configured product that was saved sometime before, and already exists inside a quote. In such cases, you can pass a configuredProductId property into the constructor arguments, which corresponds to the quoteProductId in the quote.

Example: displaying an existing configured product
var config = new kbmax.ConfiguratorEmbed({
	elementId: "viewer",
	configuredProductId: 42,
	showFields: true,
	showHeader: false,
	showConfigHeader: true,
	showMove: false,
	bindToFormSelector: ""});

Here, we are launching the configuredProduct with ID of 42. That configured product knows which configurator was used to create it, so it loads the correct configurator (along with all the selections made for product 42).

For your webserver to know this ConfiguredProductID, it could either refer to its own tables, or use our REST API to gather the correct information.

JavaScript Embed Arguments

JavaScript Argument Datatype Required? Notes
configuratorId integer

Required

(Set only one of these three arguments)

To embed a new configurator which your user can save as a configuredProduct. This is the most common use.

Provide the id of the configurator you wish to embed.  The ID of your configurator in Epicor CPQ is easy to find: it is displayed next to the configurator name in the admin tools listing of configurators

sceneId integer

To display a stand-alone scene instead of a configurator.

Use this with the id of the scene you wish to embed.  This use is less common.

configuredProductId integer To embed an existing configuredProduct someone has already created and saved, instead of starting with a new configuredProduct, use this with the Id of the configured product.  This use is less common.
elementSelector text Required

(Set only one of these two arguments)
Should contain a CSS style selector that identifies the element you want to place the viewer in. For example, to place the viewer in a div with an id of 'viewer', then use elementSelector:"#viewer"
elementId text Can be used instead of elementSelector to specify the id of the HTML element you want to place the viewer in. For example, to place the viewer in a div with an id of 'viewer', then use elementId:"viewer"
kbmaxUrl text Optional The embed script will attempt to load the configurator from the same base Epicor CPQ url that was used to load the embed script.  However, if you need to override this behavior, you can specify the kbmaxUrl explicitly.  For example:   kbmaxUrl: "https://mycompany.kbmax.com"
autoSsoLogin boolean Optional If set to true, the embed will immediately take the user to log in via Azure AD. This option is only used if the company has SSO enabled and is fully set up.
bare boolean Optional Only valid for scene embeds. Set to true to have a highly performant scene embed that does not have any ui except the scene itself. Note that field controls, hotspots, etc. are not included in bare embeds.
bindToForm
Optional

Bind to form is a powerful feature for integrating your app or website with the embed. If you have HTML inputs (like text inputs, select, checkbox, etc.) in the page where your config is embedded, Epicor CPQ can watch these inputs for changes by the user. As the user interacts with your inputs, these values will automatically flow into Epicor CPQ, be matched up with fields in the configurator/scene, and the scene re-rendered. And all of this can happen without you writing any JavaScript code.

For this to work, the name attribute and datatype of the input in your HTML must match the name/datatype of the field in Epicor CPQ. For example, if you have a configurator number field named 'Width', and the following input field with the same name and data type exists in your web page, then data entered into the input will automatically appear in the configurator field:

<input type="number" name="Width">

The containing web page may have multiple forms.  You can target which forms you want Epicor CPQ to watch by providing a CSS type selector for them. Examples:

To watch all inputs in a form with id = "my-form":

data-bind-to-form="#my-form"

To watch all inputs in a form with an id of 'my-form' and another form with an id of 'my-form-2':

data-bind-to-form="#my-form, #my-form-2"

To watch all forms on the page:

data-bind-to-form="form"
showFields boolean Optional Whether your pages and field controls will show in the embed. If you plan on having your own custom UI for your user to select options, then use bindToForm above and set this to false.
This attribute only affects the embed if the 'bare' attribute is set to false.
showHeader boolean Optional Controls whether the Epicor CPQ portal header (with company logo, links to the products and quotes tabs) will show in the embed. Only valid for full configurator embeds.
This attribute only affects the embed if the 'bare' attribute is set to false.
showDrawer boolean Optional Controls whether the Epicor CPQ portal footer (called the drawer) will show in the embed. Hiding the footer can increase vertical space for the embedded configurator.
This attribute only affects the embed if the 'bare' attribute is set to false.
showConfigHeader boolean Optional Whether the configurator header with the name, description, and action buttons of the configurator will be shown in the embed.
This attribute only affects the embed if the 'bare' attribute is set to false.
showMove boolean Optional You can choose to start the embed with an animation that invites the user to rotate and interact with the 3D scene. Otherwise they might think the 3D scene is just a 2D image.
loadImage url Optional If the load-style is set to 'image' or 'image + progress', then this attribute can be used to specify a url for the image you want to show while the scene is loading. If this attribute is left blank, Epicor CPQ will automatically use an image of the scene in its resting state.
progressColor hex color Optional If the load-style is 'progress' or 'image + progress', then this attribute can be used to specify a hex color for the progress bar.
currency text Optional

Can be set to the 3 letter ISO code of a currency that the configurator will use for displaying pricing.  If not provided, then the default currency of the company will be used. 

The currency ISO code provided must be enabled in the currency settings of the company.

idTheme integer Optional Can be set to the id of a Epicor CPQ theme to override the default theme currently set in the company settings.  In this way, your embedded configurator can appear in the same colors and font as the page it is embedded within.
fields object Optional Can be used to set starting field values for the embedded configurator.  The object to be passed in follows the same construct as the object passed to setFields (see below in the api section).  
configuredProduct Configured
Product
Optional Specifies a configured product to load immediately. This is similar to setConfiguredProduct except by sending the configured product as an embed arg, it will defer the loaded rule until after the configured product is applied, which will better reflect the actual behavior of loading an existing configuration from a quote using the portal.

ConfiguratorEmbed Calls

After you instantiate the embedded configurator in the parent web page, you can use JavaScript in that page to make calls to control your configurator.

 

Call Description
setFields (fieldsObject, callback)

Sets values of fields in the configurator. The fields object parameter is an anonymous object where the properties are field names, and the values are the value for that field.

For example:

config.setFields({
	"Width": 5,
	"Height": 10,
	"Color": "Red"}); 

Only the fields that you provide values for will be set in the configurator. 

Note that the setFields call will start a rule cycle in the configurator.  If you need to know when the rules are done running, you can add a function call after the list of fields to provide an optional callback.  For example:

config.setFields({
	"Width": 5,
	"Height": 10,
	"Color": "Red"}, function(){
	//when the configurator rules are done,
       //this code will be executed
});


getFields (callback)

Gets an anonymous object where the properties are the field names, and the values are the field values from the configurator. Note that this will not include fields in nested configurators. If you need those fields, or other detailed information about the configurator, it's best to use getConfiguredProduct().

config.getFields(function(o){
	//o will contain the field names and values
}); 
getConfiguredProduct (callback)

Gets a ConfiguredProduct object, fully populated with information about the configurator at that time. This object can be very large for complicated configurators, so if you only need basic field name-value pairs for the configurator, we recommend you use getFields() instead. Unlike other requests, this is an asynchronous call and requires you to use a callback to get the result.

config.getConfiguredProduct(function(cp){
	//cp will contain the ConfiguredProduct
}); 
setConfiguredProduct (configProduct, callback)

Sets field values of the configurator given a ConfiguredProduct object.  The typical use case is that you have acquired the ConfiguredProduct object from the getConfiguredProduct call at some time in the past, and you want to re-instate the configurator to this state.

config.setConfiguredProduct(configuredProduct, function(){
	//callback after the configuredProduct 
       //has been applied to the configurator
}); 
runAction (actionName)

Runs a scene action with the given name. For example, if you have a button on your enclosing HTML page, and when clicked you want the scene to run its explode animation, you could add the following code in the button click handler:

viewer.runAction("ZoomCameraToWheelDetails");
setFieldsFromForm (formSelector) Similar to the bindToForm embed argument, calling setFieldsFromForm will look for any inputs in the given form, match them with fields in the scene, and update the scene accordingly.
saveProduct (callback)

Saves the configured product to a new or active quote on the Epicor CPQ server. Accepts a callback that is called when the save is complete, passing in the quote it was saved to.

config.saveProduct(function (quote) {
	//save is complete
});
saveProductAndSubmit (callback)

Saves the configured product to a new or active quote on the Epicor CPQ server and also submits the quote. It accepts a callback that is called when the save is complete.  If you decide to use the callback, that callback has access to the freshly-submitted quote as a parameter.

config.saveProductAndSubmit(function (quote) {
	//quote submit is complete
});
snapshot (options, callback)

Takes a snapshot image of the current scene with options.  The available options are:

  • dataType (string) - Possible values can only be "image", "blob", or "dataURL".
    • image - instructs the browser to download the snapshot image immediately
    • blob - return the snapshot image as a Blob in the provided callback
    • dataURL - return the snapshot image as a dataURL string in the provided callback
  • width (number) - The width of the desired image in pixels
  • height (number) - The height of the desired image in pixels

    Optional terms you can include in your call are

  • frameCamera (boolean) - Possible values are true or false, with no surrounding quotes. Default is true. 
    • Set to true to frame the viewpoint (ensure all visible meshes in the scene are included in the viewpoint) before the render is taken.  This is useful for configurable products that change in size.
    • Set to false to leave the viewpoint's position and rotation untouched.

  • framePadding (number) - What percentage of the entire snapshot image should be reserved to separate the edge of any mesh in the render, and the edge of the image?  Default is one percent.
  • viewpoint (string) - The name of the scene viewpoint to take the snapshot from. Default will use either the viewpoint as currently set by the user, or as originally specified in the scene node properties.
  • mimeType (string) - Defaults to "image/png".  Ensure your mimeType matches the file extension you specify in the filename parameter.  For example, "image/jpg" and "FrontView.jpg" match.
  • filename (string) - The name of the snapshot image file.  For safety, try to limit the number of characters and use simple single-byte letters, numbers, and symbols.
//example downloading the image immediately, using most default values
config.snapshot({
	dataType: "image",
	width: 500,
	height: 500
});

//example getting an image blob from a specific viewpoint, 
//and using a callback to place the blob within an img element for display.
config.snapshot({
	dataType: "blob",
	viewpoint: "Viewpoint1",
	width: 500,
	height: 500
}, function(blob){
	var imgElement= document.getElementById("some-img");
	imgElement.src = URL.createObjectURL(blob);
});
 

Note that this is an asynchronous call: to ensure you get the results you need, we suggest you wrap each snapshot() call in a promise or callback.

 

onMessage.add (handler)

Configurators can send messages to your page when certain configurator events have occurred, such as the user changing the value of a field or moving from one configurator tab to the next. Catch these messages in your page by using this call.  This allows your web page and configurator to work together, with each click the user makes, leading to a smooth and exceptional user experience.

You can add a handler that will be called whenever the web page gets a message from the configurator, so it can respond accordingly. For example:

config.onMessage.add(function (msg) {
	if (msg.name == "show tab") { //messages have a name to differentiate
		//the data property of the message contains custom data from your scene.  
		//In this case, we are using it to pass the name of the tab
		//this is just sample code, replace with your own
		showTab("#" + msg.data); 
	}
});

For more information, see the full walkthrough describing one way of using messages: gathering analytics on your configurator.

onMessage.remove (handler) Used to remove a message handler that you added using onMessage.add().
onSubmit.add (handler)

If your configurator embed is set to have a submit button (see the showSubmitButton parameter), then you can add a handler to determine what happens when the submit button is clicked.

config.onSubmit.add(function () {
	//add to the cart of your website for example
});
onSubmit.remove (handler) Used to remove a message handler that you added using onSubmit.add().
onLoaded (handler) Sets a handler that is fired when the configurator has been fully loaded.
dispose Removes the Epicor CPQ content from the parent page's DIV, and disposes of all Epicor CPQ callbacks.

In most cases, you do not need to "unload" the Epicor CPQ configurator embedded within the parent page.  When your user navigates to a different URL, the current page (and the embedded configurator within it) are automatically unloaded from the browser's memory. However, if you are embedding the CPQ into a single page application, you may want to dispose of the loaded Epicor CPQ visual and logical components before moving on to something else.
getPrice ()

Returns the current priceObject of the configurator.  The priceObject contains text and number data, along with an array of priceItem objects.  Each priceItem –  like a row in a table – consists of multiple priceColumns of data.  Note that depending on the security set for each priceColumn, one user running this call may retrieve a different number of priceColumns than another user.

config.getPrice(function(po){
	//po will contain the PriceObject
}); 

 

 

Call Description
getFields (callback)

Gets an anonymous object where the properties are the field names, and the values are the field values from the configurator. Note that this will not include fields in nested configurators. If you need those fields, or other detailed information about the configurator, it's best to use getConfiguredProduct().

config.getFields(function(o){
	//o will contain the field names and values
}); 
getConfiguredProduct (callback)

Gets a ConfiguredProduct object, fully populated with information about the configurator at that time. This object can be very large for complicated configurators, so if you only need basic field name-value pairs for the configurator, we recommend you use getFields() instead. Unlike other requests, this is an asynchronous call and requires you to use a callback to get the result.

config.getConfiguredProduct(function(cp){
	//cp will contain the ConfiguredProduct
}); 
setConfiguredProduct (configProduct, callback)

Sets field values of the configurator given a ConfiguredProduct object.  The typical use case is that you have acquired the ConfiguredProduct object from the getConfiguredProduct call at some time in the past, and you want to re-instate the configurator to this state.

config.setConfiguredProduct(configuredProduct, function(){
	//callback after the configuredProduct
       //has been applied to the configurator
}); 
runAction (actionName)

Runs a scene action with the given name. For example, if you have a button on your enclosing HTML page, and when clicked you want the scene to run its explode animation, you could add the following code in the button click handler:

viewer.runAction("ZoomCameraToWheelDetails");
setFieldsFromForm (formSelector) Similar to the bindToForm embed argument, calling setFieldsFromForm will look for any inputs in the given form, match them with fields in the scene, and update the scene accordingly.
saveProduct (callback)

Saves the configured product to a new or active quote on the Epicor CPQ server. Accepts a callback that is called when the save is complete, passing in the quote it was saved to.

config.saveProduct(function (quote) {
	//save is complete
});
saveProductAndSubmit (callback)

Saves the configured product to a new or active quote on the Epicor CPQ server and also submits the quote. It accepts a callback that is called when the save is complete.  If you decide to use the callback, that callback has access to the freshly-submitted quote as a parameter.

config.saveProductAndSubmit(function (quote) {
	//quote submit is complete
});
snapshot (options, callback)

Takes a snapshot image of the current scene with options.  The available options are:

  • dataType (string) - Possible values can only be "image", "blob", or "dataURL".
    • image - instructs the browser to download the snapshot image immediately
    • blob - return the snapshot image as a Blob in the provided callback
    • dataURL - return the snapshot image as a dataURL string in the provided callback
  • width (number) - The width of the desired image in pixels
  • height (number) - The height of the desired image in pixels

    Optional terms you can include in your call are

  • frameCamera (boolean) - Possible values are true or false, with no surrounding quotes. Default is true. 
    • Set to true to frame the viewpoint (ensure all visible meshes in the scene are included in the viewpoint) before the render is taken.  This is useful for configurable products that change in size.
    • Set to false to leave the viewpoint's position and rotation untouched.

  • framePadding (number) - What percentage of the entire snapshot image should be reserved to separate the edge of any mesh in the render, and the edge of the image?  Default is one percent.
  • viewpoint (string) - The name of the scene viewpoint to take the snapshot from. Default will use either the viewpoint as currently set by the user, or as originally specified in the scene node properties.
  • mimeType (string) - Defaults to "image/png".  Ensure your mimeType matches the file extension you specify in the filename parameter.  For example, "image/jpg" and "FrontView.jpg" match.
  • filename (string) - The name of the snapshot image file.  For safety, try to limit the number of characters and use simple single-byte letters, numbers, and symbols.
//example downloading the image immediately, 
//using most default values
config.snapshot({
	dataType: "image",
	width: 500,
	height: 500
});

//example getting an image blob from a specific viewpoint, 
//and using a callback to place the blob within an img element for display
config.snapshot({
	dataType: "blob",
	viewpoint: "Viewpoint1",
	width: 500,
	height: 500
}, function(blob){
	var imgElement= document.getElementById("some-img");
	imgElement.src = URL.createObjectURL(blob);
});

Note that this is an asynchronous call: to ensure you get the results you need, we suggest you wrap each snapshot() call in a promise or callback.

onMessage.add (handler)

Configurators can send messages to your page when certain configurator events have occurred, such as the user changing the value of a field or moving from one configurator tab to the next. Catch these messages in your page by using this call.  This allows your web page and configurator to work together, with each click the user makes, leading to a smooth and exceptional user experience.

You can add a handler that will be called whenever the web page gets a message from the configurator, so it can respond accordingly. For example:

config.onMessage.add(function (msg) {
	if (msg.name == "show tab") { //messages have a name to differentiate
		//the data property of the message contains
               // custom data from your scene.  
		//In this case, we are using it to pass the name of the tab.
		//this is just sample code, replace with your own
		showTab("#" + msg.data); 
	}
});

For more information, see the full walkthrough describing one way of using messages: gathering analytics on your configurator.

onMessage.remove (handler) Used to remove a message handler that you added using onMessage.add().
onSubmit.add (handler)

If your configurator embed is set to have a submit button (see the showSubmitButton parameter), then you can add a handler to determine what happens when the submit button is clicked.

config.onSubmit.add(function () {
	//add to the cart of your website for example
});
onSubmit.remove (handler) Used to remove a message handler that you added using onSubmit.add().
onLoaded (handler) Sets a handler that is fired when the configurator has been fully loaded.
dispose Removes the Epicor CPQ content from the parent page's DIV, and disposes of all Epicor CPQ callbacks.

In most cases, you do not need to "unload" the Epicor CPQ configurator embedded within the parent page.  When your user navigates to a different URL, the current page (and the embedded configurator within it) are automatically unloaded from the browser's memory. However, if you are embedding the CPQ into a single page application, you may want to dispose of the loaded Epicor CPQ visual and logical components before moving on to something else.
getPrice ()

Returns the current priceObject of the configurator.  The priceObject contains text and number data, along with an array of priceItem objects.  Each priceItem –  like a row in a table – consists of multiple priceColumns of data.  Note that depending on the security set for each priceColumn, one user running this call may retrieve a different number of priceColumns than another user.

config.getPrice(function(po){
	//po will contain the PriceObject
}); 

Cookies required.

Since your user will be looking at content from both your servers and the Epicor CPQ platform servers, their browser should allow "third-party cookies". 

Further Reading


Was this article helpful?