Custom Embedded Demo Forms

Setup demo functionality on CQG side

In order to allow your users to request demo logins for your application based on white-labeled CQG product or direct CQG API usage, the following information should be provided to the FCM Desk:

  • Application name.
  • Domain name (Site URL) where demo form will be embedded.
  • HTML template of email which will be sent to user once demo login is created.
  • Email address(es) that you'll want to cc/bcc (optional). Bcc email also can be configured during demo form code generation.
  • Mandatory SMS verification (optional). User will have to verify phone number with SMS code after first login to application in order to use it.
  • Duration (optional). Demo login lifespan in days. Default is 5 working days.
  • Live Data Demo eligible (optional). In this case user will have to provide real address information on demo form if it supports live data account type. Note: Valid address is required for live data demos, as these require reporting to respective exchanges.

Then CQG will provide you Product ID, which should be used while demo form code snippet generation.

Demo Email HTML template format

It should contain the following placeholders for information about created demo login:

  1. %username - demo login username.
  2. %password - demo login password.
  3. %first_name - user's first name.
  4. %last_name - user's last name.
  5. %expiration_date - date until which demo login is alive.

Also send graphics, CQG will need to host them on cqg.com and change reference paths in the email.

In case of integration with a 'CQG Desktop' product, there may be additional optional fields.

Generate demo form code

Before you can setup demo form on your site, you need to generate HTML code for embedding.

Proceed to DemoRequest Generator and fill the following information:

  1. Brokerage name - your company name.
  2. Sales email to receive a copy of the demo requests - bcc email, once user requested demo using your form, email sent to user will be blindly copied to this email.
  3. URL where this form will be hosted on your domain.
  4. CQG Product ID - ID of your application provided by CQG on 1st step.
  5. Your demo request form title.
  6. Type of demo account requested. Possible values:
    • Standard - without address fields;
    • Live data - address fields are required (address, city, state, country, ZIP code);
    • User selectable - on generated form user can able to choose 'Standard' or 'Live data' requested demo login.

Then press 'Generate HTML'.

Once generated you will see 2 HTML code snippets:

  1. iFrame HTML - in case you don't need any customization of demo form. Just embed it to your site and it is done.
  2. Form HTML - demo form HTML code which can be customized with additional input fields and styles.

Embed code to your site

iFrame HTML

Example of generated code snippet you should embed into html page of your site:

<!-- Begin of demo request form. -->
<iframe frameborder="0" height="950" width="350" scrolling="auto" src="https://demoform.cqg.com/form/index.html?brokerageName=Test&brokerageEmail=test%40test.com&brokerageUrl=https%3A%2F%2Ftest.com&productId=1111000&formTitle=Test%20title"></iframe>
<!-- End of demo request form. -->

If you need to collect user's data in case of successful demo request, you can subscribe on special window message with 'CQGDemoForm' sender and 'demoRequested' topic.

Event data contains the following fields:

  • sender - string has the value "CQGDemoForm";
  • topic - string with possible event topic name;
  • userData -
    • In case of 'demoRequested' or 'demoRequestIsFailed' event types, object has the following structure: { firstName: string, lastName: string, email: string, phone: string}.
    • In case of 'phoneValidationIsSuccess' type, object has the following structure: { originalPhone: string, countryCode: number, national: string, international: string, E164:string }.
    • In case of 'phoneValidationIsFailed' type, object has the following structure: { originalPhone: string }.
  • error - object with an exception or string with server error message.

Demo form supports the following event types (HTML form) or topics (iFrame form)

  • demoRequested - In case when demo login successfully requested. Event will have 'userData' field with user's input data.
  • demoRequestIsStarted - When requested is sent to server.
  • demoRequestIsFinished - When request is finished.
  • demoRequestIsFailed - In case when during sending request some error occurred or server return a failed result. Event will have 'userData' field with user's input data and 'error' field with error object.
  • reCaptchaResolved - In case when the reCAPTCHA successfully solved.
  • reCaptchaExpired - In case when the reCAPTCHA response expires and the user needs to re-verify.
  • phoneValidationIsSuccess - In case when phone number validation is success. Event will have 'userData' field with the following structure: { originalPhone: string, countryCode: number, national: string, international: string, E164:string }.
  • phoneValidationIsFailed - In case when phone number validation is failed. Event will have 'userData' field with user's input phone number: { originalPhone: string } and 'error' field with error object.
  • loadCountriesOrRegionsIsFailed - In case when load list of countries or regions is failed. Event will have only 'error' field with error object.
  • checkDomainIsFailed - In case when check domain operation is failed. Event will have only 'error' field with error object.

See code example:

<script>
    function listener(event) {
        console.log(`Received event from origin: ${event.origin}`);
        if (!event.data || event.data.sender !== "CQGDemoForm") {
            return;
        }

        switch (event.data.topic) {
            case "demoRequested":
            case "phoneValidationIsSuccess":
                console.log(`Received user's input data from 'CQGDemoForm' with topic '${event.data.topic}':`);
                console.log(event.data.userData);
                break;
            case "demoRequestIsStarted":
            case "demoRequestIsFinished":
            case "reCaptchaResolved":
            case "reCaptchaExpired":
                console.log(`Received event from 'CQGDemoForm' with topic '${event.data.topic}'.`);
                break;
            case "demoRequestIsFailed":
            case "phoneValidationIsFailed":
                console.log(`Received failed event with user's input data from 'CQGDemoForm' with topic '${event.data.topic}':`);
                console.log(event.data.userData);
                console.log("Error info:");
                console.log(event.data.error);
                break;
            case "loadCountriesOrRegionsIsFailed":
            case "checkDomainIsFailed":
                console.log(`Received failed event from 'CQGDemoForm' with topic '${event.data.topic}':`);
                console.log("Error info:");
                console.log(event.data.error);
                break;
        }
    }

    if (window.addEventListener) {
        window.addEventListener("message", listener);
    } else {
        // IE8
        window.attachEvent("onmessage", listener);
    }
</script>

Form HTML

Example of generated code snippet you should embed into html page of your site:

<!-- Begin of demo request form. -->
<div class="cqg-demo well" style="width: 330px;">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
    <h3 class="cqg-demo__title">Test title</h3>
    <form class="cqg-demo__form" method="post">
        <div class="form-group">
            <img src="https://sqa1demoform.sqa.cqg/img/demoScreen.png" alt="Demo screen" style="max-width: 100%;">
        </div>
        <div class="cqg-demo__error alert alert-danger" style="display: none; white-space: pre-line;"></div>
        <div class="cqg-demo__success alert alert-success" style="display: none; white-space: pre-line;"></div>
        <input type="hidden" name="brokerageName" value="Test">
        <input type="hidden" name="brokerageEmail" value="test@test.com">
        <input type="hidden" name="brokerageUrl" value="https://test.com">
        <input type="hidden" name="productId" value="1111000">
        <input type="hidden" name="demoFormVersion" value="1.2.45000.00003">
        <div class="form-group">
            <label>First Name</label>
            <input type="text" class="form-control" name="userName" required="" maxlength="20" placeholder="max 20 symbols">
        </div>
        <div class="form-group">
            <label>Last Name</label>
            <input type="text" class="form-control" name="userLastName" required="" maxlength="25" placeholder="max 25 symbols">
        </div>
        <div class="form-group">
            <label>Email</label>
            <input type="email" class="form-control" name="userEmail" required="">
        </div>
        <div class="form-group">
            <label>Phone</label><span class="cqg-demo__form-user-phone-description"> (used for SMS verification)</span>
            <input type="tel" class="form-control" name="userPhone" required="" placeholder="international format (e.g. +17024181234)">
        </div>
        <div class="cqg-demo__captcha form-group" data-size="normal" data-theme="light" data-type="image"></div>
        <div class="form-group">
            <button type="submit" class="cqg-demo__submit btn btn-primary">Submit Demo Request</button>
        </div>
    </form>
    <p class="text-info">
        Instructions on how to download and activate your demo account will be sent to the email address that you provided above.
    </p>
<div style="color: #888; display: flex; justify-content: flex-end; font-size: 13px;">v.1.2.45000.00003</div>
    <script src="https://sqa1demoform.sqa.cqg/form/form.js"></script>
    <script>
        function initializeCqgDemoForm() {
            let demoForm = CQG.Demo.Form.initializeDemoForm(document.querySelector('.cqg-demo'));
        }
    </script>
    <script src="https://www.google.com/recaptcha/api.js?onload=initializeCqgDemoForm&amp;render=explicit" async="" defer=""></script>
</div>
<!-- End of demo request form. -->

If you need to collect user's data in case of successful demo request or add custom validation function which will be called before demo request send, you can use the following CQG demo form object methods:

/** Sets custom form validation function which will be called before form submitted.
 * @param callback - Callback function for the validation. Function will be called with one input parameter - object with the following structure:
 *    { firstName: string, lastName: string, email: string, phone: string }.
 * Returns string which will be shown as error message and prevent to submit the form data, if string not empty.
 */

setCustomValidator(callback: CallableFunction): void;

interface CallableFunction {
    (formData: UserInput): string;
}

interface UserInput {
    firstName: string;
    lastName: string;
    email: string;
    phone: string;
}

/** Checks phone number. This method will be called before form submitted if phone number is required (in case when form has product ID value).
* @param phoneNumber - Phone number to check.
* @param callback -Callback function with two parameters.
*   First of Error type in case when validation failed. Otherwise parameter will be 'null'.
*   Second parameter, in case when validation failed, will have only { originalPhone: string } value.
*   In case when validation is succeeded, parameter will have the following fields:
*       { originalPhone: string, countryCode: number, national: string, international: string, E164:string }
*/
checkPhoneNumber(phoneNumber: string, callback: AsyncCallback): void;

interface AsyncCallback {
    (error?: Error, result?: any): void;
}

/** Sets up a function that will be called whenever the specified event is delivered to the target.
 * @param eventType - A case-sensitive string representing the event type to listen for.
 * @param callback - Callback that receives a notification when an event of the specified name occurs.
 *    Function will be called with one input parameter - event object which contains the following fields:
 *       * type - event type;
 *       * userData (in case of 'demoRequested' event type) - object has the following structure:
 *            { firstName: string, lastName: string, email: string, phone: string}.
 *            In case of 'phoneValidationIsSuccess' type, object has the following structure:
 *               { originalPhone: string, countryCode: number, national: string, international: string, E164:string }.
 *            In case of 'phoneValidationIsFailed' type, object has the following structure:
 *               { originalPhone: string }.
 *       * error - object with an exception or string with server error message.
 */

addEventListener(eventType, callback)

/** Removes from the target an event listener previously registered with addEventListener().
 * @param eventType - A case-sensitive string representing the event type which you want to unsubscribe from.
 * @param callback - Callback function of the event handler to remove from the event target.
 */

removeEventListener(eventType, callback)

The list of supported event types see above.

See code example:

<script>
    function initializeCqgDemoForm() {
        let demoForm = CQG.Demo.Form.initializeDemoForm(document.querySelector('.cqg-demo'));

        // Sample code.
        demoForm.setCustomValidator((userData) => {
            console.log("Custom validator handled with user data: ");
            console.log(userData);
            if ((userData.firstName || "").toLowerCase() == "test") {
                return "Please enter your real name.";
            }
        });

        demoForm.addEventListener('demoRequested', (event) =>
            console.log(`Received '${event.type}' event with user data:\n`, event.userData));

        demoForm.addEventListener('demoRequestIsStarted', (event) => console.log(`Received '${event.type}' event.`));

        demoForm.addEventListener('demoRequestIsFinished', (event) => console.log(`Received '${event.type}' event.`));

        demoForm.addEventListener('demoRequestIsFailed', (event) => {
            console.log(`Received '${event.type}' event with user data:\n`,event.userData);
            console.log(`Error info:\n`, event.error);
        });

        demoForm.addEventListener('reCaptchaResolved', (event) => console.log(`Received '${event.type}' event.`));

        demoForm.addEventListener('reCaptchaExpired', (event) => console.log(`Received '${event.type}' event.`));

        demoForm.addEventListener('phoneValidationIsSuccess', (event) =>
            console.log(`Received '${event.type}' event with user data:\n`, event.userData));
        
        demoForm.addEventListener('phoneValidationIsFailed', (event) => {
            console.log(`Received '${event.type}' event with user data:\n`, event.userData);
            console.log(`Error info:\n`, event.error);
        });

        demoForm.addEventListener('loadCountriesOrRegionsIsFailed', (event) =>
            console.log(`Received '${event.type}' event. Error info:\n `, event.error));
        demoForm.addEventListener('checkDomainIsFailed', (event) =>
            console.log(`Received '${event.type}' event. Error info:\n `, event.error));
    }
</script>